From 018b7bb72d213ac3f15091020716a257bb00efd6 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Thu, 4 Nov 2021 17:49:18 +0100 Subject: [PATCH 001/361] [dwdunwetter] Fixed broken link in documentation (#11512) - Fixed broken link in documentation Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.dwdunwetter/README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.dwdunwetter/README.md b/bundles/org.openhab.binding.dwdunwetter/README.md index b8ee201031e75..75e0f0e5cc9e8 100644 --- a/bundles/org.openhab.binding.dwdunwetter/README.md +++ b/bundles/org.openhab.binding.dwdunwetter/README.md @@ -63,12 +63,7 @@ For rules that need to fire if a new warning occurs, there is the trigger channe That trigger channel fires an event whenever a warning is sent for the first time. It also triggers if a warning is replaced by another. -More explanations about the specific values of the channels can be found in the documentation of the DWD at: - -[CAP DWD Profile 1.2](https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_dwd_profile_de_pdf_1_10.html) - -[CAP DWD Profil zum Common Alerting Protocol v1.2 (PDF)](https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_dwd_profile_de_pdf_1_10.pdf?__blob=publicationFile&v=4) - +More explanations about the specific values of the channels can be found in the PDF documentation of the DWD at: [CAP DWD Profile 1.2](https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_dwd_profile_en_pdf_1_12.html) ## Full Example @@ -80,7 +75,7 @@ dwdunwetter:dwdwarnings:cologne "Warnings Cologne" [ cellId="105315000", refresh e.g. -to get two warnings like in the item example, set warningCount=2 in things file +to get two warnings like in the item example, set `warningCount=2` in things file ``` dwdunwetter:dwdwarnings:cologne "Warnings Cologne" [ cellId="105315000", refresh=15, warningCount=2 From 708f42592067013856a2367919d66849eeb4bba9 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Fri, 5 Nov 2021 12:10:10 +0100 Subject: [PATCH 002/361] [weathercompany] Fix internationalization of discovery service (#11499) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../internal/WeatherCompanyHandlerFactory.java | 8 ++++++-- .../discovery/WeatherCompanyDiscoveryService.java | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/WeatherCompanyHandlerFactory.java b/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/WeatherCompanyHandlerFactory.java index 220c6d6589c17..8356e0442c9f8 100644 --- a/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/WeatherCompanyHandlerFactory.java +++ b/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/WeatherCompanyHandlerFactory.java @@ -29,6 +29,7 @@ import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.LocationProvider; import org.openhab.core.i18n.TimeZoneProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.i18n.UnitProvider; import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.thing.Bridge; @@ -58,16 +59,19 @@ public class WeatherCompanyHandlerFactory extends BaseThingHandlerFactory { private HttpClient httpClient; private LocationProvider locationProvider; private LocaleProvider localeProvider; + private TranslationProvider i18nProvider; @Activate public WeatherCompanyHandlerFactory(@Reference TimeZoneProvider timeZoneProvider, @Reference UnitProvider unitProvider, @Reference HttpClientFactory httpClientFactory, - @Reference LocationProvider locationProvider, @Reference LocaleProvider localeProvider) { + @Reference LocationProvider locationProvider, @Reference LocaleProvider localeProvider, + @Reference TranslationProvider i18nProvider) { this.timeZoneProvider = timeZoneProvider; this.unitProvider = unitProvider; this.httpClient = httpClientFactory.getCommonHttpClient(); this.locationProvider = locationProvider; this.localeProvider = localeProvider; + this.i18nProvider = i18nProvider; } @Override @@ -103,7 +107,7 @@ protected synchronized void removeHandler(ThingHandler thingHandler) { private synchronized void registerDeviceDiscoveryService(WeatherCompanyBridgeHandler bridgeHandler) { WeatherCompanyDiscoveryService discoveryService = new WeatherCompanyDiscoveryService(bridgeHandler, - locationProvider, localeProvider); + locationProvider, localeProvider, i18nProvider); discoveryService.activate(null); this.discoveryServiceRegs.put(bridgeHandler.getThing().getUID(), bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>())); diff --git a/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/discovery/WeatherCompanyDiscoveryService.java b/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/discovery/WeatherCompanyDiscoveryService.java index e2e9fb4d5c60d..1dffde948aa6b 100644 --- a/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/discovery/WeatherCompanyDiscoveryService.java +++ b/bundles/org.openhab.binding.weathercompany/src/main/java/org/openhab/binding/weathercompany/internal/discovery/WeatherCompanyDiscoveryService.java @@ -27,6 +27,7 @@ import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.PointType; import org.openhab.core.thing.ThingUID; import org.slf4j.Logger; @@ -49,7 +50,6 @@ public class WeatherCompanyDiscoveryService extends AbstractDiscoveryService { private final Logger logger = LoggerFactory.getLogger(WeatherCompanyDiscoveryService.class); private final LocationProvider locationProvider; - private final LocaleProvider localeProvider; private final WeatherCompanyBridgeHandler bridgeHandler; private @Nullable ScheduledFuture discoveryJob; @@ -58,11 +58,12 @@ public class WeatherCompanyDiscoveryService extends AbstractDiscoveryService { * Creates a WeatherCompanyDiscoveryService with discovery enabled */ public WeatherCompanyDiscoveryService(WeatherCompanyBridgeHandler bridgeHandler, LocationProvider locationProvider, - LocaleProvider localeProvider) { + LocaleProvider localeProvider, TranslationProvider i18nProvider) { super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, true); this.bridgeHandler = bridgeHandler; this.locationProvider = locationProvider; this.localeProvider = localeProvider; + this.i18nProvider = i18nProvider; } @Override From c72380d5525b3a14f2fff615703afaee5e26dd40 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Fri, 5 Nov 2021 13:56:58 +0100 Subject: [PATCH 003/361] Suppress bnd warnings for unused imports/exports (#11513) Ignores warnings like: ``` Warning: /home/runner/work/openhab-addons/openhab-addons/bom/runtime-index/pom.xml [0:0]: Unused Export-Package instructions: [org.openhab.*] Warning: /home/runner/work/openhab-addons/openhab-addons/bom/runtime-index/pom.xml [0:0]: Unused Import-Package instructions: [io.swagger.v3.oas.annotations.*, ``` These are safe to ignore because the import/export packages are globally defined and not every bundle imports/exports all these packages. The `skipIfEmpty` configuration furthermore prevents warnings when the bnd-maven-plugin runs on projects that don't have any code like BOMs. More important compiler/SAT warnings standout more when there are there are fewer useless warnings. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- pom.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ba3b31ff637cf..a25687bcdb1fb 100644 --- a/pom.xml +++ b/pom.xml @@ -159,9 +159,13 @@ Import-Package: \\ -sources: false -contract: * -includeresource: ${bnd.includeresource} --fixupmessages: ${bnd.fixupmessages}]]> +-fixupmessages: \\ + 'Unused Import-Package instructions';is:=ignore,\\ + 'Unused Export-Package instructions';is:=ignore,\\ + ${bnd.fixupmessages}]]> + true From b0cfe0637dd2df91ddd9a757632e08a3472264fe Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Fri, 5 Nov 2021 15:21:48 +0100 Subject: [PATCH 004/361] [hue] Fixed unicode character in translation (#11519) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/i18n/hue.properties | 2 +- .../src/main/resources/OH-INF/thing/LightLevelSensor.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties index 46bee8d8e243b..a7609ea22cb2f 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties @@ -64,7 +64,7 @@ thing-type.config.hue.0106.sensorId.description = The identifier that is used wi thing-type.config.hue.0106.tholddark.label = Threshold Dark thing-type.config.hue.0106.tholddark.description = Threshold the user configured to be used in rules to determine insufficient light level (ie below threshold). Default value 16000. thing-type.config.hue.0106.tholdoffset.label = Threshold Offset -thing-type.config.hue.0106.tholdoffset.description = Threshold the user configured to be used in rules to determine sufficient light level (ie above threshold). Specified as relative offset to the “dark” threshold. Shall be >=1. Default value 7000. +thing-type.config.hue.0106.tholdoffset.description = Threshold the user configured to be used in rules to determine sufficient light level (ie above threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. thing-type.config.hue.0110.fadetime.label = Fade Time thing-type.config.hue.0110.fadetime.description = Fade time in milliseconds for changing values thing-type.config.hue.0110.lightId.label = Light ID diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml index 0774e75afbddd..661d6e9f3c6fc 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml @@ -47,7 +47,7 @@ Threshold the user configured to be used in rules to determine sufficient light level (ie above - threshold). Specified as relative offset to the “dark” threshold. Shall be >=1. Default value 7000. + threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. 7000 From 9d92cc945b6eaf4ff313e24531eed483cf310c86 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Fri, 5 Nov 2021 18:42:16 +0100 Subject: [PATCH 005/361] Fix wrong build result when single add-on build fails (#11522) Fixes the issue that single add-on builds that fail are not marked as such in GitHub Actions. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .github/scripts/maven-build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/scripts/maven-build b/.github/scripts/maven-build index 8ee64663e2973..777228110277b 100755 --- a/.github/scripts/maven-build +++ b/.github/scripts/maven-build @@ -87,7 +87,9 @@ function build_addon() { echo "+ $mvn_command" echo + set -o pipefail # exit build with error when pipes fail $mvn_command 2>&1 | tee "$BUILD_LOG" + exit $? } function build_based_on_changes() { From 960dc2551134de1903e5a9370916919db453b095 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Fri, 5 Nov 2021 19:37:03 +0100 Subject: [PATCH 006/361] New Crowdin updates (#11518) * New translations lametrictime.properties (French) * New translations thingstate.properties (French) * New translations twitter.properties (French) * New translations tradfri.properties (French) * New translations vigicrues.properties (French) Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/lametrictime_fr.properties | 3 ++ .../OH-INF/i18n/thingstate_fr.properties | 6 +++ .../OH-INF/i18n/tradfri_fr.properties | 51 +++++++++++++++++++ .../OH-INF/i18n/twitter_fr.properties | 9 ++++ .../OH-INF/i18n/vigicrues_fr.properties | 17 ++++--- 5 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 bundles/org.openhab.binding.lametrictime/src/main/resources/OH-INF/i18n/lametrictime_fr.properties create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/thingstate_fr.properties create mode 100644 bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties create mode 100644 bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties diff --git a/bundles/org.openhab.binding.lametrictime/src/main/resources/OH-INF/i18n/lametrictime_fr.properties b/bundles/org.openhab.binding.lametrictime/src/main/resources/OH-INF/i18n/lametrictime_fr.properties new file mode 100644 index 0000000000000..75bf519891bce --- /dev/null +++ b/bundles/org.openhab.binding.lametrictime/src/main/resources/OH-INF/i18n/lametrictime_fr.properties @@ -0,0 +1,3 @@ +# configuration messages +config-status.error.missing-host-configuration=Aucun hôte pour le dispositif LaMetric Time n'a été fourni. +config-status.error.missing-api-key-configuration=Aucune clé API pour le périphérique LaMetric Time n'a été fournie. diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/thingstate_fr.properties b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/thingstate_fr.properties new file mode 100644 index 0000000000000..0043f24b09d68 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/thingstate_fr.properties @@ -0,0 +1,6 @@ +teleinfo.thingstate.serial_notfound=Erreur série \: le port {0} n''existe pas +teleinfo.thingstate.serial_inuse=Erreur série \: le port {0} est en cours d''utilisation +teleinfo.thingstate.serial_unsupported=Erreur série \: opération non prise en charge sur le port {0} +teleinfo.thingstate.serial_listeners=Erreur série \: trop de listeners sur le port {0} +teleinfo.thingstate.controller_offline=Le contrôleur est hors ligne +teleinfo.thingstate.controller_unknown_retry_inprogress=Erreur série \: nouvelle tentative en cours... diff --git a/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties new file mode 100644 index 0000000000000..9c5dae830cba4 --- /dev/null +++ b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties @@ -0,0 +1,51 @@ +# binding + +binding.tradfri.name = Extension TRÅDFRI +binding.tradfri.description = Cette extension apporte le support des appareils IKEA de la gamme TRÅDFRI par l’intermédiaire de la passerelle IKEA. + +# thing types + +thing-type.tradfri.0010.label = Prise On/Off +thing-type.tradfri.0010.description = Une prise qui peut être allumée et éteinte. +thing-type.tradfri.0100.label = Ampoule à intensité lumineuse réglable +thing-type.tradfri.0100.description = Une ampoule avec contrôle de la l'intensité lumineuse. +thing-type.tradfri.0107.label = Capteur de présence +thing-type.tradfri.0107.description = Un détecteur de mouvement capable aussi de signaler le niveau de la batterie. +thing-type.tradfri.0202.label = Store ou rideau +thing-type.tradfri.0202.description = Un store ou un rideau qui peut être déplacé vers le haut ou vers le bas. Fournit également le niveau actuel de la batterie. +thing-type.tradfri.0203.label = Télécommande pour store ou rideau +thing-type.tradfri.0203.description = Une télécommande sans fil pour ouvrir ou fermer le store ou le rideau, capable aussi de signaler le niveau de la batterie. +thing-type.tradfri.0210.label = Ampoule couleur +thing-type.tradfri.0210.description = Une ampoule à intensité variable et avec réglage de la couleur et de la température de couleur. +thing-type.tradfri.0220.label = Ampoule avec température de couleur réglable +thing-type.tradfri.0220.description = Une ampoule à intensité variable et avec réglage de la température de couleur. +thing-type.tradfri.0820.label = Variateur +thing-type.tradfri.0820.description = Un variateur sans fil capable aussi de signaler le niveau de la batterie. +thing-type.tradfri.0830.label = Télécommande de scénario +thing-type.tradfri.0830.description = Une télécommande capable de signaler le niveau de la batterie. +thing-type.tradfri.gateway.label = Passerelle TRÅDFRI +thing-type.tradfri.gateway.description = Passerelle IP IKEA TRÅDFRI + +# thing types config + +bridge-type.config.tradfri.gateway.code.label = Code de sécurité +bridge-type.config.tradfri.gateway.code.description = Code de sécurité imprimé sur l'étiquette sous la passerelle. +bridge-type.config.tradfri.gateway.host.label = Hôte +bridge-type.config.tradfri.gateway.host.description = Nom d'hôte ou adresse IP de la passerelle IKEA TRÅDFRI +bridge-type.config.tradfri.gateway.identity.label = Identité +bridge-type.config.tradfri.gateway.identity.description = Identifiant unique utilisé pour communiquer avec la passerelle +bridge-type.config.tradfri.gateway.port.label = Port +bridge-type.config.tradfri.gateway.port.description = Port pour accéder à la passerelle +bridge-type.config.tradfri.gateway.preSharedKey.label = Clé de sécurité pré-partagée +bridge-type.config.tradfri.gateway.preSharedKey.description = Clé de sécurité obtenue lors de la première initialisation de la passerelle +thing-type.config.tradfri.device.id.label = ID +thing-type.config.tradfri.device.id.description = Identifiant de l'équipement sur la passerelle. + +# channel types + +channel-type.tradfri.position.label = Position +channel-type.tradfri.position.description = Contrôler la position du store ou du rideau en pourcentage de 0 (ouvert) à 100 (fermé). + +# discovery result + +discovery.gateway.label = Passerelle TRÅDFRI diff --git a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties new file mode 100644 index 0000000000000..0c4ed5b7f0212 --- /dev/null +++ b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties @@ -0,0 +1,9 @@ +# actions +sendTweetActionLabel = envoyer un Tweet +sendTweetActionDescription = Envoie un Tweet. + +sendAttachmentTweetActionLabel = envoyer un Tweet avec pièce jointe +sendAttachmentTweetActionDescription = Envoie un Tweet avec pièce jointe. + +sendDirectMessageActionLabel = envoyer un message privé +sendDirectMessageActionDescription = Envoie un message privé. diff --git a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties index 7f026573c0ad1..673be0b2c2bec 100644 --- a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties +++ b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties @@ -1,18 +1,18 @@ # binding binding.vigicrues.name = Extension VigiCrues -binding.vigicrues.description = Informations de niveau et de seuil d'alerte des rivières de France. +binding.vigicrues.description = Récupère les niveaux et alertes des cours d'eau en France # thing types thing-type.vigicrues.station.label = Station -thing-type.vigicrues.station.description = Fournit les informations de niveau et de flux pour cette station. +thing-type.vigicrues.station.description = Fournit des informations sur le niveau du cours d'eau relevées par cette station # thing types config thing-type.config.vigicrues.station.id.label = Identifiant thing-type.config.vigicrues.station.id.description = Identifiant unique de la station. -thing-type.config.vigicrues.station.refresh.label = Période de Rafraîchissement +thing-type.config.vigicrues.station.refresh.label = Fréquence de rafraîchissement thing-type.config.vigicrues.station.refresh.description = Fréquence de rafraichissement en minutes. # channel types @@ -28,10 +28,11 @@ channel-type.vigicrues.comment.label = Commentaire channel-type.vigicrues.comment.description = Commentaire détaillé. channel-type.vigicrues.flow.label = Débit channel-type.vigicrues.flow.description = Débit du cours d'eau. +channel-type.vigicrues.gauge.label = Mesure relative channel-type.vigicrues.height.label = Hauteur -channel-type.vigicrues.height.description = Hauteur d'eau dans le cours d'eau. -channel-type.vigicrues.observation-time.label = Horodatage -channel-type.vigicrues.observation-time.description = Heure de rapport des mesures. +channel-type.vigicrues.height.description = Niveau d'eau de la rivière +channel-type.vigicrues.observation-time.label = Heure d'observation +channel-type.vigicrues.observation-time.description = Date et heure de l’observation # channels @@ -39,5 +40,5 @@ thing-type.vigicrues.station.channel.relative-flow.label = Débit relatif thing-type.vigicrues.station.channel.relative-flow.description = Débit relatif par rapport aux crues historiques. thing-type.vigicrues.station.channel.relative-height.label = Hauteur relative thing-type.vigicrues.station.channel.relative-height.description = Hauteur relative par rapport aux crues historiques. -thing-type.vigicrues.station.channel.short-comment.label = Situation -thing-type.vigicrues.station.channel.short-comment.description = Bref descriptif de la situation. +thing-type.vigicrues.station.channel.short-comment.label = Description Courte +thing-type.vigicrues.station.channel.short-comment.description = Brève description de la situation. From 49fc02809088e4780b3527779ae3f808f67cee28 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sat, 6 Nov 2021 10:08:57 +0100 Subject: [PATCH 007/361] [twitter] Extend properties file with all default translations (#11528) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/twitter.properties | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter.properties b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter.properties index 3de984bd6a2d0..1dc20882dc251 100644 --- a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter.properties +++ b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter.properties @@ -1,9 +1,32 @@ +# binding + +binding.twitter.name = Twitter Binding +binding.twitter.description = Supports adding Thing for getting the Last Tweet. Send Tweets and Pictures with Actions. + +# thing types + +thing-type.twitter.account.label = Twitter Account +thing-type.twitter.account.description = Account uses for sending Tweets + +# thing types config + +thing-type.config.twitter.account.accessToken.label = Access Token +thing-type.config.twitter.account.accessTokenSecret.label = Access Token Secret +thing-type.config.twitter.account.consumerKey.label = Consumer API Key +thing-type.config.twitter.account.consumerSecret.label = Consumer API Secret +thing-type.config.twitter.account.refresh.label = Refresh Time +thing-type.config.twitter.account.refresh.description = Refresh Time for This Account in Mins + +# channel types + +channel-type.twitter.lasttweet.label = Last Tweet +channel-type.twitter.lasttweet.description = Users Last Tweet + # actions -sendTweetActionLabel = send a Tweet -sendTweetActionDescription = Sends a Tweet. sendAttachmentTweetActionLabel = send a Tweet with attachment sendAttachmentTweetActionDescription = Sends a Tweet with an attachment. - sendDirectMessageActionLabel = send a DirectMessage sendDirectMessageActionDescription = Sends a DirectMessage. +sendTweetActionLabel = send a Tweet +sendTweetActionDescription = Sends a Tweet. From 3ceadb5fda85b7ddf9e889c0fa7677616a76fc08 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sat, 6 Nov 2021 10:11:55 +0100 Subject: [PATCH 008/361] [mail] Extend properties file with all default translations (#11530) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/mail.properties | 62 +++++++++++++++---- .../resources/OH-INF/thing/thing-types.xml | 55 ++++++++-------- 2 files changed, 80 insertions(+), 37 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties index c7a481fb2ffae..f526993d3ee73 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties @@ -1,21 +1,61 @@ +# binding + +binding.mail.name = Mail Binding +binding.mail.description = This binding is used to access POP3, IMAP and SMTP servers. + +# thing types + +thing-type.mail.imap.label = IMAP Server +thing-type.mail.imap.description = Used for receiving emails +thing-type.mail.pop3.label = POP3 Server +thing-type.mail.pop3.description = Used for receiving emails +thing-type.mail.smtp.label = SMTP Server +thing-type.mail.smtp.description = Used for sending emails via rule actions + +# thing types config + +thing-type.config.mail.imap.port.description = Default values are 143 for plain/STARTTLS and 993 for SSL/TLS +thing-type.config.mail.pop3.port.description = Default values are 110 for plain/STARTTLS and 995 for SSL/TLS +thing-type.config.mail.smtp.port.description = Default values are 25 for plain/STARTTLS and 465 for SSL/TLS +thing-type.config.mail.smtp.sender.label = Sender +thing-type.config.mail.smtp.sender.description = Default sender address for mail + +config.hostname.label = Server Hostname +config.password.label = SMTP Server Password +config.port.label = Server Port +config.refresh.label = Refresh Time +config.refresh.description = Refresh time for this account in seconds +config.security.label = SMTP Server Security Protocol +config.security.option.PLAIN = plain +config.security.option.STARTTLS = STARTTLS +config.security.option.SSL = SSL/TLS +config.username.label = SMTP Server Username + +# channel types + +channel-type.mail.mailcount.label = Mail Count +channel-type.mail.mailcount.description = Number of emails in folder + +# channel types config + +channel-type.config.mail.mailcount.folder.label = Folder Name +channel-type.config.mail.mailcount.type.label = Counter Type +channel-type.config.mail.mailcount.type.option.UNREAD = Unread +channel-type.config.mail.mailcount.type.option.TOTAL = Total + # actions -sendMessageActionLabel = send a text mail -sendMessageActionDescription = Sends a text mail. +addHeaderActionLabel = add a mail header +addHeaderActionDescription = Adds a mail header to the mail message. sendAttachmentMessageActionLabel = send a text mail with attachment sendAttachmentMessageActionDescription = Sends a text mail with an URL attachment. - sendAttachmentsMessageActionLabel = send a text mail with several attachments sendAttachmentsMessageActionDescription = Sends a text mail with several URL attachments. - -sendHTMLMessageActionLabel = send a HTML mail -sendHTMLMessageActionDescription = Sends a HTML mail. - sendHTMLAttachmentMessageActionLabel = send a HTML mail with attachment sendHTMLAttachmentMessageActionDescription = Sends a HTML mail with an URL attachment. - sendHTMLAttachmentsMessageActionLabel = send a HTML mail with several attachments sendHTMLAttachmentsMessageActionDescription = Sends a HTML mail with several URL attachments. - -addHeaderActionLabel = add a mail header -addHeaderActionDescription = Adds a mail header to the mail message. +sendHTMLMessageActionLabel = send a HTML mail +sendHTMLMessageActionDescription = Sends a HTML mail. +sendMessageActionLabel = send a text mail +sendMessageActionDescription = Sends a text mail. diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml index a7eaebf65c34e..5483caecb2e51 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml @@ -13,28 +13,28 @@ Default sender address for mail - + - + Default values are 25 for plain/STARTTLS and 465 for SSL/TLS true - + - - - + + + true PLAIN - + - + password @@ -44,32 +44,33 @@ Used for receiving emails - + - + Default values are 143 for plain/STARTTLS and 993 for SSL/TLS true - + - - - + + + true PLAIN - + - + password - + + @text/config.refresh.description 60 @@ -79,32 +80,33 @@ Used for receiving emails - + - + Default values are 110 for plain/STARTTLS and 995 for SSL/TLS true - + - - - + + + true PLAIN - + - + password - + + @text/config.refresh.description 60 @@ -120,6 +122,7 @@ + From e972ef475418455b38776518f6fdc3161a5b8e86 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 6 Nov 2021 10:13:40 +0100 Subject: [PATCH 009/361] Always run OSGi HTTP service on random port in itests (#11523) It is probably always a good idea to run the OSGi HTTP service on a random available port in itests. So when this is always done it prevents future issues and removes a bit of duplication. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- itests/itest-common.bndrun | 4 +++ .../itest.bndrun | 2 -- itests/org.openhab.binding.feed.tests/pom.xml | 25 ------------------- .../itest.bndrun | 2 -- .../pom.xml | 23 ----------------- itests/pom.xml | 19 ++++++++++++++ 6 files changed, 23 insertions(+), 52 deletions(-) diff --git a/itests/itest-common.bndrun b/itests/itest-common.bndrun index 65c903d7514fe..6ff2541ba5d63 100644 --- a/itests/itest-common.bndrun +++ b/itests/itest-common.bndrun @@ -24,6 +24,10 @@ Import-Package: org.osgi.framework.*;version="[1.8,2)",* -runfw: org.eclipse.osgi -runee: JavaSE-11 +# An unused random HTTP port is used during tests to prevent resource conflicts +# This property is set by the build-helper-maven-plugin in the itests pom.xml +-runvm: -Dorg.osgi.service.http.port=${org.osgi.service.http.port} + # The integration test itself does not export anything. Export-Package: -exportcontents: diff --git a/itests/org.openhab.binding.feed.tests/itest.bndrun b/itests/org.openhab.binding.feed.tests/itest.bndrun index 19572ada11ae7..9378160408139 100644 --- a/itests/org.openhab.binding.feed.tests/itest.bndrun +++ b/itests/org.openhab.binding.feed.tests/itest.bndrun @@ -14,8 +14,6 @@ Fragment-Host: org.openhab.binding.feed -runblacklist: \ bnd.identity;id='org.openhab.core.storage.json' --runvm: -Dorg.osgi.service.http.port=${org.osgi.service.http.port} - # # done # diff --git a/itests/org.openhab.binding.feed.tests/pom.xml b/itests/org.openhab.binding.feed.tests/pom.xml index c801dbfa88717..1fbe5d0ee410a 100644 --- a/itests/org.openhab.binding.feed.tests/pom.xml +++ b/itests/org.openhab.binding.feed.tests/pom.xml @@ -15,8 +15,6 @@ openHAB Add-ons :: Integration Tests :: Feed Binding Tests - 9090 - 1.15.0 @@ -44,27 +42,4 @@ - - - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-network-port - - reserve-network-port - - process-resources - - - org.osgi.service.http.port - - - - - - - - diff --git a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun index 0fa85e225e0a5..47773da6de74d 100644 --- a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun +++ b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun @@ -12,8 +12,6 @@ Fragment-Host: org.openhab.binding.mielecloud bnd.identity;id='org.openhab.core.storage.json',\ bnd.identity;id='org.openhab.core.storage.mapdb' --runvm: -Dorg.osgi.service.http.port=${org.osgi.service.http.port} - # # done # diff --git a/itests/org.openhab.binding.mielecloud.tests/pom.xml b/itests/org.openhab.binding.mielecloud.tests/pom.xml index bc399d0d5a9e5..a21efcf275a76 100644 --- a/itests/org.openhab.binding.mielecloud.tests/pom.xml +++ b/itests/org.openhab.binding.mielecloud.tests/pom.xml @@ -22,27 +22,4 @@ - - - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-network-port - - reserve-network-port - - process-resources - - - org.osgi.service.http.port - - - - - - - - diff --git a/itests/pom.xml b/itests/pom.xml index ad0e57ef8286b..e77f6eac4918c 100644 --- a/itests/pom.xml +++ b/itests/pom.xml @@ -38,6 +38,7 @@ target/dependency + 9090 @@ -179,6 +180,24 @@ + + org.codehaus.mojo + build-helper-maven-plugin + + + reserve-network-port + + reserve-network-port + + process-resources + + + org.osgi.service.http.port + + + + + From 625fc1c4b6755c90fba583d761532117419945c3 Mon Sep 17 00:00:00 2001 From: LukasA83 <58861945+LukasA83@users.noreply.github.com> Date: Sat, 6 Nov 2021 19:18:40 +0100 Subject: [PATCH 010/361] [jsscripting] Update GraalJS to 21.3 to allow method selection via JavaScript (#11437) Signed-off-by: Lukas Agethen Signed-off-by: Michael Schmidt --- .../pom.xml | 4 +- .../automation/jsscripting/ClassExtender.java | 37 ------------------- .../internal/OpenhabGraalJSScriptEngine.java | 7 +++- 3 files changed, 8 insertions(+), 40 deletions(-) delete mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/ClassExtender.java diff --git a/bundles/org.openhab.automation.jsscripting/pom.xml b/bundles/org.openhab.automation.jsscripting/pom.xml index e8868bb24bdbb..5a5ff68b054cc 100644 --- a/bundles/org.openhab.automation.jsscripting/pom.xml +++ b/bundles/org.openhab.automation.jsscripting/pom.xml @@ -22,7 +22,7 @@ !jdk.internal.reflect.*, !jdk.vm.ci.services - 20.1.0 + 21.3.0 6.2.1 ${project.version} @@ -81,7 +81,7 @@ com.ibm.icu icu4j - 62.1 + 69.1 diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/ClassExtender.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/ClassExtender.java deleted file mode 100644 index d3a1623df7df9..0000000000000 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/ClassExtender.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.automation.jsscripting; - -import com.oracle.truffle.js.runtime.java.adapter.JavaAdapterFactory; - -/** - * Class utility to allow creation of 'extendable' classes with a classloader of the GraalJS bundle, rather than the - * classloader of the file being extended. - * - * @author Jonathan Gilbert - Initial contribution - */ -public class ClassExtender { - private static ClassLoader classLoader = ClassExtender.class.getClassLoader(); - - public static Object extend(String className) { - try { - return extend(Class.forName(className)); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Cannot find class " + className, e); - } - } - - public static Object extend(Class clazz) { - return JavaAdapterFactory.getAdapterClassFor(clazz, null, classLoader); - } -} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index aa62c1308592e..9f29b0d99d2c7 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -30,6 +30,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Engine; import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable; @@ -65,10 +66,14 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi */ public OpenhabGraalJSScriptEngine() { super(null); // delegate depends on fields not yet initialised, so we cannot set it immediately - delegate = GraalJSScriptEngine.create(null, + delegate = GraalJSScriptEngine.create( + Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false") + .build(), Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true) .option("js.commonjs-require-cwd", MODULE_DIR).option("js.nashorn-compat", "true") // to ease // migration + .option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we + // want ecma2021 .option("js.commonjs-require", "true") // enable CommonJS module support .hostClassLoader(getClass().getClassLoader()) .fileSystem(new DelegatingFileSystem(FileSystems.getDefault().provider()) { From f6df539326a8fc8d2b3af2feb7d05ef822551e13 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:28:53 +0100 Subject: [PATCH 011/361] feat: add enum for api version Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/ApiVersion.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java new file mode 100644 index 0000000000000..112a4cc46f32f --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api; + +/** + * Represents version for the API of the evnotify online service. + * + * @author Michael Schmidt - Initial contribution + */ +public enum ApiVersion { + + V2, + V3; + + public static ApiVersion getApiVersion(String searchVersion) { + + for (ApiVersion version : ApiVersion.values()) { + if (version.name().equals(searchVersion)) { + return version; + } + } + + throw new IllegalArgumentException(String.format("'%s' is not a valid version", searchVersion)); + } +} From ca74346d34779db7cb99e0f8dfbac26a8f50cddf Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:30:59 +0100 Subject: [PATCH 012/361] test: add tests for api version enum Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/ApiVersionTest.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java new file mode 100644 index 0000000000000..9edb49657ab20 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Test cases for the {@link ApiVersion} class + * + * @author Michael Schmidt - Initial contribution + */ +class ApiVersionTest { + + @Test + void shouldGetVersions() { + // given + + // when + ApiVersion v2 = ApiVersion.getApiVersion("V2"); + ApiVersion v3 = ApiVersion.getApiVersion("V3"); + + // then + assertEquals(ApiVersion.V2, v2); + assertEquals(ApiVersion.V3, v3); + } + + @Test + void shouldHandleNullVersions() { + // given + String versionToBeTested = null; + + // when + assertThrows(IllegalArgumentException.class, () -> ApiVersion.getApiVersion(versionToBeTested)); + + // then + } + + @Test + void shouldThrowIllegalArgumentExceptionForInvalidVersion() { + // given + String versionToBeTested = "V999"; + + // when + assertThrows(IllegalArgumentException.class, () -> ApiVersion.getApiVersion(versionToBeTested)); + + // then + } + +} \ No newline at end of file From 144867ba5c607e8b41526ca7f5bf8dc986c104fd Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:32:48 +0100 Subject: [PATCH 013/361] feat: add inteface for data of evnotify online service Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/CarChargingData.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java new file mode 100644 index 0000000000000..528dc3ccc9fe2 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api; + +import java.time.OffsetDateTime; + +/** + * Interface for the data from the API of the evnotify online service. + * + * @author Michael Schmidt - Initial contribution + */ +public interface CarChargingData { + + Boolean isCharging(); + + Boolean isRapidChargePort(); + + Boolean isNormalChargePort(); + + Boolean isSlowChargePort(); + + Float getStateOfHealth(); + + Float getAuxBatteryVoltage(); + + Float getDcBatteryVoltage(); + + Float getDcBatteryCurrent(); + + Float getDcBatteryPower(); + + Float getCumulativeEnergyCharged(); + + Float getCumulativeEnergyDischarged(); + + Float getBatteryMinTemperature(); + + Float getBatteryMaxTemperature(); + + Float getBatteryInletTemperature(); + + Float getExternalTemperature(); + + OffsetDateTime getLastExtended(); +} From b99a715a91fb751df42073e7378c675f908c230e Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:33:12 +0100 Subject: [PATCH 014/361] feat: add inteface for client for evnotify online service Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/EVNotifyClient.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java new file mode 100644 index 0000000000000..aec72341425d1 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api; + +import java.io.IOException; + +/** + * Interface for the client to get data from the API of the evnotify online service. + * + * @author Michael Schmidt - Initial contribution + */ +public interface EVNotifyClient { + + /** + * returns a {@link CarChargingData} + * + * @return state of a car + */ + CarChargingData getCarChargingData() throws IOException, InterruptedException; +} From 99ba2a9f18f0608f72bc658059ce52242fd4fe78 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:33:53 +0100 Subject: [PATCH 015/361] feat: add v2 api implementation for client for evnotify online service Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/EVNotifyClientImpl.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java new file mode 100644 index 0000000000000..a059ba35b5b74 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.EVNotifyClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +/** + * The {@link EVNotifyClient} is responsible for retrieving + * data via EVNotify V2 API + * + * @author Michael Schmidt - Initial contribution + */ +public class EVNotifyClientImpl implements EVNotifyClient { + + public static String DEFAULT_API_URL_PATTERN = "hhttps://app.evnotify.de/soc?akey=%s&token=%s"; + public static String EXTENDED_API_URL_PATTERN = "https://app.evnotify.de/extended?akey=%s&token=%s"; + + private final Logger logger = LoggerFactory.getLogger(EVNotifyClientImpl.class); + private final HttpClient client; + + private final String aKey; + + private final String token; + + public EVNotifyClientImpl(String aKey, String token, HttpClient client) { + this.aKey = aKey; + this.token = token; + this.client = client; + } + + @Override + public CarChargingData getCarChargingData() throws IOException, InterruptedException { + + // create a request + var request = HttpRequest.newBuilder(URI.create(String.format(EXTENDED_API_URL_PATTERN, aKey, token))) + .header("accept", "application/json").build(); + + try { + // use the client to send the request + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + + CarChargingData carChargingData = new Gson().fromJson(response.body(), CarChargingDataDTO.class); + + return carChargingData; + } catch (Exception e) { + logger.error("Could not retrieve state of car", e); + throw e; + } + } +} From 40ebfa7271c55e4c67186bc08a7b51838c536aee Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:34:14 +0100 Subject: [PATCH 016/361] feat: add v2 api implementation for data for evnotify online service Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/CarChargingDataDTO.java | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java new file mode 100644 index 0000000000000..e35dcb31e5b3d --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java @@ -0,0 +1,180 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +import org.openhab.binding.evnotify.api.CarChargingData; + +import com.google.gson.annotations.SerializedName; + +/** + * Represents the data that is returned by evnotify v2 API. + * + * e.g. + * + * { + * "soh": 100, + * "charging": 1, + * "rapid_charge_port": 0, + * "normal_charge_port": 1, + * "slow_charge_port": null, + * "aux_battery_voltage": 14.5, + * "dc_battery_voltage": 362.1, + * "dc_battery_current": -8.7, + * "dc_battery_power": -3.15027, + * "cumulative_energy_charged": 3881.5, + * "cumulative_energy_discharged": 3738.8, + * "battery_min_temperature": 25, + * "battery_max_temperature": 26, + * "battery_inlet_temperature": 24, + * "external_temperature": null, + * "odo": null, + * "last_extended": 1631220014 + * } + * + * @author Michael Schmidt - Initial contribution + */ +public class CarChargingDataDTO implements CarChargingData { + + @SerializedName("charging") + public Integer charging; + + @SerializedName("rapid_charge_port") + public Integer rapidChargePort; + + @SerializedName("normal_charge_port") + public Integer normalChargePort; + + @SerializedName("slow_charge_port") + public Integer slowChargePort; + + @SerializedName("soh") + public Float stateOfHealth; + + @SerializedName("aux_battery_voltage") + public Float auxBatteryVoltage; + + @SerializedName("dc_battery_voltage") + public Float dcBatteryVoltage; + + @SerializedName("dc_battery_current") + public Float dcBatteryCurrent; + + @SerializedName("cumulative_energy_charged") + public Float cumulativeEnergyCharged; + + @SerializedName("cumulative_energy_discharged") + public Float cumulativeEnergyDischarged; + + @SerializedName("battery_min_temperature") + public Float batteryMinTemperature; + + @SerializedName("battery_max_temperature") + public Float batteryMaxTemperature; + + @SerializedName("battery_inlet_temperature") + public Float batteryInletTemperature; + + @SerializedName("external_temperature") + public Float externalTemperature; + + @SerializedName("last_extended") + public Integer lastExtended; + + @SerializedName("dc_battery_power") + public Float dcBatteryPower; + + @Override + public Float getCumulativeEnergyCharged() { + return cumulativeEnergyCharged; + } + + @Override + public Float getCumulativeEnergyDischarged() { + return cumulativeEnergyDischarged; + } + + @Override + public Float getBatteryMinTemperature() { + return batteryMinTemperature; + } + + @Override + public Float getBatteryMaxTemperature() { + return batteryMaxTemperature; + } + + @Override + public Float getBatteryInletTemperature() { + return batteryInletTemperature; + } + + @Override + public Float getExternalTemperature() { + return externalTemperature; + } + + @Override + public OffsetDateTime getLastExtended() { + return lastExtended == null ? null + : OffsetDateTime.from(Instant.ofEpochMilli(lastExtended).atZone(ZoneId.of("Europe/Berlin"))); + } + + @Override + public Float getAuxBatteryVoltage() { + return auxBatteryVoltage; + } + + @Override + public Float getDcBatteryVoltage() { + return dcBatteryVoltage; + } + + @Override + public Float getDcBatteryCurrent() { + return dcBatteryCurrent; + } + + @Override + public Float getDcBatteryPower() { + return dcBatteryPower; + } + + @Override + public Boolean isCharging() { + return charging != null && charging == 1; + } + + @Override + public Boolean isRapidChargePort() { + return rapidChargePort != null && rapidChargePort == 1; + } + + @Override + public Boolean isNormalChargePort() { + return normalChargePort != null && normalChargePort == 1; + } + + @Override + public Boolean isSlowChargePort() { + return slowChargePort != null && slowChargePort == 1; + } + + @Override + public Float getStateOfHealth() { + return stateOfHealth; + } +} From 96a2a2ccb97c929826b0ca928c6f26d1a6fe3993 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:34:46 +0100 Subject: [PATCH 017/361] test: add test for v2 api implementation for client for evnotify online service Signed-off-by: Michael Schmidt --- .../api/v2/EVNotifyClientImplTest.java | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java new file mode 100644 index 0000000000000..0bb383367ac1b --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Optional; + +import javax.net.ssl.SSLSession; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.EVNotifyClient; + +/** + * Test cases for the {@link EVNotifyClientImpl} class + * + * @author Michael Schmidt - Initial contribution + */ +class EVNotifyClientImplTest { + + @Mock + HttpClient httpClient; + + @BeforeEach + void setUp() { + httpClient = mock(HttpClient.class); + } + + @Test + void shouldGiveAValidCarCHargingDataForValidResponse() throws IOException, InterruptedException { + // given + HttpResponse response = getResponse(200, getResponseBody()); + when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(response); + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + CarChargingData carChargingData = evNotifyClient.getCarChargingData(); + + // then + assertEquals(true, carChargingData.isCharging()); + assertEquals(false, carChargingData.isRapidChargePort()); + assertEquals(true, carChargingData.isNormalChargePort()); + assertEquals(false, carChargingData.isSlowChargePort()); + assertEquals(Float.valueOf(100.0f), carChargingData.getStateOfHealth()); + assertEquals(Float.valueOf(14.5f), carChargingData.getAuxBatteryVoltage()); + assertEquals(Float.valueOf(362.1f), carChargingData.getDcBatteryVoltage()); + assertEquals(Float.valueOf(-8.7f), carChargingData.getDcBatteryCurrent()); + assertEquals(Float.valueOf(-3.15027f), carChargingData.getDcBatteryPower()); + assertEquals(Float.valueOf(3881.5f), carChargingData.getCumulativeEnergyCharged()); + assertEquals(Float.valueOf(3738.8f), carChargingData.getCumulativeEnergyDischarged()); + assertEquals(Float.valueOf(25f), carChargingData.getBatteryMinTemperature()); + assertEquals(Float.valueOf(26f), carChargingData.getBatteryMaxTemperature()); + assertEquals(Float.valueOf(24f), carChargingData.getBatteryInletTemperature()); + assertNull(carChargingData.getExternalTemperature()); + assertEquals(1631220014L, carChargingData.getLastExtended().toInstant().toEpochMilli()); + } + + private HttpResponse getResponse(Integer statusCode, String body) { + return new HttpResponse<>() { + @Override + public int statusCode() { + return statusCode; + } + + @Override + public HttpRequest request() { + return null; + } + + @Override + public Optional> previousResponse() { + return Optional.empty(); + } + + @Override + public HttpHeaders headers() { + return null; + } + + @Override + public String body() { + return body; + } + + @Override + public Optional sslSession() { + return Optional.empty(); + } + + @Override + public URI uri() { + return null; + } + + @Override + public HttpClient.Version version() { + return null; + } + }; + } + + private String getResponseBody() { + return "{" + "\"soh\": 100," + "\"charging\": 1," + "\"rapid_charge_port\": 0," + "\"normal_charge_port\": 1," + + "\"slow_charge_port\": null," + "\"aux_battery_voltage\": 14.5," + "\"dc_battery_voltage\": 362.1," + + "\"dc_battery_current\": -8.7," + "\"dc_battery_power\": -3.15027," + + "\"cumulative_energy_charged\": 3881.5," + "\"cumulative_energy_discharged\": 3738.8," + + "\"battery_min_temperature\": 25," + "\"battery_max_temperature\": 26," + + "\"battery_inlet_temperature\": 24," + "\"external_temperature\": null," + "\"odo\": null," + + "\"last_extended\": 1631220014" + "}"; + } +} \ No newline at end of file From b6b1af712efb5eff56f2b9335f7e0ab43c00d1f8 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:36:01 +0100 Subject: [PATCH 018/361] feat: add initial files Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.evnotify/NOTICE | 13 +++++ .../org.openhab.binding.evnotify/README.md | 56 +++++++++++++++++++ bundles/org.openhab.binding.evnotify/pom.xml | 17 ++++++ .../src/main/feature/feature.xml | 9 +++ .../OH-INF/i18n/evnotify_xx.properties | 21 +++++++ 5 files changed, 116 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/NOTICE create mode 100644 bundles/org.openhab.binding.evnotify/README.md create mode 100644 bundles/org.openhab.binding.evnotify/pom.xml create mode 100644 bundles/org.openhab.binding.evnotify/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties diff --git a/bundles/org.openhab.binding.evnotify/NOTICE b/bundles/org.openhab.binding.evnotify/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/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/openhab-addons diff --git a/bundles/org.openhab.binding.evnotify/README.md b/bundles/org.openhab.binding.evnotify/README.md new file mode 100644 index 0000000000000..68d59ec2d753b --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/README.md @@ -0,0 +1,56 @@ +# EVNotify Binding + +_Give some details about what this binding is meant for - a protocol, system, specific device._ + +_If possible, provide some resources like pictures, a video, etc. to give an impression of what can be done with this binding. You can place such resources into a `doc` folder next to this README.md._ + +## Supported Things + +_Please describe the different supported things / devices within this section._ +_Which different types are supported, which models were tested etc.?_ +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ + +## Discovery + +_Describe the available auto-discovery features here. Mention for what it works and what needs to be kept in mind when using it._ + +## Binding Configuration + +_If your binding requires or supports general configuration settings, please create a folder ```cfg``` and place the configuration file ```.cfg``` inside it. In this section, you should link to this file and provide some information about the options. The file could e.g. look like:_ + +``` +# Configuration for the EVNotify Binding +# +# Default secret key for the pairing of the EVNotify Thing. +# It has to be between 10-40 (alphanumeric) characters. +# This may be changed by the user for security reasons. +secret=openHABSecret +``` + +_Note that it is planned to generate some part of this based on the information that is available within ```src/main/resources/OH-INF/binding``` of your binding._ + +_If your binding does not offer any generic configurations, you can remove this section completely._ + +## Thing Configuration + +_Describe what is needed to manually configure a thing, either through the UI or via a thing-file. This should be mainly about its mandatory and optional configuration parameters. A short example entry for a thing file can help!_ + +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ + +## Channels + +_Here you should provide information about available channel types, what their meaning is and how they can be used._ + +_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ + +| channel | type | description | +|----------|--------|------------------------------| +| control | Switch | This is the control channel | + +## Full Example + +_Provide a full usage example based on textual configuration files (*.things, *.items, *.sitemap)._ + +## Any custom content here! + +_Feel free to add additional sections for whatever you think should also be mentioned about your binding!_ diff --git a/bundles/org.openhab.binding.evnotify/pom.xml b/bundles/org.openhab.binding.evnotify/pom.xml new file mode 100644 index 0000000000000..e4f733ca971d1 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.evnotify + + openHAB Add-ons :: Bundles :: EVNotify Binding + + diff --git a/bundles/org.openhab.binding.evnotify/src/main/feature/feature.xml b/bundles/org.openhab.binding.evnotify/src/main/feature/feature.xml new file mode 100644 index 0000000000000..b244ee1235354 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.evnotify/${project.version} + + diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties new file mode 100644 index 0000000000000..18c18bff81238 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties @@ -0,0 +1,21 @@ +# FIXME: please substitute the xx with a proper locale, ie. de +# FIXME: please do not add the file to the repo if you add or change no content +# binding +binding.evnotify.name = +binding.evnotify.description = + +# thing types +thing-type.evnotify.sample.label = +thing-type.evnotify.sample.description = + +# thing type config description +thing-type.config.evnotify.sample.hostname.label = +thing-type.config.evnotify.sample.hostname.description = +thing-type.config.evnotify.sample.password.label = +thing-type.config.evnotify.sample.password.description = +thing-type.config.evnotify.sample.refreshInterval.label = +thing-type.config.evnotify.sample.refreshInterval.description = + +# channel types +channel-type.evnotify.sample-channel.label = +channel-type.evnotify.sample-channel.description = From f56bd03a4a77326f95124e521bccecf51e0cdaf2 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:36:46 +0100 Subject: [PATCH 019/361] feat: add initial files Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/binding/binding.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..294739aa9ba98 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,10 @@ + + + + EVNotify Binding + This is the binding for EVNotify. + Michael Schmidt + + From 92b27409b2c5d699b1b00c5dbe7c5a0297a4b879 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 09:38:14 +0100 Subject: [PATCH 020/361] feat: add things, handlers, configurations and bindings Signed-off-by: Michael Schmidt --- .../internal/EVNotifyBindingConstants.java | 70 ++++++ .../internal/EVNotifyConfiguration.java | 43 ++++ .../evnotify/internal/EVNotifyHandler.java | 234 ++++++++++++++++++ .../internal/EVNotifyHandlerFactory.java | 77 ++++++ .../resources/OH-INF/thing/thing-types.xml | 143 +++++++++++ 5 files changed, 567 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java create mode 100644 bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java new file mode 100644 index 0000000000000..b17b4f9a6496d --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.internal; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link EVNotifyBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Michael Schmidt - Initial contribution + */ +@NonNullByDefault +public class EVNotifyBindingConstants { + + private static final String BINDING_ID = "evnotify"; + + // // Bridge + // public static final String THING_TYPE_BRIDGE_ID = "bridge"; + // public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, THING_TYPE_BRIDGE_ID); + // public static final Set SUPPORTED_BRIDGE_THING_TYPES_UIDS = Collections + // .unmodifiableSet(Set.of(THING_TYPE_BRIDGE)); + + // List of all Thing Type UIDs + public static final String THING_TYPE_EVNOTIFY_ID = "evnotify"; + public static final ThingTypeUID THING_TYPE_EVNOTIFY = new ThingTypeUID(BINDING_ID, THING_TYPE_EVNOTIFY_ID); + + // List of all Channel ids + public static final String STATE_OF_HEALTH = "soh"; + public static final String CHARGING = "charging"; + public static final String RAPID_CHARING_PORT = "rapid_charge_port"; + public static final String NORMAL_CHARING_PORT = "normal_charge_port"; + public static final String SLOW_CHARING_PORT = "slow_charge_port"; + public static final String AUX_BATTERY_VOLTAGE = "aux_battery_voltage"; + public static final String DC_BATTERY_VOLTAGE = "dc_battery_voltage"; + public static final String DC_BATTERY_CURRENT = "dc_battery_current"; + public static final String DC_BATTERY_POWER = "dc_battery_power"; + public static final String CUMULATIVE_ENERGY_CHARGED = "cumulative_energy_charged"; + public static final String CUMULATIVE_ENERGY_DISCHARGED = "cumulative_energy_discharged"; + public static final String BATTERY_MIN_TEMPERATURE = "battery_min_temperature"; + public static final String BATTERY_MAX_TEMPERATURE = "battery_max_temperature"; + public static final String BATTERY_INLET_TEMPERATURE = "battery_inlet_temperature"; + public static final String EXTERNAL_TEMPERATURE = "external_temperature"; + public static final String LAST_EXTENDED = "last_extended"; + + // Collection of all supported thing types + public static final Set SUPPORTED_THING_TYPES_UIDS = Collections + .unmodifiableSet(Set.of(THING_TYPE_EVNOTIFY)); + + // Collections.unmodifiableSet( + // Stream.concat( + // SUPPORTED_BRIDGE_THING_TYPES_UIDS.stream(), + // Collections.unmodifiableSet(Set.of(THING_TYPE_EVNOTIFY)).stream() + // ) + // .collect(Collectors.toSet())); +} diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java new file mode 100644 index 0000000000000..3772b0a2310f4 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.internal; + +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link EVNotifyConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Michael Schmidt - Initial contribution + */ +public class EVNotifyConfiguration { + + /** + * AKey + */ + public @Nullable String aKey; + + /** + * Token + */ + public @Nullable String token; + + /** + * Version + */ + public String version = "V2"; + + /** + * Refresh interval + */ + public Integer refreshInterval = 5; +} diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java new file mode 100644 index 0000000000000..eb3eadfd345ef --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.internal; + +import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.*; + +import java.io.IOException; +import java.net.http.HttpClient; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.evnotify.api.ApiVersion; +import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.EVNotifyClient; +import org.openhab.binding.evnotify.api.v2.EVNotifyClientImpl; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link EVNotifyHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Michael Schmidt - Initial contribution + */ +@NonNullByDefault +public class EVNotifyHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(EVNotifyHandler.class); + + private @Nullable EVNotifyConfiguration config; + + private List allChannels = new ArrayList<>(); + + private @Nullable EVNotifyClient client; + + private @Nullable ScheduledFuture refreshJob; + + public EVNotifyHandler(Thing thing) { + super(thing); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // if (CHANNEL_1.equals(channelUID.getId())) { + // if (command instanceof RefreshType) { + // // TODO: handle data refresh + // } + + // TODO: handle command + + // Note: if communication with thing fails for some reason, + // indicate that by setting the status with detail information: + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + // "Could not control device at IP address x.x.x.x"); + // } + } + + @Override + public void initialize() { + // TODO: Initialize the handler. + // The framework requires you to return from this method quickly. Also, before leaving this method a thing + // status from one of ONLINE, OFFLINE or UNKNOWN must be set. This might already be the real thing status in + // case you can decide it directly. + // In case you can not decide the thing status directly (e.g. for long running connection handshake using WAN + // access or similar) you should set status UNKNOWN here and then decide the real status asynchronously in the + // background. + config = getConfigAs(EVNotifyConfiguration.class); + + // use client for configured version + ApiVersion apiVersion = ApiVersion.getApiVersion(config.version); + switch (apiVersion) { + case V2: + client = new EVNotifyClientImpl(config.aKey, config.token, HttpClient.newHttpClient()); + case V3: + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + String.format("'%s' not implemented yet.", apiVersion.name())); + } + + allChannels = getThing().getChannels().stream().map(channel -> channel.getUID().getId()) + .collect(Collectors.toList()); + + // set the thing status to UNKNOWN temporarily and let the background task decide for the real status. + // the framework is then able to reuse the resources from the thing handler initialization. + // we set this upfront to reliably check status updates in unit tests. + updateStatus(ThingStatus.UNKNOWN); + + startAutomaticRefresh(); + logger.debug("Finished initializing!"); + } + + private void updateChannelsAndStatus(@Nullable CarChargingData carChargingData, @Nullable String message) { + if (carChargingData == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message); + allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF)); + } else { + updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE); + allChannels.forEach(channel -> updateState(channel, getValue(channel, carChargingData))); + } + } + + private State getValue(String channelId, CarChargingData carChargingData) { + switch (channelId) { + case STATE_OF_HEALTH: + if (carChargingData.getStateOfHealth() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getStateOfHealth(), Units.PERCENT); + case CHARGING: + if (carChargingData.isCharging() == null) { + return UnDefType.UNDEF; + } + return carChargingData.isCharging() ? OnOffType.ON : OnOffType.OFF; + case RAPID_CHARING_PORT: + if (carChargingData.isRapidChargePort() == null) { + return UnDefType.UNDEF; + } + return carChargingData.isRapidChargePort() ? OnOffType.ON : OnOffType.OFF; + case NORMAL_CHARING_PORT: + if (carChargingData.isNormalChargePort() == null) { + return UnDefType.UNDEF; + } + return carChargingData.isNormalChargePort() ? OnOffType.ON : OnOffType.OFF; + case SLOW_CHARING_PORT: + if (carChargingData.isSlowChargePort() == null) { + return UnDefType.UNDEF; + } + return carChargingData.isSlowChargePort() ? OnOffType.ON : OnOffType.OFF; + case AUX_BATTERY_VOLTAGE: + if (carChargingData.getAuxBatteryVoltage() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getAuxBatteryVoltage(), Units.VOLT); + case DC_BATTERY_VOLTAGE: + if (carChargingData.getDcBatteryVoltage() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getDcBatteryVoltage(), Units.VOLT); + case DC_BATTERY_CURRENT: + if (carChargingData.getDcBatteryCurrent() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getDcBatteryCurrent(), Units.AMPERE); + case DC_BATTERY_POWER: + if (carChargingData.getDcBatteryPower() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getDcBatteryPower(), Units.WATT); + case CUMULATIVE_ENERGY_CHARGED: + if (carChargingData.getCumulativeEnergyCharged() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getCumulativeEnergyCharged(), Units.KILOWATT_HOUR); + case CUMULATIVE_ENERGY_DISCHARGED: + if (carChargingData.getCumulativeEnergyDischarged() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getCumulativeEnergyDischarged(), Units.KILOWATT_HOUR); + case BATTERY_MAX_TEMPERATURE: + if (carChargingData.getBatteryMaxTemperature() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getBatteryMaxTemperature(), SIUnits.CELSIUS); + case BATTERY_MIN_TEMPERATURE: + if (carChargingData.getBatteryMinTemperature() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getBatteryMinTemperature(), SIUnits.CELSIUS); + case BATTERY_INLET_TEMPERATURE: + if (carChargingData.getBatteryInletTemperature() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getBatteryInletTemperature(), SIUnits.CELSIUS); + case LAST_EXTENDED: + if (carChargingData.getLastExtended() == null) { + return UnDefType.UNDEF; + } + return new StringType(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(carChargingData.getLastExtended())); + } + return UnDefType.UNDEF; + } + + private void refresh() { + // Request new EVNotify data + try { + if (client != null) { + CarChargingData carChargingData = client.getCarChargingData(); + updateChannelsAndStatus(carChargingData, null); + } + + } catch (InterruptedException | IOException e) { + updateChannelsAndStatus(null, e.getMessage()); + } + } + + private void startAutomaticRefresh() { + if (refreshJob == null || refreshJob.isCancelled()) { + if (config != null) { + int delay = config.refreshInterval; + logger.debug("Running refresh job with delay {} s", delay); + refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, delay, TimeUnit.SECONDS); + } + + } + } +} diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java new file mode 100644 index 0000000000000..64c8feb6a27c0 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.internal; + +import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.SUPPORTED_THING_TYPES_UIDS; +import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.THING_TYPE_EVNOTIFY; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link EVNotifyHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Michael Schmidt - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.evnotify", service = ThingHandlerFactory.class) +public class EVNotifyHandlerFactory extends BaseThingHandlerFactory { + + private final Logger logger = LoggerFactory.getLogger(EVNotifyHandlerFactory.class); + + @Activate + public EVNotifyHandlerFactory() { + } + + @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_EVNOTIFY.equals(thingTypeUID)) { + return new EVNotifyHandler(thing); + } + + // if (SUPPORTED_BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID)) { + // logger.debug("Creating bridge handler for thing {}", thing.getUID()); + // EVNotifBridgeHandler bridgeHandler = new EVNotifBridgeHandler((Bridge) thing); + // + // logger.debug("Creating and registering discovery service"); + // BhyveDiscoveryService discoveryService = new BhyveDiscoveryService(bridgeHandler); + // // Register the discovery service with the bridge handler + // bridgeHandler.setDiscoveryService(discoveryService); + // // Register the discovery service + // ServiceRegistration reg = bundleContext.registerService(DiscoveryService.class.getName(), + // discoveryService, new Hashtable()); + // // Add the service to the ServiceRegistration map + // discoveryServiceRegs.put(bridgeHandler.getThing().getUID(), reg); + // return bridgeHandler; + // } + + return null; + } +} diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..4500512ce9ee0 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,143 @@ + + + + + + + The EVNotify account represents a connection to the EVNotify online service + + + + + + + + + + + + + + + + + + + + + + + + AKey used for EVNotify API access + + + + + Token used for EVNotify API access. It is like a password. Do not share this with people you do not + trust! + password + + + + + + Number + + State of Health + + + + Switch + + ON if charging + + + + Switch + + ON if connected to rapid charging + + + + Switch + + ON if connected to normal charging + + + + Switch + + ON if connected to slow charging + + + + Number:ElectricPotential + + AUX Battery Voltage + + + + Number:ElectricPotential + + DC Battery Voltage + + + + Number:Power + + DC Battery Power + + + + Number:Energy + + Amount of energy that has been charged + + + + Number:Energy + + Amount of energy that has been discharged + + + + Number:Temperature + + External Temperature + + + + Number:Temperature + + Battery Min Temperature + + + + Number:Temperature + + Battery Max Temperature + + + + Number:Temperature + + Battery Inlet Temperature + + + + Number:Temperature + + External Temperature + + + + String + + Timestamp of the latest export + + + + From 47fc83d4d9f0aaa6476f47222ca8e9cf87ee7b67 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 10:06:49 +0100 Subject: [PATCH 021/361] refactor: format Signed-off-by: Michael Schmidt --- .../org/openhab/binding/evnotify/api/ApiVersionTest.java | 6 +++--- .../binding/evnotify/api/v2/EVNotifyClientImplTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java index 9edb49657ab20..89bd38119ecde 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/ApiVersionTest.java @@ -11,10 +11,11 @@ * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.evnotify.api; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + /** * Test cases for the {@link ApiVersion} class * @@ -56,5 +57,4 @@ void shouldThrowIllegalArgumentExceptionForInvalidVersion() { // then } - -} \ No newline at end of file +} diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java index 0bb383367ac1b..45cc16e47f982 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -130,4 +130,4 @@ private String getResponseBody() { + "\"battery_inlet_temperature\": 24," + "\"external_temperature\": null," + "\"odo\": null," + "\"last_extended\": 1631220014" + "}"; } -} \ No newline at end of file +} From 3abe4ee9e313a41e0696cfda90828be5c2764286 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 11:23:53 +0100 Subject: [PATCH 022/361] feat: change type id and description Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index 4500512ce9ee0..b975466dec2b8 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -4,10 +4,10 @@ xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd"> - - - - The EVNotify account represents a connection to the EVNotify online service + + + + The EVNotify car (account) represents a connection to the EVNotify online services From 4ec0741d513fedbcef8829e25c65b37bfb79c1da Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sun, 31 Oct 2021 11:24:31 +0100 Subject: [PATCH 023/361] feat: add config parameter for refresh interval Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index b975466dec2b8..76e9966bda3f1 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -40,6 +40,12 @@ trust! password + + + + Refresh interval for acquiring data from EVNotify online service in seconds + s + From 973a3af5cc5c07cf483b8961b36a0ca0c02ceca2 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 10:47:54 +0100 Subject: [PATCH 024/361] feat: add channel for dc battery current Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index 76e9966bda3f1..08956aa16df3f 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -7,7 +7,7 @@ - The EVNotify car (account) represents a connection to the EVNotify online services + The EVNotify car (account) represents a connection to the EVNotify online service @@ -91,6 +91,12 @@ DC Battery Voltage + + Number:ElectricCurrent + + DC Battery Current + + Number:Power From 8f68d86cf30ff099ba15f660d8c409dfa5203149 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 10:51:09 +0100 Subject: [PATCH 025/361] refactor: rename id of thing type Signed-off-by: Michael Schmidt --- .../binding/evnotify/internal/EVNotifyBindingConstants.java | 6 +++--- .../binding/evnotify/internal/EVNotifyHandlerFactory.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java index b17b4f9a6496d..bb7c2d343c4c8 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java @@ -36,8 +36,8 @@ public class EVNotifyBindingConstants { // .unmodifiableSet(Set.of(THING_TYPE_BRIDGE)); // List of all Thing Type UIDs - public static final String THING_TYPE_EVNOTIFY_ID = "evnotify"; - public static final ThingTypeUID THING_TYPE_EVNOTIFY = new ThingTypeUID(BINDING_ID, THING_TYPE_EVNOTIFY_ID); + public static final String THING_TYPE_CAR_ID = "car"; + public static final ThingTypeUID THING_TYPE_CAR = new ThingTypeUID(BINDING_ID, THING_TYPE_CAR_ID); // List of all Channel ids public static final String STATE_OF_HEALTH = "soh"; @@ -59,7 +59,7 @@ public class EVNotifyBindingConstants { // Collection of all supported thing types public static final Set SUPPORTED_THING_TYPES_UIDS = Collections - .unmodifiableSet(Set.of(THING_TYPE_EVNOTIFY)); + .unmodifiableSet(Set.of(THING_TYPE_CAR)); // Collections.unmodifiableSet( // Stream.concat( diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java index 64c8feb6a27c0..2d6801f16345b 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java @@ -13,7 +13,7 @@ package org.openhab.binding.evnotify.internal; import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.SUPPORTED_THING_TYPES_UIDS; -import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.THING_TYPE_EVNOTIFY; +import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.THING_TYPE_CAR; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -52,7 +52,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (THING_TYPE_EVNOTIFY.equals(thingTypeUID)) { + if (THING_TYPE_CAR.equals(thingTypeUID)) { return new EVNotifyHandler(thing); } From 0345cf93459a42c813eff142694c0000d55c088c Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 10:52:08 +0100 Subject: [PATCH 026/361] feat: add handling for external temperature Signed-off-by: Michael Schmidt --- .../openhab/binding/evnotify/internal/EVNotifyHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java index eb3eadfd345ef..3367e7bbeeef7 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -199,6 +199,11 @@ private State getValue(String channelId, CarChargingData carChargingData) { return UnDefType.UNDEF; } return new QuantityType<>(carChargingData.getBatteryInletTemperature(), SIUnits.CELSIUS); + case EXTERNAL_TEMPERATURE: + if (carChargingData.getExternalTemperature() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(carChargingData.getExternalTemperature(), SIUnits.CELSIUS); case LAST_EXTENDED: if (carChargingData.getLastExtended() == null) { return UnDefType.UNDEF; From 1fae52c02b4c596c8d555c949d95530eb0f9b52a Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 12:03:41 +0100 Subject: [PATCH 027/361] refactor: change description of binding Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/binding/binding.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml index 294739aa9ba98..b5205352f3d32 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/binding/binding.xml @@ -4,7 +4,7 @@ xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd"> EVNotify Binding - This is the binding for EVNotify. + Binding for using the EVNotify online service Michael Schmidt From 2fe24319f48c3a26715b6723fdb17dd4ac185baf Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 12:04:18 +0100 Subject: [PATCH 028/361] refactor: change labels and descriptions of channels Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/thing/thing-types.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index 08956aa16df3f..dee92f38f4315 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -43,7 +43,7 @@ - Refresh interval for acquiring data from EVNotify online service in seconds + Refresh interval for acquiring data from EVNotify online service (in seconds) s @@ -64,43 +64,43 @@ Switch - ON if connected to rapid charging + ON if connected to a rapid charging port Switch - ON if connected to normal charging + ON if connected to a normal charging port Switch - ON if connected to slow charging + ON if connected to a slow charging port Number:ElectricPotential - AUX Battery Voltage + Voltage of the aux battery Number:ElectricPotential - DC Battery Voltage + Voltage of the DC battery Number:ElectricCurrent - DC Battery Current + Current of the DC battery Number:Power - DC Battery Power + Power of the DC battery From 23c9e48cfd80b518f6744dcdff16aa6bd4e51cd3 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 12:05:06 +0100 Subject: [PATCH 029/361] feat: add de translastions for labels and descriptions Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/evnotify_de.properties | 49 +++++++++++++++++++ .../OH-INF/i18n/evnotify_xx.properties | 21 -------- 2 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties delete mode 100644 bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties new file mode 100644 index 0000000000000..61c689a2f2067 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties @@ -0,0 +1,49 @@ +# binding +binding.evnotify.name = EVNotify Binding +binding.evnotify.description = Binding zur Nutzung des EVNotify Online Service + +# thing types +thing-type.evnotify.car.label = EVNotify Auto +thing-type.evnotify.car.description = Ein EVNotify Auto (Account) reprsentiert die Verbindung zum EVNotify Online Service + +# thing type config description +thing-type.config.evnotify.car.akey.label = AKey +thing-type.config.evnotify.car.akey.description = AKey wird fr den EVNotify API Zugang bentigt +thing-type.config.evnotify.car.token.label = Token +thing-type.config.evnotify.car.token.description = Token wird fr den EVNotify API Zugang bentigt. Es ist wie ein Passwort zu behandeln. Teile es niemals mit nicht vertrauenswrdigen Personen! +thing-type.config.evnotify.car.refreshInterval.label = Aktualisierungsintervall +thing-type.config.evnotify.car.refreshInterval.description = Intervall, in dem die Daten vom EVNotify Online Service aktualisiert werden (in Sekunden) + +# channel types +channel-type.evnotify.soh.label = Akkugesundheit +channel-type.evnotify.soh.description = Akkugesundheit (SOH) +channel-type.evnotify.charging.label = Wird geladen +channel-type.evnotify.charging.description = AN wenn gerade geladen wird +channel-type.evnotify.rapid_charge_port.label = Ladestation (schnell) +channel-type.evnotify.rapid_charge_port.description = AN wenn an einer schnellen Ladestation geladen wird +channel-type.evnotify.normal_charge_port.label = Ladestation (normal) +channel-type.evnotify.normal_charge_port.description = AN wenn an einer normalen Ladestation geladen wird +channel-type.evnotify.slow_charge_port.label = Ladestation (langsam) +channel-type.evnotify.slow_charge_port.description = AN wenn an einer langsamen Ladestation geladen wird +channel-type.evnotify.aux_battery_voltage.label = Spannung 12V Batterie +channel-type.evnotify.aux_battery_voltage.description = Spannung der 12V Batterie +channel-type.evnotify.dc_battery_voltage.label = Spannung Hochvoltbatterie +channel-type.evnotify.dc_battery_voltage.description = Spannung der Hochvoltbatterie +channel-type.evnotify.dc_battery_current.label = Strom Hochvoltbatterie +channel-type.evnotify.dc_battery_current.description = Strom der Hochvoltbatterie +channel-type.evnotify.dc_battery_power.label = Leistung Hochvoltbatterie +channel-type.evnotify.dc_battery_power.description = Leistung der Hochvoltbatterie +channel-type.evnotify.cumulative_energy_charged.label = Kumulative Energie geladen +channel-type.evnotify.cumulative_energy_charged.description = Kumulative Energie, die bereits geladen wurde +channel-type.evnotify.cumulative_energy_discharged.label = Kumulative Energie entladen +channel-type.evnotify.cumulative_energy_discharged.description = Kumulative Energie, die bereits entladen wurde +channel-type.evnotify.battery_min_temperature.label = Akkutemperatur (Min) +channel-type.evnotify.battery_min_temperature.description = Minimale Akkutemperatur +channel-type.evnotify.battery_max_temperature.label = Akkutemperatur (Max) +channel-type.evnotify.battery_max_temperature.description = Maximale Akkutemperatur +channel-type.evnotify.battery_inlet_temperature.label = Akkutemperatur (Einlass) +channel-type.evnotify.battery_inlet_temperature.description = Einlass Akkutemperatur +channel-type.evnotify.external_temperature.label = Akkutemperatur (auerhalb) +channel-type.evnotify.external_temperature.description = Akkutemperatur auerhalb +channel-type.evnotify.last_extended.label = Letzte Datenaktualisierung +channel-type.evnotify.last_extended.description = Zeitpunkt der letzte Datenaktualisierung diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties deleted file mode 100644 index 18c18bff81238..0000000000000 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_xx.properties +++ /dev/null @@ -1,21 +0,0 @@ -# FIXME: please substitute the xx with a proper locale, ie. de -# FIXME: please do not add the file to the repo if you add or change no content -# binding -binding.evnotify.name = -binding.evnotify.description = - -# thing types -thing-type.evnotify.sample.label = -thing-type.evnotify.sample.description = - -# thing type config description -thing-type.config.evnotify.sample.hostname.label = -thing-type.config.evnotify.sample.hostname.description = -thing-type.config.evnotify.sample.password.label = -thing-type.config.evnotify.sample.password.description = -thing-type.config.evnotify.sample.refreshInterval.label = -thing-type.config.evnotify.sample.refreshInterval.description = - -# channel types -channel-type.evnotify.sample-channel.label = -channel-type.evnotify.sample-channel.description = From 5477736b7516172fceb95310a79ae20b6d88119d Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 16:53:36 +0100 Subject: [PATCH 030/361] feat: fix de translations for labels and descriptions Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/evnotify_de.properties | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties index 61c689a2f2067..deb9ff5595baa 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties @@ -17,33 +17,33 @@ thing-type.config.evnotify.car.refreshInterval.description = Intervall, in dem d # channel types channel-type.evnotify.soh.label = Akkugesundheit channel-type.evnotify.soh.description = Akkugesundheit (SOH) -channel-type.evnotify.charging.label = Wird geladen -channel-type.evnotify.charging.description = AN wenn gerade geladen wird -channel-type.evnotify.rapid_charge_port.label = Ladestation (schnell) -channel-type.evnotify.rapid_charge_port.description = AN wenn an einer schnellen Ladestation geladen wird -channel-type.evnotify.normal_charge_port.label = Ladestation (normal) -channel-type.evnotify.normal_charge_port.description = AN wenn an einer normalen Ladestation geladen wird -channel-type.evnotify.slow_charge_port.label = Ladestation (langsam) -channel-type.evnotify.slow_charge_port.description = AN wenn an einer langsamen Ladestation geladen wird -channel-type.evnotify.aux_battery_voltage.label = Spannung 12V Batterie -channel-type.evnotify.aux_battery_voltage.description = Spannung der 12V Batterie -channel-type.evnotify.dc_battery_voltage.label = Spannung Hochvoltbatterie -channel-type.evnotify.dc_battery_voltage.description = Spannung der Hochvoltbatterie -channel-type.evnotify.dc_battery_current.label = Strom Hochvoltbatterie -channel-type.evnotify.dc_battery_current.description = Strom der Hochvoltbatterie -channel-type.evnotify.dc_battery_power.label = Leistung Hochvoltbatterie -channel-type.evnotify.dc_battery_power.description = Leistung der Hochvoltbatterie -channel-type.evnotify.cumulative_energy_charged.label = Kumulative Energie geladen -channel-type.evnotify.cumulative_energy_charged.description = Kumulative Energie, die bereits geladen wurde -channel-type.evnotify.cumulative_energy_discharged.label = Kumulative Energie entladen -channel-type.evnotify.cumulative_energy_discharged.description = Kumulative Energie, die bereits entladen wurde -channel-type.evnotify.battery_min_temperature.label = Akkutemperatur (Min) -channel-type.evnotify.battery_min_temperature.description = Minimale Akkutemperatur -channel-type.evnotify.battery_max_temperature.label = Akkutemperatur (Max) -channel-type.evnotify.battery_max_temperature.description = Maximale Akkutemperatur -channel-type.evnotify.battery_inlet_temperature.label = Akkutemperatur (Einlass) -channel-type.evnotify.battery_inlet_temperature.description = Einlass Akkutemperatur -channel-type.evnotify.external_temperature.label = Akkutemperatur (auerhalb) -channel-type.evnotify.external_temperature.description = Akkutemperatur auerhalb -channel-type.evnotify.last_extended.label = Letzte Datenaktualisierung -channel-type.evnotify.last_extended.description = Zeitpunkt der letzte Datenaktualisierung +channel-type.evnotify.cha.label = Wird geladen +channel-type.evnotify.cha.description = AN wenn gerade geladen wird +channel-type.evnotify.rcp.label = Ladestation (schnell) +channel-type.evnotify.rcp.description = AN wenn an einer schnellen Ladestation geladen wird +channel-type.evnotify.ncp.label = Ladestation (normal) +channel-type.evnotify.ncp.description = AN wenn an einer normalen Ladestation geladen wird +channel-type.evnotify.scp.label = Ladestation (langsam) +channel-type.evnotify.scp.description = AN wenn an einer langsamen Ladestation geladen wird +channel-type.evnotify.abv.label = Spannung 12V Batterie +channel-type.evnotify.abv.description = Spannung der 12V Batterie +channel-type.evnotify.dbv.label = Spannung Hochvoltbatterie +channel-type.evnotify.dbv.description = Spannung der Hochvoltbatterie +channel-type.evnotify.dbc.label = Strom Hochvoltbatterie +channel-type.evnotify.dbc.description = Strom der Hochvoltbatterie +channel-type.evnotify.dbp.label = Leistung Hochvoltbatterie +channel-type.evnotify.dbp.description = Leistung der Hochvoltbatterie +channel-type.evnotify.cec.label = Kumulative Energie geladen +channel-type.evnotify.cec.description = Kumulative Energie, die bereits geladen wurde +channel-type.evnotify.ced.label = Kumulative Energie entladen +channel-type.evnotify.ced.description = Kumulative Energie, die bereits entladen wurde +channel-type.evnotify.bmit.label = Akkutemperatur (Min) +channel-type.evnotify.bmit.description = Minimale Akkutemperatur +channel-type.evnotify.bmat.label = Akkutemperatur (Max) +channel-type.evnotify.bmat.description = Maximale Akkutemperatur +channel-type.evnotify.bit.label = Akkutemperatur (Einlass) +channel-type.evnotify.bit.description = Einlass Akkutemperatur +channel-type.evnotify.et.label = Akkutemperatur (auerhalb) +channel-type.evnotify.et.description = Akkutemperatur auerhalb +channel-type.evnotify.le.label = Letzte Datenaktualisierung +channel-type.evnotify.le.description = Zeitpunkt der letzten Datenaktualisierung From cedfbf4f4d5c51260b300c82350499ed6619a914 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 21:08:18 +0100 Subject: [PATCH 031/361] refactor: change thing id Signed-off-by: Michael Schmidt --- .../internal/EVNotifyBindingConstants.java | 6 +++--- .../internal/EVNotifyHandlerFactory.java | 4 ++-- .../resources/OH-INF/i18n/evnotify_de.properties | 16 ++++++++-------- .../main/resources/OH-INF/thing/thing-types.xml | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java index bb7c2d343c4c8..86534df13d466 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java @@ -36,8 +36,8 @@ public class EVNotifyBindingConstants { // .unmodifiableSet(Set.of(THING_TYPE_BRIDGE)); // List of all Thing Type UIDs - public static final String THING_TYPE_CAR_ID = "car"; - public static final ThingTypeUID THING_TYPE_CAR = new ThingTypeUID(BINDING_ID, THING_TYPE_CAR_ID); + public static final String THING_TYPE_VEHICLE_ID = "vehicle"; + public static final ThingTypeUID THING_TYPE_VEHICLE = new ThingTypeUID(BINDING_ID, THING_TYPE_VEHICLE_ID); // List of all Channel ids public static final String STATE_OF_HEALTH = "soh"; @@ -59,7 +59,7 @@ public class EVNotifyBindingConstants { // Collection of all supported thing types public static final Set SUPPORTED_THING_TYPES_UIDS = Collections - .unmodifiableSet(Set.of(THING_TYPE_CAR)); + .unmodifiableSet(Set.of(THING_TYPE_VEHICLE)); // Collections.unmodifiableSet( // Stream.concat( diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java index 2d6801f16345b..2decf6db8442b 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java @@ -13,7 +13,7 @@ package org.openhab.binding.evnotify.internal; import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.SUPPORTED_THING_TYPES_UIDS; -import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.THING_TYPE_CAR; +import static org.openhab.binding.evnotify.internal.EVNotifyBindingConstants.THING_TYPE_VEHICLE; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -52,7 +52,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (THING_TYPE_CAR.equals(thingTypeUID)) { + if (THING_TYPE_VEHICLE.equals(thingTypeUID)) { return new EVNotifyHandler(thing); } diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties index deb9ff5595baa..908ab9911c040 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties @@ -3,16 +3,16 @@ binding.evnotify.name = EVNotify Binding binding.evnotify.description = Binding zur Nutzung des EVNotify Online Service # thing types -thing-type.evnotify.car.label = EVNotify Auto -thing-type.evnotify.car.description = Ein EVNotify Auto (Account) reprsentiert die Verbindung zum EVNotify Online Service +thing-type.evnotify.vehicle.label = EVNotify Auto +thing-type.evnotify.vehicle.description = Ein EVNotify Auto (Account) reprsentiert die Verbindung zum EVNotify Online Service # thing type config description -thing-type.config.evnotify.car.akey.label = AKey -thing-type.config.evnotify.car.akey.description = AKey wird fr den EVNotify API Zugang bentigt -thing-type.config.evnotify.car.token.label = Token -thing-type.config.evnotify.car.token.description = Token wird fr den EVNotify API Zugang bentigt. Es ist wie ein Passwort zu behandeln. Teile es niemals mit nicht vertrauenswrdigen Personen! -thing-type.config.evnotify.car.refreshInterval.label = Aktualisierungsintervall -thing-type.config.evnotify.car.refreshInterval.description = Intervall, in dem die Daten vom EVNotify Online Service aktualisiert werden (in Sekunden) +thing-type.config.evnotify.vehicle.akey.label = AKey +thing-type.config.evnotify.vehicle.akey.description = AKey wird fr den EVNotify API Zugang bentigt +thing-type.config.evnotify.vehicle.token.label = Token +thing-type.config.evnotify.vehicle.token.description = Token wird fr den EVNotify API Zugang bentigt. Es ist wie ein Passwort zu behandeln. Teile es niemals mit nicht vertrauenswrdigen Personen! +thing-type.config.evnotify.vehicle.refreshInterval.label = Aktualisierungsintervall +thing-type.config.evnotify.vehicle.refreshInterval.description = Intervall, in dem die Daten vom EVNotify Online Service aktualisiert werden (in Sekunden) # channel types channel-type.evnotify.soh.label = Akkugesundheit diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index dee92f38f4315..51d53a5441993 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -4,10 +4,10 @@ xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd"> - - - - The EVNotify car (account) represents a connection to the EVNotify online service + + + + The EVNotify vehicle (account) represents a connection to the EVNotify online service @@ -43,7 +43,7 @@ - Refresh interval for acquiring data from EVNotify online service (in seconds) + Refresh interval for reading data from EVNotify online service (in seconds) s From 56c487d27c6c71b493b345fd360b81b372124ff6 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:35:07 +0100 Subject: [PATCH 032/361] refactor: renaming Signed-off-by: Michael Schmidt --- .../evnotify/api/{CarChargingData.java => ChargingData.java} | 0 .../v2/{CarChargingDataDTO.java => ExtendedChargingDataDTO.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/{CarChargingData.java => ChargingData.java} (100%) rename bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/{CarChargingDataDTO.java => ExtendedChargingDataDTO.java} (100%) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java similarity index 100% rename from bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/CarChargingData.java rename to bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java similarity index 100% rename from bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/CarChargingDataDTO.java rename to bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java From a6f6dc2cb73e851635ca8062b8c8970868ded4d6 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:35:43 +0100 Subject: [PATCH 033/361] refactor: do not implement interface Signed-off-by: Michael Schmidt --- .../api/v2/ExtendedChargingDataDTO.java | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java index e35dcb31e5b3d..497f403c6aa67 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java @@ -16,13 +16,11 @@ import java.time.OffsetDateTime; import java.time.ZoneId; -import org.openhab.binding.evnotify.api.CarChargingData; - import com.google.gson.annotations.SerializedName; /** - * Represents the data that is returned by evnotify v2 API. - * + * Represents the extended data that is returned by evnotify v2 API. + * * e.g. * * { @@ -47,7 +45,7 @@ * * @author Michael Schmidt - Initial contribution */ -public class CarChargingDataDTO implements CarChargingData { +public class ExtendedChargingDataDTO { @SerializedName("charging") public Integer charging; @@ -97,83 +95,67 @@ public class CarChargingDataDTO implements CarChargingData { @SerializedName("dc_battery_power") public Float dcBatteryPower; - @Override public Float getCumulativeEnergyCharged() { return cumulativeEnergyCharged; } - @Override public Float getCumulativeEnergyDischarged() { return cumulativeEnergyDischarged; } - @Override public Float getBatteryMinTemperature() { return batteryMinTemperature; } - @Override public Float getBatteryMaxTemperature() { return batteryMaxTemperature; } - @Override public Float getBatteryInletTemperature() { return batteryInletTemperature; } - @Override public Float getExternalTemperature() { return externalTemperature; } - @Override public OffsetDateTime getLastExtended() { return lastExtended == null ? null : OffsetDateTime.from(Instant.ofEpochMilli(lastExtended).atZone(ZoneId.of("Europe/Berlin"))); } - @Override public Float getAuxBatteryVoltage() { return auxBatteryVoltage; } - @Override public Float getDcBatteryVoltage() { return dcBatteryVoltage; } - @Override public Float getDcBatteryCurrent() { return dcBatteryCurrent; } - @Override public Float getDcBatteryPower() { return dcBatteryPower; } - @Override public Boolean isCharging() { return charging != null && charging == 1; } - @Override public Boolean isRapidChargePort() { return rapidChargePort != null && rapidChargePort == 1; } - @Override public Boolean isNormalChargePort() { return normalChargePort != null && normalChargePort == 1; } - @Override public Boolean isSlowChargePort() { return slowChargePort != null && slowChargePort == 1; } - @Override public Float getStateOfHealth() { return stateOfHealth; } From 023e57c3278a86dc4c5d101c96d39d5e1649b064 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:36:20 +0100 Subject: [PATCH 034/361] refactor: renaming Signed-off-by: Michael Schmidt --- .../org/openhab/binding/evnotify/api/ChargingData.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java index 528dc3ccc9fe2..c87b37ad2b332 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ChargingData.java @@ -19,7 +19,13 @@ * * @author Michael Schmidt - Initial contribution */ -public interface CarChargingData { +public interface ChargingData { + + Float getStateOfChargeDisplay(); + + Float getStateOfChargeBms(); + + OffsetDateTime getLastStateOfCharge(); Boolean isCharging(); From 72ebe061db933c251ff629c987fb1b50ec3c880e Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:36:52 +0100 Subject: [PATCH 035/361] feat: support basic data Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/BasicChargingDataDTO.java | 57 ++++++++ .../evnotify/api/v2/ChargingDataDTO.java | 129 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java new file mode 100644 index 0000000000000..1804d33fbcae0 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +import com.google.gson.annotations.SerializedName; + +/** + * Represents the basic data that is returned by evnotify v2 API. + * + * e.g. + * + * { + * "soc_display": 93, + * "soc_bms": 88.5, + * "last_soc": 1631220014 + * } + * + * @author Michael Schmidt - Initial contribution + */ +public class BasicChargingDataDTO { + + @SerializedName("soc_display") + public Float stateOfChargeDisplay; + + @SerializedName("soc_bms") + public Float stateOfChargeBms; + + @SerializedName("last_soc") + public Integer lastStateOfCharge; + + public Float getStateOfChargeDisplay() { + return stateOfChargeDisplay; + } + + public Float getStateOfChargeBms() { + return stateOfChargeBms; + } + + public OffsetDateTime getLastStateOfCharge() { + return lastStateOfCharge == null ? null + : OffsetDateTime.from(Instant.ofEpochMilli(lastStateOfCharge).atZone(ZoneId.of("Europe/Berlin"))); + } +} diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java new file mode 100644 index 0000000000000..1089a780564cb --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import java.time.OffsetDateTime; + +import org.openhab.binding.evnotify.api.ChargingData; + +/** + * Represents the complete data that is returned by evnotify v2 API. + * + * @author Michael Schmidt - Initial contribution + */ +public class ChargingDataDTO implements ChargingData { + + private final BasicChargingDataDTO basicChargingDataDTO; + + private final ExtendedChargingDataDTO extendedChargingDataDTO; + + public ChargingDataDTO(BasicChargingDataDTO basicChargingDataDTO, ExtendedChargingDataDTO extendedChargingDataDTO) { + this.basicChargingDataDTO = basicChargingDataDTO; + this.extendedChargingDataDTO = extendedChargingDataDTO; + } + + @Override + public Float getStateOfChargeDisplay() { + return basicChargingDataDTO.getStateOfChargeDisplay(); + } + + @Override + public Float getStateOfChargeBms() { + return basicChargingDataDTO.getStateOfChargeBms(); + } + + @Override + public OffsetDateTime getLastStateOfCharge() { + return basicChargingDataDTO.getLastStateOfCharge(); + } + + @Override + public Boolean isCharging() { + return extendedChargingDataDTO.isCharging(); + } + + @Override + public Boolean isRapidChargePort() { + return extendedChargingDataDTO.isRapidChargePort(); + } + + @Override + public Boolean isNormalChargePort() { + return extendedChargingDataDTO.isNormalChargePort(); + } + + @Override + public Boolean isSlowChargePort() { + return extendedChargingDataDTO.isSlowChargePort(); + } + + @Override + public Float getStateOfHealth() { + return extendedChargingDataDTO.getStateOfHealth(); + } + + @Override + public Float getAuxBatteryVoltage() { + return extendedChargingDataDTO.getAuxBatteryVoltage(); + } + + @Override + public Float getDcBatteryVoltage() { + return extendedChargingDataDTO.getDcBatteryVoltage(); + } + + @Override + public Float getDcBatteryCurrent() { + return extendedChargingDataDTO.getDcBatteryCurrent(); + } + + @Override + public Float getDcBatteryPower() { + return extendedChargingDataDTO.getDcBatteryPower(); + } + + @Override + public Float getCumulativeEnergyCharged() { + return extendedChargingDataDTO.getCumulativeEnergyCharged(); + } + + @Override + public Float getCumulativeEnergyDischarged() { + return extendedChargingDataDTO.getCumulativeEnergyDischarged(); + } + + @Override + public Float getBatteryMinTemperature() { + return extendedChargingDataDTO.getBatteryMinTemperature(); + } + + @Override + public Float getBatteryMaxTemperature() { + return extendedChargingDataDTO.getBatteryMaxTemperature(); + } + + @Override + public Float getBatteryInletTemperature() { + return extendedChargingDataDTO.getBatteryInletTemperature(); + } + + @Override + public Float getExternalTemperature() { + return extendedChargingDataDTO.getExternalTemperature(); + } + + @Override + public OffsetDateTime getLastExtended() { + return extendedChargingDataDTO.getLastExtended(); + } +} From 48914fbcb0119cfcfebfd9eaba6699f17f4fb816 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:37:12 +0100 Subject: [PATCH 036/361] feat: support basic data Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/EVNotifyClientImpl.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index a059ba35b5b74..21bb536f31356 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -18,7 +18,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; -import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +33,7 @@ */ public class EVNotifyClientImpl implements EVNotifyClient { - public static String DEFAULT_API_URL_PATTERN = "hhttps://app.evnotify.de/soc?akey=%s&token=%s"; + public static String BASIC_API_URL_PATTERN = "https://app.evnotify.de/soc?akey=%s&token=%s"; public static String EXTENDED_API_URL_PATTERN = "https://app.evnotify.de/extended?akey=%s&token=%s"; private final Logger logger = LoggerFactory.getLogger(EVNotifyClientImpl.class); @@ -50,19 +50,26 @@ public EVNotifyClientImpl(String aKey, String token, HttpClient client) { } @Override - public CarChargingData getCarChargingData() throws IOException, InterruptedException { + public ChargingData getCarChargingData() throws IOException, InterruptedException { - // create a request - var request = HttpRequest.newBuilder(URI.create(String.format(EXTENDED_API_URL_PATTERN, aKey, token))) + // create the requests + var basicRequest = HttpRequest.newBuilder(URI.create(String.format(BASIC_API_URL_PATTERN, aKey, token))) + .header("accept", "application/json").build(); + + var extendedRequest = HttpRequest.newBuilder(URI.create(String.format(EXTENDED_API_URL_PATTERN, aKey, token))) .header("accept", "application/json").build(); try { - // use the client to send the request - var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + // use the client to send the requests + var basicResponse = client.send(basicRequest, HttpResponse.BodyHandlers.ofString()); + BasicChargingDataDTO basicChargingDataDTO = new Gson().fromJson(basicResponse.body(), + BasicChargingDataDTO.class); - CarChargingData carChargingData = new Gson().fromJson(response.body(), CarChargingDataDTO.class); + var extendedResponse = client.send(extendedRequest, HttpResponse.BodyHandlers.ofString()); + ExtendedChargingDataDTO extendedChargingData = new Gson().fromJson(extendedResponse.body(), + ExtendedChargingDataDTO.class); - return carChargingData; + return new ChargingDataDTO(basicChargingDataDTO, extendedChargingData); } catch (Exception e) { logger.error("Could not retrieve state of car", e); throw e; From 5385210344e52b1c847eae212ecbdaf7644628c1 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:37:29 +0100 Subject: [PATCH 037/361] refactor: renaming Signed-off-by: Michael Schmidt --- .../java/org/openhab/binding/evnotify/api/EVNotifyClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java index aec72341425d1..e89bf6b09264b 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java @@ -22,9 +22,9 @@ public interface EVNotifyClient { /** - * returns a {@link CarChargingData} + * returns a {@link ChargingData} * * @return state of a car */ - CarChargingData getCarChargingData() throws IOException, InterruptedException; + ChargingData getCarChargingData() throws IOException, InterruptedException; } From 3c8424d4c732b22d1743371ae2377b6ba8a974e5 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:38:03 +0100 Subject: [PATCH 038/361] refactor: renaming Signed-off-by: Michael Schmidt --- .../evnotify/internal/EVNotifyHandler.java | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java index 3367e7bbeeef7..cf4dd8511d0bb 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -26,7 +26,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.evnotify.api.ApiVersion; -import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; import org.openhab.binding.evnotify.api.v2.EVNotifyClientImpl; import org.openhab.core.library.types.OnOffType; @@ -117,98 +117,98 @@ public void initialize() { logger.debug("Finished initializing!"); } - private void updateChannelsAndStatus(@Nullable CarChargingData carChargingData, @Nullable String message) { - if (carChargingData == null) { + private void updateChannelsAndStatus(@Nullable ChargingData chargingData, @Nullable String message) { + if (chargingData == null) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message); allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF)); } else { updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE); - allChannels.forEach(channel -> updateState(channel, getValue(channel, carChargingData))); + allChannels.forEach(channel -> updateState(channel, getValue(channel, chargingData))); } } - private State getValue(String channelId, CarChargingData carChargingData) { + private State getValue(String channelId, ChargingData chargingData) { switch (channelId) { case STATE_OF_HEALTH: - if (carChargingData.getStateOfHealth() == null) { + if (chargingData.getStateOfHealth() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getStateOfHealth(), Units.PERCENT); + return new QuantityType<>(chargingData.getStateOfHealth(), Units.PERCENT); case CHARGING: - if (carChargingData.isCharging() == null) { + if (chargingData.isCharging() == null) { return UnDefType.UNDEF; } - return carChargingData.isCharging() ? OnOffType.ON : OnOffType.OFF; + return chargingData.isCharging() ? OnOffType.ON : OnOffType.OFF; case RAPID_CHARING_PORT: - if (carChargingData.isRapidChargePort() == null) { + if (chargingData.isRapidChargePort() == null) { return UnDefType.UNDEF; } - return carChargingData.isRapidChargePort() ? OnOffType.ON : OnOffType.OFF; + return chargingData.isRapidChargePort() ? OnOffType.ON : OnOffType.OFF; case NORMAL_CHARING_PORT: - if (carChargingData.isNormalChargePort() == null) { + if (chargingData.isNormalChargePort() == null) { return UnDefType.UNDEF; } - return carChargingData.isNormalChargePort() ? OnOffType.ON : OnOffType.OFF; + return chargingData.isNormalChargePort() ? OnOffType.ON : OnOffType.OFF; case SLOW_CHARING_PORT: - if (carChargingData.isSlowChargePort() == null) { + if (chargingData.isSlowChargePort() == null) { return UnDefType.UNDEF; } - return carChargingData.isSlowChargePort() ? OnOffType.ON : OnOffType.OFF; + return chargingData.isSlowChargePort() ? OnOffType.ON : OnOffType.OFF; case AUX_BATTERY_VOLTAGE: - if (carChargingData.getAuxBatteryVoltage() == null) { + if (chargingData.getAuxBatteryVoltage() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getAuxBatteryVoltage(), Units.VOLT); + return new QuantityType<>(chargingData.getAuxBatteryVoltage(), Units.VOLT); case DC_BATTERY_VOLTAGE: - if (carChargingData.getDcBatteryVoltage() == null) { + if (chargingData.getDcBatteryVoltage() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getDcBatteryVoltage(), Units.VOLT); + return new QuantityType<>(chargingData.getDcBatteryVoltage(), Units.VOLT); case DC_BATTERY_CURRENT: - if (carChargingData.getDcBatteryCurrent() == null) { + if (chargingData.getDcBatteryCurrent() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getDcBatteryCurrent(), Units.AMPERE); + return new QuantityType<>(chargingData.getDcBatteryCurrent(), Units.AMPERE); case DC_BATTERY_POWER: - if (carChargingData.getDcBatteryPower() == null) { + if (chargingData.getDcBatteryPower() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getDcBatteryPower(), Units.WATT); + return new QuantityType<>(chargingData.getDcBatteryPower(), Units.WATT); case CUMULATIVE_ENERGY_CHARGED: - if (carChargingData.getCumulativeEnergyCharged() == null) { + if (chargingData.getCumulativeEnergyCharged() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getCumulativeEnergyCharged(), Units.KILOWATT_HOUR); + return new QuantityType<>(chargingData.getCumulativeEnergyCharged(), Units.KILOWATT_HOUR); case CUMULATIVE_ENERGY_DISCHARGED: - if (carChargingData.getCumulativeEnergyDischarged() == null) { + if (chargingData.getCumulativeEnergyDischarged() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getCumulativeEnergyDischarged(), Units.KILOWATT_HOUR); + return new QuantityType<>(chargingData.getCumulativeEnergyDischarged(), Units.KILOWATT_HOUR); case BATTERY_MAX_TEMPERATURE: - if (carChargingData.getBatteryMaxTemperature() == null) { + if (chargingData.getBatteryMaxTemperature() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getBatteryMaxTemperature(), SIUnits.CELSIUS); + return new QuantityType<>(chargingData.getBatteryMaxTemperature(), SIUnits.CELSIUS); case BATTERY_MIN_TEMPERATURE: - if (carChargingData.getBatteryMinTemperature() == null) { + if (chargingData.getBatteryMinTemperature() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getBatteryMinTemperature(), SIUnits.CELSIUS); + return new QuantityType<>(chargingData.getBatteryMinTemperature(), SIUnits.CELSIUS); case BATTERY_INLET_TEMPERATURE: - if (carChargingData.getBatteryInletTemperature() == null) { + if (chargingData.getBatteryInletTemperature() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getBatteryInletTemperature(), SIUnits.CELSIUS); + return new QuantityType<>(chargingData.getBatteryInletTemperature(), SIUnits.CELSIUS); case EXTERNAL_TEMPERATURE: - if (carChargingData.getExternalTemperature() == null) { + if (chargingData.getExternalTemperature() == null) { return UnDefType.UNDEF; } - return new QuantityType<>(carChargingData.getExternalTemperature(), SIUnits.CELSIUS); + return new QuantityType<>(chargingData.getExternalTemperature(), SIUnits.CELSIUS); case LAST_EXTENDED: - if (carChargingData.getLastExtended() == null) { + if (chargingData.getLastExtended() == null) { return UnDefType.UNDEF; } - return new StringType(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(carChargingData.getLastExtended())); + return new StringType(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(chargingData.getLastExtended())); } return UnDefType.UNDEF; } @@ -217,8 +217,8 @@ private void refresh() { // Request new EVNotify data try { if (client != null) { - CarChargingData carChargingData = client.getCarChargingData(); - updateChannelsAndStatus(carChargingData, null); + ChargingData chargingData = client.getCarChargingData(); + updateChannelsAndStatus(chargingData, null); } } catch (InterruptedException | IOException e) { From aa9c708bea84d27157f3f38633cce00d9bddc8c8 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 1 Nov 2021 23:38:22 +0100 Subject: [PATCH 039/361] test: support basic data Signed-off-by: Michael Schmidt --- .../api/v2/EVNotifyClientImplTest.java | 97 +++++++++++++------ 1 file changed, 67 insertions(+), 30 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java index 45cc16e47f982..200b2de825d91 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -13,12 +13,13 @@ package org.openhab.binding.evnotify.api.v2; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; @@ -29,8 +30,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; -import org.openhab.binding.evnotify.api.CarChargingData; +import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; /** @@ -43,38 +45,53 @@ class EVNotifyClientImplTest { @Mock HttpClient httpClient; + private URI basicUri = new URI("https://app.evnotify.de/soc"); + + private URI extendedUri = new URI("https://app.evnotify.de/extended"); + + EVNotifyClientImplTest() throws URISyntaxException { + } + @BeforeEach void setUp() { httpClient = mock(HttpClient.class); } @Test - void shouldGiveAValidCarCHargingDataForValidResponse() throws IOException, InterruptedException { + void shouldGiveAValidCarChargingDataForValidResponse() throws IOException, InterruptedException { // given - HttpResponse response = getResponse(200, getResponseBody()); - when(httpClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(response); + HttpResponse basicResponse = getResponse(200, getBasicResponseBody()); + when(httpClient.send(argThat(new HttpRequestUriMatcher(basicUri)), any(HttpResponse.BodyHandler.class))) + .thenReturn(basicResponse); + + HttpResponse extendedResponse = getResponse(200, getExtendedResponseBody()); + when(httpClient.send(argThat(new HttpRequestUriMatcher(extendedUri)), any(HttpResponse.BodyHandler.class))) + .thenReturn(extendedResponse); EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when - CarChargingData carChargingData = evNotifyClient.getCarChargingData(); + ChargingData chargingData = evNotifyClient.getCarChargingData(); // then - assertEquals(true, carChargingData.isCharging()); - assertEquals(false, carChargingData.isRapidChargePort()); - assertEquals(true, carChargingData.isNormalChargePort()); - assertEquals(false, carChargingData.isSlowChargePort()); - assertEquals(Float.valueOf(100.0f), carChargingData.getStateOfHealth()); - assertEquals(Float.valueOf(14.5f), carChargingData.getAuxBatteryVoltage()); - assertEquals(Float.valueOf(362.1f), carChargingData.getDcBatteryVoltage()); - assertEquals(Float.valueOf(-8.7f), carChargingData.getDcBatteryCurrent()); - assertEquals(Float.valueOf(-3.15027f), carChargingData.getDcBatteryPower()); - assertEquals(Float.valueOf(3881.5f), carChargingData.getCumulativeEnergyCharged()); - assertEquals(Float.valueOf(3738.8f), carChargingData.getCumulativeEnergyDischarged()); - assertEquals(Float.valueOf(25f), carChargingData.getBatteryMinTemperature()); - assertEquals(Float.valueOf(26f), carChargingData.getBatteryMaxTemperature()); - assertEquals(Float.valueOf(24f), carChargingData.getBatteryInletTemperature()); - assertNull(carChargingData.getExternalTemperature()); - assertEquals(1631220014L, carChargingData.getLastExtended().toInstant().toEpochMilli()); + assertEquals(Float.valueOf(93.0f), chargingData.getStateOfChargeDisplay()); + assertEquals(Float.valueOf(88.5f), chargingData.getStateOfChargeBms()); + assertEquals(1631220014L, chargingData.getLastStateOfCharge().toInstant().toEpochMilli()); + assertEquals(true, chargingData.isCharging()); + assertEquals(false, chargingData.isRapidChargePort()); + assertEquals(true, chargingData.isNormalChargePort()); + assertEquals(false, chargingData.isSlowChargePort()); + assertEquals(Float.valueOf(100.0f), chargingData.getStateOfHealth()); + assertEquals(Float.valueOf(14.5f), chargingData.getAuxBatteryVoltage()); + assertEquals(Float.valueOf(362.1f), chargingData.getDcBatteryVoltage()); + assertEquals(Float.valueOf(-8.7f), chargingData.getDcBatteryCurrent()); + assertEquals(Float.valueOf(-3.15027f), chargingData.getDcBatteryPower()); + assertEquals(Float.valueOf(3881.5f), chargingData.getCumulativeEnergyCharged()); + assertEquals(Float.valueOf(3738.8f), chargingData.getCumulativeEnergyDischarged()); + assertEquals(Float.valueOf(25f), chargingData.getBatteryMinTemperature()); + assertEquals(Float.valueOf(26f), chargingData.getBatteryMaxTemperature()); + assertEquals(Float.valueOf(24f), chargingData.getBatteryInletTemperature()); + assertNull(chargingData.getExternalTemperature()); + assertEquals(1631220014L, chargingData.getLastExtended().toInstant().toEpochMilli()); } private HttpResponse getResponse(Integer statusCode, String body) { @@ -121,13 +138,33 @@ public HttpClient.Version version() { }; } - private String getResponseBody() { - return "{" + "\"soh\": 100," + "\"charging\": 1," + "\"rapid_charge_port\": 0," + "\"normal_charge_port\": 1," - + "\"slow_charge_port\": null," + "\"aux_battery_voltage\": 14.5," + "\"dc_battery_voltage\": 362.1," - + "\"dc_battery_current\": -8.7," + "\"dc_battery_power\": -3.15027," - + "\"cumulative_energy_charged\": 3881.5," + "\"cumulative_energy_discharged\": 3738.8," - + "\"battery_min_temperature\": 25," + "\"battery_max_temperature\": 26," - + "\"battery_inlet_temperature\": 24," + "\"external_temperature\": null," + "\"odo\": null," - + "\"last_extended\": 1631220014" + "}"; + private String getBasicResponseBody() { + return "{\"soc_display\": 93,\"soc_bms\": 88.5,\"last_soc\": 1631220014}"; + } + + private String getExtendedResponseBody() { + return "{\"soh\": 100,\"charging\": 1,\"rapid_charge_port\": 0,\"normal_charge_port\": 1," + + "\"slow_charge_port\": null,\"aux_battery_voltage\": 14.5,\"dc_battery_voltage\": 362.1," + + "\"dc_battery_current\": -8.7,\"dc_battery_power\": -3.15027," + + "\"cumulative_energy_charged\": 3881.5,\"cumulative_energy_discharged\": 3738.8," + + "\"battery_min_temperature\": 25,\"battery_max_temperature\": 26," + + "\"battery_inlet_temperature\": 24,\"external_temperature\": null,\"odo\": null," + + "\"last_extended\": 1631220014}"; + } + + private class HttpRequestUriMatcher implements ArgumentMatcher { + + private final URI uri; + + protected HttpRequestUriMatcher(URI uri) { + this.uri = uri; + } + + @Override + public boolean matches(HttpRequest httpRequest) { + return httpRequest != null && this.uri.getScheme().equals(httpRequest.uri().getScheme()) + && this.uri.getHost().equals(httpRequest.uri().getHost()) + && this.uri.getPath().equals(httpRequest.uri().getPath()); + } } } From 142c43ae8e44dac858fbf4c2640c64ed3bb9f1df Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:14:29 +0100 Subject: [PATCH 040/361] feat: add missing basic channels and rename types Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/evnotify_de.properties | 70 ++++++++------- .../resources/OH-INF/thing/thing-types.xml | 87 ++++++++++++------- 2 files changed, 92 insertions(+), 65 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties index 908ab9911c040..4753f532ccb98 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties @@ -15,35 +15,41 @@ thing-type.config.evnotify.vehicle.refreshInterval.label = Aktualisierungsinterv thing-type.config.evnotify.vehicle.refreshInterval.description = Intervall, in dem die Daten vom EVNotify Online Service aktualisiert werden (in Sekunden) # channel types -channel-type.evnotify.soh.label = Akkugesundheit -channel-type.evnotify.soh.description = Akkugesundheit (SOH) -channel-type.evnotify.cha.label = Wird geladen -channel-type.evnotify.cha.description = AN wenn gerade geladen wird -channel-type.evnotify.rcp.label = Ladestation (schnell) -channel-type.evnotify.rcp.description = AN wenn an einer schnellen Ladestation geladen wird -channel-type.evnotify.ncp.label = Ladestation (normal) -channel-type.evnotify.ncp.description = AN wenn an einer normalen Ladestation geladen wird -channel-type.evnotify.scp.label = Ladestation (langsam) -channel-type.evnotify.scp.description = AN wenn an einer langsamen Ladestation geladen wird -channel-type.evnotify.abv.label = Spannung 12V Batterie -channel-type.evnotify.abv.description = Spannung der 12V Batterie -channel-type.evnotify.dbv.label = Spannung Hochvoltbatterie -channel-type.evnotify.dbv.description = Spannung der Hochvoltbatterie -channel-type.evnotify.dbc.label = Strom Hochvoltbatterie -channel-type.evnotify.dbc.description = Strom der Hochvoltbatterie -channel-type.evnotify.dbp.label = Leistung Hochvoltbatterie -channel-type.evnotify.dbp.description = Leistung der Hochvoltbatterie -channel-type.evnotify.cec.label = Kumulative Energie geladen -channel-type.evnotify.cec.description = Kumulative Energie, die bereits geladen wurde -channel-type.evnotify.ced.label = Kumulative Energie entladen -channel-type.evnotify.ced.description = Kumulative Energie, die bereits entladen wurde -channel-type.evnotify.bmit.label = Akkutemperatur (Min) -channel-type.evnotify.bmit.description = Minimale Akkutemperatur -channel-type.evnotify.bmat.label = Akkutemperatur (Max) -channel-type.evnotify.bmat.description = Maximale Akkutemperatur -channel-type.evnotify.bit.label = Akkutemperatur (Einlass) -channel-type.evnotify.bit.description = Einlass Akkutemperatur -channel-type.evnotify.et.label = Akkutemperatur (auerhalb) -channel-type.evnotify.et.description = Akkutemperatur auerhalb -channel-type.evnotify.le.label = Letzte Datenaktualisierung -channel-type.evnotify.le.description = Zeitpunkt der letzten Datenaktualisierung +channel-type.evnotify.type_soc_display.label = Ladezustand (Display) +channel-type.evnotify.type_soc_display.description = Ladezustand (Display) +channel-type.evnotify.type_soc_bms.label = Ladezustand (BMS) +channel-type.evnotify.type_soc_bms.description = Ladezustand (BMS) +channel-type.evnotify.type_last_soc.label = Letzte Datenaktualisierung (SOC) +channel-type.evnotify.type_last_soc.description = Zeitpunkt der letzten Datenaktualisierung (SOC) +channel-type.evnotify.type_soh.label = Akkugesundheit +channel-type.evnotify.type_soh.description = Akkugesundheit (SOH) +channel-type.evnotify.type_charging.label = Wird geladen +channel-type.evnotify.type_charging.description = AN wenn gerade geladen wird +channel-type.evnotify.type_rapid_charge_port.label = Ladestation (schnell) +channel-type.evnotify.type_rapid_charge_port.description = AN wenn an einer schnellen Ladestation geladen wird +channel-type.evnotify.type_normal_charge_port.label = Ladestation (normal) +channel-type.evnotify.type_normal_charge_port.description = AN wenn an einer normalen Ladestation geladen wird +channel-type.evnotify.type_slow_charge_port.label = Ladestation (langsam) +channel-type.evnotify.type_slow_charge_port.description = AN wenn an einer langsamen Ladestation geladen wird +channel-type.evnotify.type_aux_battery_voltage.label = Spannung 12V Batterie +channel-type.evnotify.type_aux_battery_voltage.description = Spannung der 12V Batterie +channel-type.evnotify.type_dc_battery_voltage.label = Spannung Hochvoltbatterie +channel-type.evnotify.type_dc_battery_voltage.description = Spannung der Hochvoltbatterie +channel-type.evnotify.type_dc_battery_current.label = Strom Hochvoltbatterie +channel-type.evnotify.type_dc_battery_current.description = Strom der Hochvoltbatterie +channel-type.evnotify.type_dc_battery_power.label = Leistung Hochvoltbatterie +channel-type.evnotify.type_dc_battery_power.description = Leistung der Hochvoltbatterie +channel-type.evnotify.type_cumulative_energy_charged.label = Kumulative Energie geladen +channel-type.evnotify.type_cumulative_energy_charged.description = Kumulative Energie, die bereits geladen wurde +channel-type.evnotify.type_cumulative_energy_discharged.label = Kumulative Energie entladen +channel-type.evnotify.type_cumulative_energy_discharged.description = Kumulative Energie, die bereits entladen wurde +channel-type.evnotify.type_battery_min_temperature.label = Akkutemperatur (Min) +channel-type.evnotify.type_battery_min_temperature.description = Minimale Akkutemperatur +channel-type.evnotify.type_battery_max_temperature.label = Akkutemperatur (Max) +channel-type.evnotify.type_battery_max_temperature.description = Maximale Akkutemperatur +channel-type.evnotify.type_battery_inlet_temperature.label = Akkutemperatur (Einlass) +channel-type.evnotify.type_battery_inlet_temperature.description = Einlass Akkutemperatur +channel-type.evnotify.type_external_temperature.label = Akkutemperatur (auerhalb) +channel-type.evnotify.type_external_temperature.description = Akkutemperatur auerhalb +channel-type.evnotify.type_last_extended.label = Letzte Datenaktualisierung +channel-type.evnotify.type_last_extended.description = Zeitpunkt der letzten Datenaktualisierung diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index 51d53a5441993..a88a23074ca4e 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -10,22 +10,25 @@ The EVNotify vehicle (account) represents a connection to the EVNotify online service - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -49,103 +52,121 @@ - + + Number + + State of Charge (Display) + + + + Number + + State of Charge (BMS) + + + + String + + Timestamp of the latest state of charge export + + + Number State of Health - + Switch ON if charging - + Switch ON if connected to a rapid charging port - + Switch ON if connected to a normal charging port - + Switch ON if connected to a slow charging port - + Number:ElectricPotential Voltage of the aux battery - + Number:ElectricPotential Voltage of the DC battery - + Number:ElectricCurrent Current of the DC battery - + Number:Power Power of the DC battery - + Number:Energy Amount of energy that has been charged - + Number:Energy Amount of energy that has been discharged - + Number:Temperature External Temperature - + Number:Temperature Battery Min Temperature - + Number:Temperature Battery Max Temperature - + Number:Temperature Battery Inlet Temperature - + Number:Temperature External Temperature - + String Timestamp of the latest export From ebd118353cbb1516e9652bccc2b1f94f22a9c25c Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:16:11 +0100 Subject: [PATCH 041/361] docs: improve JavaDoc Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/v2/ExtendedChargingDataDTO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java index 497f403c6aa67..775aabeb44a21 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java @@ -20,7 +20,7 @@ /** * Represents the extended data that is returned by evnotify v2 API. - * + * * e.g. * * { From 4cb65b7d8f77bf3ba1c5b55712f5ffa1338ca5ef Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:16:35 +0100 Subject: [PATCH 042/361] feat: add missing basic channel ids Signed-off-by: Michael Schmidt --- .../binding/evnotify/internal/EVNotifyBindingConstants.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java index 86534df13d466..c0808fbc572dc 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyBindingConstants.java @@ -40,6 +40,9 @@ public class EVNotifyBindingConstants { public static final ThingTypeUID THING_TYPE_VEHICLE = new ThingTypeUID(BINDING_ID, THING_TYPE_VEHICLE_ID); // List of all Channel ids + public static final String STATE_OF_CHARGE_DISPLAY = "soc_display"; + public static final String STATE_OF_CHARGE_BMS = "soc_bms"; + public static final String LAST_STATE_OF_CHARGE = "last_soc"; public static final String STATE_OF_HEALTH = "soh"; public static final String CHARGING = "charging"; public static final String RAPID_CHARING_PORT = "rapid_charge_port"; From e3abc350ea0e0c33d1526c1d77754f79e700931f Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:17:16 +0100 Subject: [PATCH 043/361] feat: add exception for api errors Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/ApiException.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiException.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiException.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiException.java new file mode 100644 index 0000000000000..3335d4b757edd --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiException.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api; + +/** + * Class for API error. + * + * @author Michael Schmidt - Initial contribution + */ +public class ApiException extends Exception { + + public ApiException(String message) { + super(message); + } + + public ApiException(String message, Throwable cause) { + super(message, cause); + } +} From a3a0afea2464797023376e66d49c3dec82321f82 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:18:10 +0100 Subject: [PATCH 044/361] feat: handle exceptions Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/EVNotifyClient.java | 2 +- .../evnotify/api/v2/EVNotifyClientImpl.java | 24 +++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java index e89bf6b09264b..410afea98e3c5 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/EVNotifyClient.java @@ -26,5 +26,5 @@ public interface EVNotifyClient { * * @return state of a car */ - ChargingData getCarChargingData() throws IOException, InterruptedException; + ChargingData getCarChargingData() throws IOException, InterruptedException, ApiException; } diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index 21bb536f31356..c39133dbcc3f6 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -18,12 +18,14 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import org.openhab.binding.evnotify.api.ApiException; import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; /** * The {@link EVNotifyClient} is responsible for retrieving @@ -50,7 +52,7 @@ public EVNotifyClientImpl(String aKey, String token, HttpClient client) { } @Override - public ChargingData getCarChargingData() throws IOException, InterruptedException { + public ChargingData getCarChargingData() throws IOException, InterruptedException, ApiException { // create the requests var basicRequest = HttpRequest.newBuilder(URI.create(String.format(BASIC_API_URL_PATTERN, aKey, token))) @@ -62,17 +64,35 @@ public ChargingData getCarChargingData() throws IOException, InterruptedExceptio try { // use the client to send the requests var basicResponse = client.send(basicRequest, HttpResponse.BodyHandlers.ofString()); + validateResponse(basicResponse); BasicChargingDataDTO basicChargingDataDTO = new Gson().fromJson(basicResponse.body(), BasicChargingDataDTO.class); var extendedResponse = client.send(extendedRequest, HttpResponse.BodyHandlers.ofString()); + validateResponse(extendedResponse); ExtendedChargingDataDTO extendedChargingData = new Gson().fromJson(extendedResponse.body(), ExtendedChargingDataDTO.class); return new ChargingDataDTO(basicChargingDataDTO, extendedChargingData); + } catch (JsonSyntaxException e) { + throw new ApiException("Request failed with invalid response body", e); } catch (Exception e) { - logger.error("Could not retrieve state of car", e); throw e; } } + + private void validateResponse(HttpResponse httpResponse) throws ApiException { + if (httpResponse != null) { + + if (httpResponse.statusCode() >= 400) { + throw new ApiException(String.format("Request failed with status %d", httpResponse.statusCode())); + } + + if (httpResponse.body() == null) { + throw new ApiException("Request failed with null response body"); + } + } else { + throw new ApiException("Response was null."); + } + } } From 266283be40b8d976d6ef7064fef5f49f95202b72 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:18:48 +0100 Subject: [PATCH 045/361] feat: handle missing basic channels Signed-off-by: Michael Schmidt --- .../evnotify/internal/EVNotifyHandler.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java index cf4dd8511d0bb..3959abfc5eee5 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.evnotify.api.ApiException; import org.openhab.binding.evnotify.api.ApiVersion; import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; @@ -129,6 +130,22 @@ private void updateChannelsAndStatus(@Nullable ChargingData chargingData, @Nulla private State getValue(String channelId, ChargingData chargingData) { switch (channelId) { + case STATE_OF_CHARGE_DISPLAY: + if (chargingData.getStateOfHealth() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(chargingData.getStateOfChargeDisplay(), Units.PERCENT); + case STATE_OF_CHARGE_BMS: + if (chargingData.getStateOfHealth() == null) { + return UnDefType.UNDEF; + } + return new QuantityType<>(chargingData.getStateOfChargeBms(), Units.PERCENT); + case LAST_STATE_OF_CHARGE: + if (chargingData.getLastExtended() == null) { + return UnDefType.UNDEF; + } + return new StringType( + DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(chargingData.getLastStateOfCharge())); case STATE_OF_HEALTH: if (chargingData.getStateOfHealth() == null) { return UnDefType.UNDEF; @@ -221,7 +238,7 @@ private void refresh() { updateChannelsAndStatus(chargingData, null); } - } catch (InterruptedException | IOException e) { + } catch (InterruptedException | IOException | ApiException e) { updateChannelsAndStatus(null, e.getMessage()); } } From 0c2d54ca78992b7b34bab2c3ee42c3939591bb10 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 07:19:42 +0100 Subject: [PATCH 046/361] test: extend tests for validation Signed-off-by: Michael Schmidt --- .../api/v2/EVNotifyClientImplTest.java | 219 ++++++++++++++++-- 1 file changed, 203 insertions(+), 16 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java index 200b2de825d91..dad561cad0a0e 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -32,6 +32,7 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatcher; import org.mockito.Mock; +import org.openhab.binding.evnotify.api.ApiException; import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; @@ -45,9 +46,13 @@ class EVNotifyClientImplTest { @Mock HttpClient httpClient; - private URI basicUri = new URI("https://app.evnotify.de/soc"); + private final URI basicUri = new URI("https://app.evnotify.de/soc"); - private URI extendedUri = new URI("https://app.evnotify.de/extended"); + private final URI extendedUri = new URI("https://app.evnotify.de/extended"); + + private final HttpRequestUriMatcher basicUriMatcher = new HttpRequestUriMatcher(basicUri); + + private final HttpRequestUriMatcher extendedUriMatcher = new HttpRequestUriMatcher(extendedUri); EVNotifyClientImplTest() throws URISyntaxException { } @@ -58,15 +63,14 @@ void setUp() { } @Test - void shouldGiveAValidCarChargingDataForValidResponse() throws IOException, InterruptedException { + void shouldGiveAValidChargingDataForValidResponse() throws IOException, InterruptedException, ApiException { // given - HttpResponse basicResponse = getResponse(200, getBasicResponseBody()); - when(httpClient.send(argThat(new HttpRequestUriMatcher(basicUri)), any(HttpResponse.BodyHandler.class))) - .thenReturn(basicResponse); + HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); - HttpResponse extendedResponse = getResponse(200, getExtendedResponseBody()); - when(httpClient.send(argThat(new HttpRequestUriMatcher(extendedUri)), any(HttpResponse.BodyHandler.class))) - .thenReturn(extendedResponse); EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when @@ -76,10 +80,10 @@ void shouldGiveAValidCarChargingDataForValidResponse() throws IOException, Inter assertEquals(Float.valueOf(93.0f), chargingData.getStateOfChargeDisplay()); assertEquals(Float.valueOf(88.5f), chargingData.getStateOfChargeBms()); assertEquals(1631220014L, chargingData.getLastStateOfCharge().toInstant().toEpochMilli()); - assertEquals(true, chargingData.isCharging()); - assertEquals(false, chargingData.isRapidChargePort()); - assertEquals(true, chargingData.isNormalChargePort()); - assertEquals(false, chargingData.isSlowChargePort()); + assertTrue(chargingData.isCharging()); + assertFalse(chargingData.isRapidChargePort()); + assertTrue(chargingData.isNormalChargePort()); + assertFalse(chargingData.isSlowChargePort()); assertEquals(Float.valueOf(100.0f), chargingData.getStateOfHealth()); assertEquals(Float.valueOf(14.5f), chargingData.getAuxBatteryVoltage()); assertEquals(Float.valueOf(362.1f), chargingData.getDcBatteryVoltage()); @@ -94,6 +98,176 @@ void shouldGiveAValidCarChargingDataForValidResponse() throws IOException, Inter assertEquals(1631220014L, chargingData.getLastExtended().toInstant().toEpochMilli()); } + @Test + void shouldGiveAEmptyChargingDataForEmptyResponse() throws IOException, InterruptedException, ApiException { + // given + HttpResponse basicResponse = getResponse(200, getEmptyResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getEmptyResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + ChargingData chargingData = evNotifyClient.getCarChargingData(); + + // then + assertNull(chargingData.getStateOfChargeDisplay()); + assertNull(chargingData.getStateOfChargeBms()); + assertNull(chargingData.getLastStateOfCharge()); + assertFalse(chargingData.isCharging()); + assertFalse(chargingData.isRapidChargePort()); + assertFalse(chargingData.isNormalChargePort()); + assertFalse(chargingData.isSlowChargePort()); + assertNull(chargingData.getStateOfHealth()); + assertNull(chargingData.getAuxBatteryVoltage()); + assertNull(chargingData.getDcBatteryVoltage()); + assertNull(chargingData.getDcBatteryCurrent()); + assertNull(chargingData.getDcBatteryPower()); + assertNull(chargingData.getCumulativeEnergyCharged()); + assertNull(chargingData.getCumulativeEnergyDischarged()); + assertNull(chargingData.getBatteryMinTemperature()); + assertNull(chargingData.getBatteryMaxTemperature()); + assertNull(chargingData.getBatteryInletTemperature()); + assertNull(chargingData.getExternalTemperature()); + assertNull(chargingData.getLastExtended()); + } + + @Test + void shouldThrowApiExceptionForNullBasicResponse() throws IOException, InterruptedException { + // given + mockResponse(basicUriMatcher, null); + + HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForNullExtendedResponse() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + mockResponse(extendedUriMatcher, null); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForInvalidBasicResponseStatus() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(400, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForInvalidExtendedResponseStatus() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(400, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForNullBasicResponseBody() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, null); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForNullExtendedResponseBody() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, null); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForInvalidBasicResponseBody() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, getInvalidResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + + @Test + void shouldThrowApiExceptionForInvalidExtendedResponseBody() throws IOException, InterruptedException { + // given + HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); + mockResponse(basicUriMatcher, basicResponse); + + HttpResponse extendedResponse = getResponse(200, getInvalidResponseBody()); + mockResponse(extendedUriMatcher, extendedResponse); + + EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); + + // when + assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + + // then + } + private HttpResponse getResponse(Integer statusCode, String body) { return new HttpResponse<>() { @Override @@ -138,11 +312,19 @@ public HttpClient.Version version() { }; } - private String getBasicResponseBody() { + private String getValidBasicResponseBody() { return "{\"soc_display\": 93,\"soc_bms\": 88.5,\"last_soc\": 1631220014}"; } - private String getExtendedResponseBody() { + private String getEmptyResponseBody() { + return "{}"; + } + + private String getInvalidResponseBody() { + return "{999}"; + } + + private String getValidExtendedResponseBody() { return "{\"soh\": 100,\"charging\": 1,\"rapid_charge_port\": 0,\"normal_charge_port\": 1," + "\"slow_charge_port\": null,\"aux_battery_voltage\": 14.5,\"dc_battery_voltage\": 362.1," + "\"dc_battery_current\": -8.7,\"dc_battery_power\": -3.15027," @@ -152,7 +334,12 @@ private String getExtendedResponseBody() { + "\"last_extended\": 1631220014}"; } - private class HttpRequestUriMatcher implements ArgumentMatcher { + private void mockResponse(HttpRequestUriMatcher httpRequestUriMatcher, HttpResponse response) + throws IOException, InterruptedException { + when(httpClient.send(argThat(httpRequestUriMatcher), any(HttpResponse.BodyHandler.class))).thenReturn(response); + } + + private static class HttpRequestUriMatcher implements ArgumentMatcher { private final URI uri; From b9306ea1ef8d1e636c2624e8c1d7150ec03265dd Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 17:19:45 +0100 Subject: [PATCH 047/361] feat: change some descriptions Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/evnotify_de.properties | 2 +- .../resources/OH-INF/thing/thing-types.xml | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties index 4753f532ccb98..1da46c8f4a6b8 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/i18n/evnotify_de.properties @@ -4,7 +4,7 @@ binding.evnotify.description = Binding zur Nutzung des EVNotify Online Service # thing types thing-type.evnotify.vehicle.label = EVNotify Auto -thing-type.evnotify.vehicle.description = Ein EVNotify Auto (Account) reprsentiert die Verbindung zum EVNotify Online Service +thing-type.evnotify.vehicle.description = Ein EVNotify Auto reprsentiert die Verbindung zum EVNotify Online Service (Account) # thing type config description thing-type.config.evnotify.vehicle.akey.label = AKey diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index a88a23074ca4e..9326f661dd908 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -7,7 +7,7 @@ - The EVNotify vehicle (account) represents a connection to the EVNotify online service + The EVNotify vehicle represents a connection to the EVNotify online service (account) @@ -136,34 +136,28 @@ Amount of energy that has been discharged - - Number:Temperature - - External Temperature - - Number:Temperature - Battery Min Temperature + The minimum temperature of the battery Number:Temperature - - Battery Max Temperature + + The maximum temperature of the battery Number:Temperature - Battery Inlet Temperature + The inlet temperature of the battery Number:Temperature - External Temperature + External temperature From 24bc1f4c06ce467768c02835b1a27c42866226bb Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 17:21:06 +0100 Subject: [PATCH 048/361] feat: increase default refresh interval Signed-off-by: Michael Schmidt --- .../binding/evnotify/internal/EVNotifyConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java index 3772b0a2310f4..2cf2d320e2e38 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java @@ -39,5 +39,5 @@ public class EVNotifyConfiguration { /** * Refresh interval */ - public Integer refreshInterval = 5; + public Integer refreshInterval = 120; } From fadf7b3907b1e09d1011561fe2f3464898b14b56 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 3 Nov 2021 17:21:34 +0100 Subject: [PATCH 049/361] docs: document binding Signed-off-by: Michael Schmidt --- .../org.openhab.binding.evnotify/README.md | 106 ++++++++++++------ 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/README.md b/bundles/org.openhab.binding.evnotify/README.md index 68d59ec2d753b..ba6388b5fb9f2 100644 --- a/bundles/org.openhab.binding.evnotify/README.md +++ b/bundles/org.openhab.binding.evnotify/README.md @@ -1,56 +1,98 @@ # EVNotify Binding -_Give some details about what this binding is meant for - a protocol, system, specific device._ +This binding can be used to read data for a given electric vehicle from the EVNotify online service (account). Please see [EVNotify](https://evnotify.de/). -_If possible, provide some resources like pictures, a video, etc. to give an impression of what can be done with this binding. You can place such resources into a `doc` folder next to this README.md._ +It allows you to monitor different data from your electric vehicle (e.g. state of charge, state of health, etc.). + +The binding was tested with a Hyundai Ioniq electric. ## Supported Things -_Please describe the different supported things / devices within this section._ -_Which different types are supported, which models were tested etc.?_ -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ +| Thing Type | Description | +| ---------- | ----------- | +| `vehicle` | The vehicle represents a connection to the [EVNotify](https://evnotify.de/) online service (account) | ## Discovery -_Describe the available auto-discovery features here. Mention for what it works and what needs to be kept in mind when using it._ +There is no discovery implemented. You have to create your things manually and specify the `AKey` and the `Token` of your [EVNotify](https://evnotify.de/) online service (account). ## Binding Configuration -_If your binding requires or supports general configuration settings, please create a folder ```cfg``` and place the configuration file ```.cfg``` inside it. In this section, you should link to this file and provide some information about the options. The file could e.g. look like:_ - -``` -# Configuration for the EVNotify Binding -# -# Default secret key for the pairing of the EVNotify Thing. -# It has to be between 10-40 (alphanumeric) characters. -# This may be changed by the user for security reasons. -secret=openHABSecret -``` - -_Note that it is planned to generate some part of this based on the information that is available within ```src/main/resources/OH-INF/binding``` of your binding._ - -_If your binding does not offer any generic configurations, you can remove this section completely._ +The binding has no configuration options, all configuration is done at `vehicle` level. ## Thing Configuration -_Describe what is needed to manually configure a thing, either through the UI or via a thing-file. This should be mainly about its mandatory and optional configuration parameters. A short example entry for a thing file can help!_ +### Vehicle Thing Configuration -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ +| Parameter | Description | Required | Default | +| ----------------- | ----------- | :------: | :-----: | +| `AKey` | AKey used for EVNotify API access | yes | - | +| `Token` | Token used for EVNotify API access. It is like a password. Do not share this with people you do not trust! | yes | - | +| `refreshInterval` | Refresh interval for reading data from EVNotify online service (in seconds) | no | 120 | ## Channels -_Here you should provide information about available channel types, what their meaning is and how they can be used._ - -_Note that it is planned to generate some part of this based on the XML files within ```src/main/resources/OH-INF/thing``` of your binding._ - -| channel | type | description | -|----------|--------|------------------------------| -| control | Switch | This is the control channel | +### Channels for Vehicle Thing + +| Channel ID | Item Type | Description | +| ------------------------------ | --------- | ---------------------------------------------- | +| `soc_display` | Number | State of Charge (Display) | +| `soc_bms` | Number | State of Charge (BMS) | +| `last_soc` | String | Timestamp of the latest state of charge export | +| `soh` | Number | State of Health | +| `charging` | Switch | ON if charging | +| `rapid_charge_port` | Switch | ON if connected to a rapid charging port | +| `normal_charge_port` | Switch | ON if connected to a normal charging port | +| `slow_charge_port` | Switch | ON if connected to a slow charging port | +| `aux_battery_voltage` | Number | Voltage of the aux battery | +| `dc_battery_voltage` | Number | Voltage of the DC battery | +| `dc_battery_current` | Number | Current of the DC battery | +| `dc_battery_power` | Number | Power of the DC battery | +| `cumulative_energy_charged` | Number | Amount of energy that has been charged | +| `cumulative_energy_discharged` | Number | Amount of energy that has been discharged | +| `battery_min_temperature` | Number | The minimum temperature of the battery | +| `battery_max_temperature` | Number | The maximum temperature of the battery | +| `battery_inlet_temperature` | Number | The inlet temperature of the battery | +| `external_temperature` | Number | External temperature | +| `last_extended` | String | Timestamp of the latest export | | ## Full Example -_Provide a full usage example based on textual configuration files (*.things, *.items, *.sitemap)._ +### evnotify.things -## Any custom content here! +```properties +# Thing evnotify:vehicle:YOUR_VEHICLE_ID "YOUR_VEHICLE_LABEL" @ "YOUR_VEHICLE_LOCATION" [akey="YOUR_AKEY",token="YOUR_TOKEN",refreshInterval=120] +Thing evnotify:vehicle:ioniq "Ioniq" @ "Carport" [akey="YOUR_AKEY",token="YOUR_TOKEN",refreshInterval=120] +``` -_Feel free to add additional sections for whatever you think should also be mentioned about your binding!_ +### evnotify.items + +```properties +// Equipment representing thing: +// evnotify:vehicle:ioniq +// (Ioniq) + +Group Ioniq "Ioniq" ["Car"] + +// Points: + +Number Ioniq_StateofChargeDisplay "State of Charge (Display)" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:soc_display" } +Number Ioniq_StateofChargeBMS "State of Charge (BMS)" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:soc_bms" } +String Ioniq_Lateststateofcharge "Latest state of charge" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:last_soc" } +Number Ioniq_StateofHealth "State of Health" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:soh" } +Switch Ioniq_Charging "Charging" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:charging" } +Switch Ioniq_RapidChargingPort "Rapid Charging Port" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:rapid_charge_port" } +Switch Ioniq_NormalChargingPort "Normal Charging Port" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:normal_charge_port" } +Switch Ioniq_SlowChargingPort "Slow Charging Port" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:slow_charge_port" } +Number:ElectricPotential Ioniq_AUXBatteryVoltage "AUX Battery Voltage" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:aux_battery_voltage" } +Number:ElectricPotential Ioniq_DCBatteryVoltage "DC Battery Voltage" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:dc_battery_voltage" } +Number:ElectricCurrent Ioniq_DCBatteryCurrent "DC Battery Current" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:dc_battery_current" } +Number:Power Ioniq_DCBatteryPower "DC Battery Power" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:dc_battery_power" } +Number:Energy Ioniq_CumulativeEnergyCharged "Cumulative Energy Charged" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:cumulative_energy_charged" } +Number:Energy Ioniq_CumulativeEnergyDischarged "Cumulative Energy Discharged" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:cumulative_energy_discharged" } +Number:Temperature Ioniq_BatteryMinTemperature "Battery Min Temperature" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:battery_min_temperature" } +Number:Temperature Ioniq_BatteryMaxTemperature "Battery Max Temperature" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:battery_max_temperature" } +Number:Temperature Ioniq_BatteryInletTemperature "Battery Inlet Temperature" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:battery_inlet_temperature" } +Number:Temperature Ioniq_ExternalTemperature "External Temperature" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:external_temperature" } +String Ioniq_Latestexport "Latest export" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:last_extended" } +``` From 014dd0593d4d0a4917834ca361dd9232675fe3dc Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 07:11:48 +0100 Subject: [PATCH 050/361] test: reformat tests for validation Signed-off-by: Michael Schmidt --- .../api/v2/EVNotifyClientImplTest.java | 32 +++++-------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java index dad561cad0a0e..acb8ccdd052e0 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -144,10 +144,8 @@ void shouldThrowApiExceptionForNullBasicResponse() throws IOException, Interrupt EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -160,10 +158,8 @@ void shouldThrowApiExceptionForNullExtendedResponse() throws IOException, Interr EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -177,10 +173,8 @@ void shouldThrowApiExceptionForInvalidBasicResponseStatus() throws IOException, EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -194,10 +188,8 @@ void shouldThrowApiExceptionForInvalidExtendedResponseStatus() throws IOExceptio EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -211,10 +203,8 @@ void shouldThrowApiExceptionForNullBasicResponseBody() throws IOException, Inter EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -228,10 +218,8 @@ void shouldThrowApiExceptionForNullExtendedResponseBody() throws IOException, In EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -245,10 +233,8 @@ void shouldThrowApiExceptionForInvalidBasicResponseBody() throws IOException, In EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } @Test @@ -262,10 +248,8 @@ void shouldThrowApiExceptionForInvalidExtendedResponseBody() throws IOException, EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); - // when + // when then assertThrows(ApiException.class, evNotifyClient::getCarChargingData); - - // then } private HttpResponse getResponse(Integer statusCode, String body) { From 9c3237d4a2d84ff20cbce5317ca861cc32f882fd Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 07:13:12 +0100 Subject: [PATCH 051/361] test: add ChargingDataDTO validation tests Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/ChargingDataDTOTest.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java new file mode 100644 index 0000000000000..16e8bc422a36b --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.openhab.binding.evnotify.api.ChargingData; + +import com.google.gson.Gson; + +/** + * Test cases for the {@link ChargingDataDTO} class + * + * @author Michael Schmidt - Initial contribution + */ +class ChargingDataDTOTest { + + @Test + void shouldCreateChargingDataForValidData() { + // given + BasicChargingDataDTO basicChargingDataDTO = getValidBasicChargingDataDTO(); + ExtendedChargingDataDTO extendedChargingDataDTO = getValidExtendedChargingDataDTO(); + + // when + ChargingData chargingData = new ChargingDataDTO(basicChargingDataDTO, extendedChargingDataDTO); + + // then + assertEquals(Float.valueOf(93.0f), chargingData.getStateOfChargeDisplay()); + assertEquals(Float.valueOf(88.5f), chargingData.getStateOfChargeBms()); + assertEquals(1631220014L, chargingData.getLastStateOfCharge().toInstant().toEpochMilli()); + assertTrue(chargingData.isCharging()); + assertFalse(chargingData.isRapidChargePort()); + assertTrue(chargingData.isNormalChargePort()); + assertFalse(chargingData.isSlowChargePort()); + assertEquals(Float.valueOf(100.0f), chargingData.getStateOfHealth()); + assertEquals(Float.valueOf(14.5f), chargingData.getAuxBatteryVoltage()); + assertEquals(Float.valueOf(362.1f), chargingData.getDcBatteryVoltage()); + assertEquals(Float.valueOf(-8.7f), chargingData.getDcBatteryCurrent()); + assertEquals(Float.valueOf(-3.15027f), chargingData.getDcBatteryPower()); + assertEquals(Float.valueOf(3881.5f), chargingData.getCumulativeEnergyCharged()); + assertEquals(Float.valueOf(3738.8f), chargingData.getCumulativeEnergyDischarged()); + assertEquals(Float.valueOf(25f), chargingData.getBatteryMinTemperature()); + assertEquals(Float.valueOf(26f), chargingData.getBatteryMaxTemperature()); + assertEquals(Float.valueOf(24f), chargingData.getBatteryInletTemperature()); + assertNull(chargingData.getExternalTemperature()); + assertEquals(1631220014L, chargingData.getLastExtended().toInstant().toEpochMilli()); + } + + private BasicChargingDataDTO getValidBasicChargingDataDTO() { + String validChargingDataJson = "{\"soc_display\": 93,\"soc_bms\": 88.5,\"last_soc\": 1631220014}"; + return new Gson().fromJson(validChargingDataJson, BasicChargingDataDTO.class); + } + + private ExtendedChargingDataDTO getValidExtendedChargingDataDTO() { + String validChargingDataJson = "{\"soh\": 100,\"charging\": 1,\"rapid_charge_port\": 0,\"normal_charge_port\": 1," + + "\"slow_charge_port\": null,\"aux_battery_voltage\": 14.5,\"dc_battery_voltage\": 362.1," + + "\"dc_battery_current\": -8.7,\"dc_battery_power\": -3.15027," + + "\"cumulative_energy_charged\": 3881.5,\"cumulative_energy_discharged\": 3738.8," + + "\"battery_min_temperature\": 25,\"battery_max_temperature\": 26," + + "\"battery_inlet_temperature\": 24,\"external_temperature\": null,\"odo\": null," + + "\"last_extended\": 1631220014}"; + return new Gson().fromJson(validChargingDataJson, ExtendedChargingDataDTO.class); + } + + @Test + void shouldThrowExceptionForNullData() { + // when + assertThrows(IllegalArgumentException.class, () -> new ChargingDataDTO(null, null)); + } +} From 414e4798ac44553b6fe8ae2b6aba1797f4aad811 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 07:13:45 +0100 Subject: [PATCH 052/361] feat: add basic validation Signed-off-by: Michael Schmidt --- .../org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java index 1089a780564cb..a61195d386bf8 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTO.java @@ -28,6 +28,11 @@ public class ChargingDataDTO implements ChargingData { private final ExtendedChargingDataDTO extendedChargingDataDTO; public ChargingDataDTO(BasicChargingDataDTO basicChargingDataDTO, ExtendedChargingDataDTO extendedChargingDataDTO) { + + if (basicChargingDataDTO == null || extendedChargingDataDTO == null) { + throw new IllegalArgumentException("Given charging data must not be null"); + } + this.basicChargingDataDTO = basicChargingDataDTO; this.extendedChargingDataDTO = extendedChargingDataDTO; } From e59517ef08720a3482c128bca7917b6b53082650 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 23:03:01 +0100 Subject: [PATCH 053/361] fix: time problem Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/BasicChargingDataDTO.java | 2 +- .../api/v2/ExtendedChargingDataDTO.java | 2 +- .../evnotify/api/v2/ChargingDataDTOTest.java | 4 +- .../api/v2/EVNotifyClientImplTest.java | 41 +++++++++++++------ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java index 1804d33fbcae0..1ab8645eacbb9 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/BasicChargingDataDTO.java @@ -52,6 +52,6 @@ public Float getStateOfChargeBms() { public OffsetDateTime getLastStateOfCharge() { return lastStateOfCharge == null ? null - : OffsetDateTime.from(Instant.ofEpochMilli(lastStateOfCharge).atZone(ZoneId.of("Europe/Berlin"))); + : OffsetDateTime.from(Instant.ofEpochSecond(lastStateOfCharge).atZone(ZoneId.of("Europe/Berlin"))); } } diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java index 775aabeb44a21..2d2a842867d25 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ExtendedChargingDataDTO.java @@ -121,7 +121,7 @@ public Float getExternalTemperature() { public OffsetDateTime getLastExtended() { return lastExtended == null ? null - : OffsetDateTime.from(Instant.ofEpochMilli(lastExtended).atZone(ZoneId.of("Europe/Berlin"))); + : OffsetDateTime.from(Instant.ofEpochSecond(lastExtended).atZone(ZoneId.of("Europe/Berlin"))); } public Float getAuxBatteryVoltage() { diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java index 16e8bc422a36b..1c0f8a2d6c156 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/ChargingDataDTOTest.java @@ -38,7 +38,7 @@ void shouldCreateChargingDataForValidData() { // then assertEquals(Float.valueOf(93.0f), chargingData.getStateOfChargeDisplay()); assertEquals(Float.valueOf(88.5f), chargingData.getStateOfChargeBms()); - assertEquals(1631220014L, chargingData.getLastStateOfCharge().toInstant().toEpochMilli()); + assertEquals(1631220014L, chargingData.getLastStateOfCharge().toEpochSecond()); assertTrue(chargingData.isCharging()); assertFalse(chargingData.isRapidChargePort()); assertTrue(chargingData.isNormalChargePort()); @@ -54,7 +54,7 @@ void shouldCreateChargingDataForValidData() { assertEquals(Float.valueOf(26f), chargingData.getBatteryMaxTemperature()); assertEquals(Float.valueOf(24f), chargingData.getBatteryInletTemperature()); assertNull(chargingData.getExternalTemperature()); - assertEquals(1631220014L, chargingData.getLastExtended().toInstant().toEpochMilli()); + assertEquals(1631220014L, chargingData.getLastExtended().toEpochSecond()); } private BasicChargingDataDTO getValidBasicChargingDataDTO() { diff --git a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java index acb8ccdd052e0..57dda55efbfdd 100644 --- a/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java +++ b/bundles/org.openhab.binding.evnotify/src/test/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImplTest.java @@ -79,7 +79,7 @@ void shouldGiveAValidChargingDataForValidResponse() throws IOException, Interrup // then assertEquals(Float.valueOf(93.0f), chargingData.getStateOfChargeDisplay()); assertEquals(Float.valueOf(88.5f), chargingData.getStateOfChargeBms()); - assertEquals(1631220014L, chargingData.getLastStateOfCharge().toInstant().toEpochMilli()); + assertEquals(1631220014L, chargingData.getLastStateOfCharge().toEpochSecond()); assertTrue(chargingData.isCharging()); assertFalse(chargingData.isRapidChargePort()); assertTrue(chargingData.isNormalChargePort()); @@ -95,7 +95,7 @@ void shouldGiveAValidChargingDataForValidResponse() throws IOException, Interrup assertEquals(Float.valueOf(26f), chargingData.getBatteryMaxTemperature()); assertEquals(Float.valueOf(24f), chargingData.getBatteryInletTemperature()); assertNull(chargingData.getExternalTemperature()); - assertEquals(1631220014L, chargingData.getLastExtended().toInstant().toEpochMilli()); + assertEquals(1631220014L, chargingData.getLastExtended().toEpochSecond()); } @Test @@ -145,7 +145,8 @@ void shouldThrowApiExceptionForNullBasicResponse() throws IOException, Interrupt EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Response was null", exception.getMessage()); } @Test @@ -159,13 +160,14 @@ void shouldThrowApiExceptionForNullExtendedResponse() throws IOException, Interr EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Response was null", exception.getMessage()); } @Test void shouldThrowApiExceptionForInvalidBasicResponseStatus() throws IOException, InterruptedException { // given - HttpResponse basicResponse = getResponse(400, getValidBasicResponseBody()); + HttpResponse basicResponse = getResponse(401, getErrorResponseBody()); mockResponse(basicUriMatcher, basicResponse); HttpResponse extendedResponse = getResponse(200, getValidExtendedResponseBody()); @@ -174,7 +176,10 @@ void shouldThrowApiExceptionForInvalidBasicResponseStatus() throws IOException, EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals( + "Request failed with status 401 with error code 1900 and message 'Provided token is invalid or no longer valid.'", + exception.getMessage()); } @Test @@ -183,13 +188,16 @@ void shouldThrowApiExceptionForInvalidExtendedResponseStatus() throws IOExceptio HttpResponse basicResponse = getResponse(200, getValidBasicResponseBody()); mockResponse(basicUriMatcher, basicResponse); - HttpResponse extendedResponse = getResponse(400, getValidExtendedResponseBody()); + HttpResponse extendedResponse = getResponse(401, getErrorResponseBody()); mockResponse(extendedUriMatcher, extendedResponse); EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals( + "Request failed with status 401 with error code 1900 and message 'Provided token is invalid or no longer valid.'", + exception.getMessage()); } @Test @@ -204,7 +212,8 @@ void shouldThrowApiExceptionForNullBasicResponseBody() throws IOException, Inter EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Request failed with null response body", exception.getMessage()); } @Test @@ -219,7 +228,8 @@ void shouldThrowApiExceptionForNullExtendedResponseBody() throws IOException, In EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Request failed with null response body", exception.getMessage()); } @Test @@ -234,7 +244,8 @@ void shouldThrowApiExceptionForInvalidBasicResponseBody() throws IOException, In EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Request failed with invalid response body", exception.getMessage()); } @Test @@ -249,7 +260,8 @@ void shouldThrowApiExceptionForInvalidExtendedResponseBody() throws IOException, EVNotifyClient evNotifyClient = new EVNotifyClientImpl("aKey", "token", httpClient); // when then - assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + ApiException exception = assertThrows(ApiException.class, evNotifyClient::getCarChargingData); + assertEquals("Request failed with invalid response body", exception.getMessage()); } private HttpResponse getResponse(Integer statusCode, String body) { @@ -300,6 +312,10 @@ private String getValidBasicResponseBody() { return "{\"soc_display\": 93,\"soc_bms\": 88.5,\"last_soc\": 1631220014}"; } + private String getErrorResponseBody() { + return "{\"error\":{\"code\":1900,\"message\":\"Provided token is invalid or no longer valid.\"}}"; + } + private String getEmptyResponseBody() { return "{}"; } @@ -318,6 +334,7 @@ private String getValidExtendedResponseBody() { + "\"last_extended\": 1631220014}"; } + @SuppressWarnings("unchecked") private void mockResponse(HttpRequestUriMatcher httpRequestUriMatcher, HttpResponse response) throws IOException, InterruptedException { when(httpClient.send(argThat(httpRequestUriMatcher), any(HttpResponse.BodyHandler.class))).thenReturn(response); From d6d267b35548d5e6aec076cd7037226ab00f03ff Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 23:03:40 +0100 Subject: [PATCH 054/361] refactor: remove unused logger Signed-off-by: Michael Schmidt --- .../binding/evnotify/internal/EVNotifyHandlerFactory.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java index 2decf6db8442b..6c7318c5b5aff 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandlerFactory.java @@ -24,8 +24,6 @@ import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The {@link EVNotifyHandlerFactory} is responsible for creating things and thing @@ -37,8 +35,6 @@ @Component(configurationPid = "binding.evnotify", service = ThingHandlerFactory.class) public class EVNotifyHandlerFactory extends BaseThingHandlerFactory { - private final Logger logger = LoggerFactory.getLogger(EVNotifyHandlerFactory.class); - @Activate public EVNotifyHandlerFactory() { } From 9636b50d745a3ae0cbf1435e4cc374782b76795b Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 23:04:10 +0100 Subject: [PATCH 055/361] feat: add ErrorDTO for error parsing Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/v2/ErrorDTO.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ErrorDTO.java diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ErrorDTO.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ErrorDTO.java new file mode 100644 index 0000000000000..8e089e4402610 --- /dev/null +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/ErrorDTO.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.evnotify.api.v2; + +import com.google.gson.annotations.SerializedName; + +/** + * Represents the error data that is returned by evnotify v2 API. + * + * e.g. + * + * {"error":{"code":1900,"message":"Provided token is invalid or no longer valid."}} + * + * @author Michael Schmidt - Initial contribution + */ +public class ErrorDTO { + + @SerializedName("error") + public Error error; + + public Integer getCode() { + return error.code; + } + + public String getMessage() { + return error.message; + } + + private class Error { + + @SerializedName("code") + public Integer code; + + @SerializedName("message") + public String message; + } +} From 456ea84feb904698c8bdf0e3efdc75bb285ffaa2 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 23:04:52 +0100 Subject: [PATCH 056/361] feat: use ErrorDTO for error parsing Signed-off-by: Michael Schmidt --- .../evnotify/api/v2/EVNotifyClientImpl.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index c39133dbcc3f6..9e163dddab780 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -76,8 +76,6 @@ public ChargingData getCarChargingData() throws IOException, InterruptedExceptio return new ChargingDataDTO(basicChargingDataDTO, extendedChargingData); } catch (JsonSyntaxException e) { throw new ApiException("Request failed with invalid response body", e); - } catch (Exception e) { - throw e; } } @@ -85,14 +83,31 @@ private void validateResponse(HttpResponse httpResponse) throws ApiExcep if (httpResponse != null) { if (httpResponse.statusCode() >= 400) { - throw new ApiException(String.format("Request failed with status %d", httpResponse.statusCode())); + throw new ApiException(getErrorMessage(httpResponse)); } if (httpResponse.body() == null) { throw new ApiException("Request failed with null response body"); } + } else { - throw new ApiException("Response was null."); + throw new ApiException("Response was null"); + } + } + + private String getErrorMessage(HttpResponse httpResponse) { + String errorMessage = String.format("Request failed with status %d", httpResponse.statusCode()); + + if (httpResponse.body() != null) { + try { + ErrorDTO errorDTO = new Gson().fromJson(httpResponse.body(), ErrorDTO.class); + + errorMessage += String.format(" with error code %d and message '%s'", errorDTO.getCode(), + errorDTO.getMessage()); + + } catch (Exception ignored) { + } } + return errorMessage; } } From ba594276ee4a8e95746805f710a2af8ecc45e5bb Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 4 Nov 2021 23:42:26 +0100 Subject: [PATCH 057/361] fix: configuration parameter Signed-off-by: Michael Schmidt --- .../binding/evnotify/api/v2/EVNotifyClientImpl.java | 10 +++++----- .../evnotify/internal/EVNotifyConfiguration.java | 2 +- .../binding/evnotify/internal/EVNotifyHandler.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index 9e163dddab780..0af29d483a005 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -41,12 +41,12 @@ public class EVNotifyClientImpl implements EVNotifyClient { private final Logger logger = LoggerFactory.getLogger(EVNotifyClientImpl.class); private final HttpClient client; - private final String aKey; + private final String akey; private final String token; - public EVNotifyClientImpl(String aKey, String token, HttpClient client) { - this.aKey = aKey; + public EVNotifyClientImpl(String akey, String token, HttpClient client) { + this.akey = akey; this.token = token; this.client = client; } @@ -55,10 +55,10 @@ public EVNotifyClientImpl(String aKey, String token, HttpClient client) { public ChargingData getCarChargingData() throws IOException, InterruptedException, ApiException { // create the requests - var basicRequest = HttpRequest.newBuilder(URI.create(String.format(BASIC_API_URL_PATTERN, aKey, token))) + var basicRequest = HttpRequest.newBuilder(URI.create(String.format(BASIC_API_URL_PATTERN, akey, token))) .header("accept", "application/json").build(); - var extendedRequest = HttpRequest.newBuilder(URI.create(String.format(EXTENDED_API_URL_PATTERN, aKey, token))) + var extendedRequest = HttpRequest.newBuilder(URI.create(String.format(EXTENDED_API_URL_PATTERN, akey, token))) .header("accept", "application/json").build(); try { diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java index 2cf2d320e2e38..0557ba4c278fa 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java @@ -24,7 +24,7 @@ public class EVNotifyConfiguration { /** * AKey */ - public @Nullable String aKey; + public @Nullable String akey; /** * Token diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java index 3959abfc5eee5..9993bf6c9e70f 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -100,7 +100,7 @@ public void initialize() { ApiVersion apiVersion = ApiVersion.getApiVersion(config.version); switch (apiVersion) { case V2: - client = new EVNotifyClientImpl(config.aKey, config.token, HttpClient.newHttpClient()); + client = new EVNotifyClientImpl(config.akey, config.token, HttpClient.newHttpClient()); case V3: updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.format("'%s' not implemented yet.", apiVersion.name())); From b4334004593b2f743f21b981decf600116391e5b Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Fri, 5 Nov 2021 16:58:56 +0100 Subject: [PATCH 058/361] fix: type id Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml index 9326f661dd908..5a552bcfba77d 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.evnotify/src/main/resources/OH-INF/thing/thing-types.xml @@ -154,7 +154,7 @@ The inlet temperature of the battery - + Number:Temperature External temperature From e138561d6fe4aff1650b084fdd36531368f12baf Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Fri, 5 Nov 2021 16:59:38 +0100 Subject: [PATCH 059/361] docs: extend README by images Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.evnotify/README.md | 4 ++++ .../doc/img/Model.png | Bin 0 -> 111707 bytes .../doc/img/Things.png | Bin 0 -> 57760 bytes 3 files changed, 4 insertions(+) create mode 100644 bundles/org.openhab.binding.evnotify/doc/img/Model.png create mode 100644 bundles/org.openhab.binding.evnotify/doc/img/Things.png diff --git a/bundles/org.openhab.binding.evnotify/README.md b/bundles/org.openhab.binding.evnotify/README.md index ba6388b5fb9f2..ec0dc78765123 100644 --- a/bundles/org.openhab.binding.evnotify/README.md +++ b/bundles/org.openhab.binding.evnotify/README.md @@ -65,6 +65,8 @@ The binding has no configuration options, all configuration is done at `vehicle` Thing evnotify:vehicle:ioniq "Ioniq" @ "Carport" [akey="YOUR_AKEY",token="YOUR_TOKEN",refreshInterval=120] ``` +![EV Notify Vehicle Things Example](doc/img/Things.png) + ### evnotify.items ```properties @@ -96,3 +98,5 @@ Number:Temperature Ioniq_BatteryInletTemperature "Battery Inlet Tempera Number:Temperature Ioniq_ExternalTemperature "External Temperature" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:external_temperature" } String Ioniq_Latestexport "Latest export" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:last_extended" } ``` + +![EV Notify Vehicle Model Example](doc/img/Model.png) \ No newline at end of file diff --git a/bundles/org.openhab.binding.evnotify/doc/img/Model.png b/bundles/org.openhab.binding.evnotify/doc/img/Model.png new file mode 100644 index 0000000000000000000000000000000000000000..7b146bb2fd27b9faf59e7d2538f6e02af8a8dc79 GIT binary patch literal 111707 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 QaM&M0M)7|BJ>zHp2G8-`qW}N^ literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.binding.evnotify/doc/img/Things.png b/bundles/org.openhab.binding.evnotify/doc/img/Things.png new file mode 100644 index 0000000000000000000000000000000000000000..a0ce53c06f3d669cf42c5ac2e0a0697782cd88f5 GIT binary patch literal 57760 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 Date: Sat, 6 Nov 2021 15:56:49 +0100 Subject: [PATCH 060/361] fix: add NonNullByDefault Signed-off-by: Michael Schmidt --- .../binding/evnotify/internal/EVNotifyConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java index 0557ba4c278fa..d7d42b2f55d05 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyConfiguration.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.evnotify.internal; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; /** @@ -19,6 +20,7 @@ * * @author Michael Schmidt - Initial contribution */ +@NonNullByDefault public class EVNotifyConfiguration { /** From 1515137817f75a58ca8692dbb772593469a0b179 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 6 Nov 2021 15:57:28 +0100 Subject: [PATCH 061/361] fix: docu Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.evnotify/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.evnotify/README.md b/bundles/org.openhab.binding.evnotify/README.md index ec0dc78765123..1814294028fcb 100644 --- a/bundles/org.openhab.binding.evnotify/README.md +++ b/bundles/org.openhab.binding.evnotify/README.md @@ -99,4 +99,4 @@ Number:Temperature Ioniq_ExternalTemperature "External Temperature" String Ioniq_Latestexport "Latest export" (Ioniq) ["Point"] { channel="evnotify:vehicle:ioniq:last_extended" } ``` -![EV Notify Vehicle Model Example](doc/img/Model.png) \ No newline at end of file +![EV Notify Vehicle Model Example](doc/img/Model.png) From e0852d823ff8e24f722d0f645a9819bcf339e0c8 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 6 Nov 2021 16:08:45 +0100 Subject: [PATCH 062/361] fix: add NonNullByDefault Signed-off-by: Michael Schmidt --- .../java/org/openhab/binding/evnotify/api/ApiVersion.java | 6 +++++- .../openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java index 112a4cc46f32f..08314b19f34ce 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/ApiVersion.java @@ -12,17 +12,21 @@ */ package org.openhab.binding.evnotify.api; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + /** * Represents version for the API of the evnotify online service. * * @author Michael Schmidt - Initial contribution */ +@NonNullByDefault public enum ApiVersion { V2, V3; - public static ApiVersion getApiVersion(String searchVersion) { + public static ApiVersion getApiVersion(@Nullable String searchVersion) { for (ApiVersion version : ApiVersion.values()) { if (version.name().equals(searchVersion)) { diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index 0af29d483a005..0f4895a7452b3 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -38,7 +38,6 @@ public class EVNotifyClientImpl implements EVNotifyClient { public static String BASIC_API_URL_PATTERN = "https://app.evnotify.de/soc?akey=%s&token=%s"; public static String EXTENDED_API_URL_PATTERN = "https://app.evnotify.de/extended?akey=%s&token=%s"; - private final Logger logger = LoggerFactory.getLogger(EVNotifyClientImpl.class); private final HttpClient client; private final String akey; From a5cd5303ebcfe3811a78517ea86d5e080e570557 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 6 Nov 2021 20:57:39 +0100 Subject: [PATCH 063/361] feat: add dependency and codeownership Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index a74a451fe9807..34492b66ba1a9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -84,6 +84,7 @@ /bundles/org.openhab.binding.enturno/ @klocsson /bundles/org.openhab.binding.epsonprojector/ @mlobstein /bundles/org.openhab.binding.etherrain/ @dfad1469 +/bundles/org.openhab.binding.evnotify/ @mischmidt83 /bundles/org.openhab.binding.evohome/ @Nebula83 /bundles/org.openhab.binding.exec/ @kgoderis /bundles/org.openhab.binding.feed/ @svilenvul diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 67288274817e9..d3c3e1f7c37aa 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -406,6 +406,11 @@ org.openhab.binding.etherrain ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.evnotify + ${project.version} + org.openhab.addons.bundles org.openhab.binding.evohome From 59cc002b622bccd6a44cfff50d569ffb0f3cd48e Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 6 Nov 2021 22:36:10 +0100 Subject: [PATCH 064/361] fix: optimize imports Signed-off-by: Michael Schmidt --- .../org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java index 0f4895a7452b3..7ebfe345c2a22 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/api/v2/EVNotifyClientImpl.java @@ -21,8 +21,6 @@ import org.openhab.binding.evnotify.api.ApiException; import org.openhab.binding.evnotify.api.ChargingData; import org.openhab.binding.evnotify.api.EVNotifyClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; From 35476ff7660b9c7b4d8ea847ed4f1d177046984a Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 6 Nov 2021 23:06:55 +0100 Subject: [PATCH 065/361] fix: add module Signed-off-by: Michael Schmidt --- bundles/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/bundles/pom.xml b/bundles/pom.xml index 345fc9daecd35..30eb76eac554a 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -116,6 +116,7 @@ org.openhab.binding.enturno org.openhab.binding.epsonprojector org.openhab.binding.etherrain + org.openhab.binding.evnotify org.openhab.binding.evohome org.openhab.binding.exec org.openhab.binding.feed From d4c83f23c8c0d66eabbb56765c88f91b8981727e Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Sun, 7 Nov 2021 08:46:15 +0100 Subject: [PATCH 066/361] New Crowdin updates (#11536) * New translations mail.properties (French) * New translations twitter.properties (French) Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/mail_fr.properties | 62 +++++++++++++++---- .../OH-INF/i18n/twitter_fr.properties | 29 ++++++++- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties index 7cb38bf442794..60032404647ec 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties @@ -1,21 +1,61 @@ +# binding + +binding.mail.name = Extension Mail +binding.mail.description = Cette extension est utilisée pour accéder aux serveurs POP3, IMAP et SMTP. + +# thing types + +thing-type.mail.imap.label = Serveur IMAP +thing-type.mail.imap.description = Utilisé pour recevoir des e-mails +thing-type.mail.pop3.label = Serveur POP3 +thing-type.mail.pop3.description = Utilisé pour recevoir des e-mails +thing-type.mail.smtp.label = Serveur SMTP +thing-type.mail.smtp.description = Utilisé pour envoyer des e-mails via des actions dans les règles + +# thing types config + +thing-type.config.mail.imap.port.description = Les valeurs par défaut sont 143 pour plain/STARTTLS et 993 pour SSL/TLS +thing-type.config.mail.pop3.port.description = Les valeurs par défaut sont 110 pour plain/STARTTLS et 995 pour SSL/TLS +thing-type.config.mail.smtp.port.description = Les valeurs par défaut sont 25 pour plain/STARTTLS et 465 pour SSL/TLS +thing-type.config.mail.smtp.sender.label = Expéditeur +thing-type.config.mail.smtp.sender.description = Adresse par défaut de l'expéditeur de l'e-mail + +config.hostname.label = Nom d'hôte du serveur +config.password.label = Mot de passe du serveur SMTP +config.port.label = Port du serveur +config.refresh.label = Fréquence de rafraîchissement +config.refresh.description = Fréquence de rafraîchissement de ce compte en secondes +config.security.label = Protocole de sécurité du serveur SMTP +config.security.option.PLAIN = Aucun +config.security.option.STARTTLS = STARTTLS +config.security.option.SSL = SSL/TLS +config.username.label = Nom d'utilisateur du serveur SMTP + +# channel types + +channel-type.mail.mailcount.label = Nombre d'e-mails +channel-type.mail.mailcount.description = Nombre d'e-mails dans le dossier + +# channel types config + +channel-type.config.mail.mailcount.folder.label = Nom de dossier +channel-type.config.mail.mailcount.type.label = Type de compteur +channel-type.config.mail.mailcount.type.option.UNREAD = Non lus +channel-type.config.mail.mailcount.type.option.TOTAL = Tous + # actions -sendMessageActionLabel = envoyer un mail texte -sendMessageActionDescription = Envoie un mail texte. +addHeaderActionLabel = ajouter un en-tête au mail +addHeaderActionDescription = Ajoute un en-tête au mail. sendAttachmentMessageActionLabel = envoyer un mail texte avec pièce jointe sendAttachmentMessageActionDescription = Envoie un message texte avec pièce jointe. - sendAttachmentsMessageActionLabel = envoie un mail texte avec plusieurs pièces jointes sendAttachmentsMessageActionDescription = Envoie un mail texte avec plusieurs pièces jointes. - -sendHTMLMessageActionLabel = envoyer un mail HTML -sendHTMLMessageActionDescription = Envoie un mail HTML. - sendHTMLAttachmentMessageActionLabel = envoyer un mail HTML avec pièce jointe sendHTMLAttachmentMessageActionDescription = Envoie un mail HTML avec une pièce jointe. - sendHTMLAttachmentsMessageActionLabel = envoyer un mail HTML avec plusieurs pièces jointes sendHTMLAttachmentsMessageActionDescription = Envoie un mail HTML avec plusieurs pièces jointes. - -addHeaderActionLabel = ajouter un en-tête au mail -addHeaderActionDescription = Ajoute un en-tête au mail. +sendHTMLMessageActionLabel = envoyer un mail HTML +sendHTMLMessageActionDescription = Envoie un mail HTML. +sendMessageActionLabel = envoyer un mail texte +sendMessageActionDescription = Envoie un mail texte. diff --git a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties index 0c4ed5b7f0212..1762ec4887ff5 100644 --- a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties +++ b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties @@ -1,9 +1,32 @@ +# binding + +binding.twitter.name = Extension Twitter +binding.twitter.description = Permet d'obtenir le dernier Tweet ou d'envoyer des Tweets et des images depuis vos règles d'automatisation. + +# thing types + +thing-type.twitter.account.label = Compte Twitter +thing-type.twitter.account.description = Compte pour envoyer des Tweets + +# thing types config + +thing-type.config.twitter.account.accessToken.label = Jeton d'authentification +thing-type.config.twitter.account.accessTokenSecret.label = Code secret du jeton d'authentification +thing-type.config.twitter.account.consumerKey.label = Clé d'accès à l'API +thing-type.config.twitter.account.consumerSecret.label = Code secret pour l'accès à l'API +thing-type.config.twitter.account.refresh.label = Fréquence de rafraîchissement +thing-type.config.twitter.account.refresh.description = Fréquence de rafraîchissement de ce compte en minutes + +# channel types + +channel-type.twitter.lasttweet.label = Dernier Tweet +channel-type.twitter.lasttweet.description = Dernier Tweet des utilisateurs + # actions -sendTweetActionLabel = envoyer un Tweet -sendTweetActionDescription = Envoie un Tweet. sendAttachmentTweetActionLabel = envoyer un Tweet avec pièce jointe sendAttachmentTweetActionDescription = Envoie un Tweet avec pièce jointe. - sendDirectMessageActionLabel = envoyer un message privé sendDirectMessageActionDescription = Envoie un message privé. +sendTweetActionLabel = envoyer un Tweet +sendTweetActionDescription = Envoie un Tweet. From bba343762dd6a0f627f4d2ec3e2c7fd8985a2987 Mon Sep 17 00:00:00 2001 From: Stefan Triller Date: Sun, 7 Nov 2021 15:57:41 +0100 Subject: [PATCH 067/361] [mqtt.homeassistant] Implement Vacuum discovery for Homeassistant MQTT (#11216) * Implement Vacuum discovery for Homeassistant MQTT Closes #8988 Signed-off-by: Stefan Triller * Addressed review comments Signed-off-by: Stefan Triller * Spotless run again Signed-off-by: Stefan Triller Signed-off-by: Michael Schmidt --- .../internal/ComponentChannel.java | 12 +- .../internal/component/ComponentFactory.java | 2 + .../internal/component/Vacuum.java | 264 ++++++++++++++++++ 3 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java index dc993efb80828..6865f95a180bb 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java @@ -129,6 +129,7 @@ public static class Builder { private @Nullable String commandTopic; private boolean retain; private boolean trigger; + private boolean isAdvanced; private @Nullable Integer qos; private @Nullable Predicate commandFilter; @@ -141,6 +142,7 @@ public Builder(AbstractComponent component, String channelID, Value valueStat this.channelID = channelID; this.valueState = valueState; this.label = label; + this.isAdvanced = false; this.channelStateUpdateListener = channelStateUpdateListener; } @@ -194,6 +196,11 @@ public Builder trigger(boolean trigger) { return this; } + public Builder isAdvanced(boolean advanced) { + this.isAdvanced = advanced; + return this; + } + public Builder commandFilter(@Nullable Predicate commandFilter) { this.commandFilter = commandFilter; return this; @@ -221,12 +228,13 @@ public ComponentChannel build(boolean addToComponent) { String localStateTopic = stateTopic; if (localStateTopic == null || localStateTopic.isBlank() || this.trigger) { type = ChannelTypeBuilder.trigger(channelTypeUID, label) - .withConfigDescriptionURI(URI.create(MqttBindingConstants.CONFIG_HA_CHANNEL)).build(); + .withConfigDescriptionURI(URI.create(MqttBindingConstants.CONFIG_HA_CHANNEL)) + .isAdvanced(isAdvanced).build(); } else { StateDescriptionFragment description = valueState.createStateDescription(commandTopic == null).build(); type = ChannelTypeBuilder.state(channelTypeUID, label, channelState.getItemType()) .withConfigDescriptionURI(URI.create(MqttBindingConstants.CONFIG_HA_CHANNEL)) - .withStateDescriptionFragment(description).build(); + .withStateDescriptionFragment(description).isAdvanced(isAdvanced).build(); } Configuration configuration = new Configuration(); diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java index 5be1b36e3bae1..1771a2d473f4a 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java @@ -77,6 +77,8 @@ public static AbstractComponent createComponent(ThingUID thingUID, HaID haID, return new Sensor(componentConfiguration); case "switch": return new Switch(componentConfiguration); + case "vacuum": + return new Vacuum(componentConfiguration); default: throw new UnsupportedComponentException("Component '" + haID + "' is unsupported!"); } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java new file mode 100644 index 0000000000000..f84abc36cd0a6 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mqtt.homeassistant.internal.component; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.mqtt.generic.values.DateTimeValue; +import org.openhab.binding.mqtt.generic.values.NumberValue; +import org.openhab.binding.mqtt.generic.values.TextValue; +import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration; + +/** + * A MQTT vacuum, following the https://www.home-assistant.io/components/vacuum.mqtt/ specification. + * + * @author Stefan Triller - Initial contribution + */ +@NonNullByDefault +public class Vacuum extends AbstractComponent { + public static final String VACUUM_STATE_CHANNEL_ID = "state"; + public static final String VACUUM_COMMAND_CHANNEL_ID = "command"; + public static final String VACUUM_BATTERY_CHANNEL_ID = "batteryLevel"; + public static final String VACUUM_FAN_SPEED_CHANNEL_ID = "fanSpeed"; + + // sensor stats + public static final String VACUUM_MAIN_BRUSH_CHANNEL_ID = "mainBrushUsage"; + public static final String VACUUM_SIDE_BRUSH_CHANNEL_ID = "sideBrushUsage"; + public static final String VACUUM_FILTER_CHANNEL_ID = "filter"; + public static final String VACUUM_SENSOR_CHANNEL_ID = "sensor"; + public static final String VACUUM_CURRENT_CLEAN_TIME_CHANNEL_ID = "currentCleanTime"; + public static final String VACUUM_CURRENT_CLEAN_AREA_CHANNEL_ID = "currentCleanArea"; + public static final String VACUUM_CLEAN_TIME_CHANNEL_ID = "cleanTime"; + public static final String VACUUM_CLEAN_AREA_CHANNEL_ID = "cleanArea"; + public static final String VACUUM_CLEAN_COUNT_CHANNEL_ID = "cleanCount"; + + public static final String VACUUM_LAST_RUN_START_CHANNEL_ID = "lastRunStart"; + public static final String VACUUM_LAST_RUN_END_CHANNEL_ID = "lastRunEnd"; + public static final String VACUUM_LAST_RUN_DURATION_CHANNEL_ID = "lastRunDuration"; + public static final String VACUUM_LAST_RUN_AREA_CHANNEL_ID = "lastRunArea"; + public static final String VACUUM_LAST_RUN_ERROR_CODE_CHANNEL_ID = "lastRunErrorCode"; + public static final String VACUUM_LAST_RUN_ERROR_DESCRIPTION_CHANNEL_ID = "lastRunErrorDescription"; + public static final String VACUUM_LAST_RUN_FINISHED_FLAG_CHANNEL_ID = "lastRunFinishedFlag"; + + public static final String VACUUM_BIN_IN_TIME_CHANNEL_ID = "binInTime"; + public static final String VACUUM_LAST_BIN_OUT_TIME_CHANNEL_ID = "lastBinOutTime"; + public static final String VACUUM_LAST_BIN_FULL_TIME_CHANNEL_ID = "lastBinFullTime"; + + public static final String VACUUM_CUSMTOM_COMMAND_CHANNEL_ID = "customCommand"; + + /** + * Configuration class for MQTT component + */ + static class ChannelConfiguration extends AbstractChannelConfiguration { + ChannelConfiguration() { + super("MQTT Vacuum"); + } + + protected @Nullable String commandTopic; + protected String stateTopic = ""; + protected @Nullable String sendCommandTopic; // for custom_command + + // [start, pause, stop, return_home, battery, status, locate, clean_spot, fan_speed, send_command] + protected String[] supportedFeatures = new String[] {}; + protected @Nullable String setFanSpeedTopic; + protected String[] fanSpeedList = new String[] {}; + + protected @Nullable String jsonAttributesTopic; + protected @Nullable String jsonAttributesTemplate; + } + + public Vacuum(ComponentFactory.ComponentConfiguration componentConfiguration) { + super(componentConfiguration, ChannelConfiguration.class); + + List features = Arrays.asList(channelConfiguration.supportedFeatures); + + // features = [start, pause, stop, return_home, status, locate, clean_spot, fan_speed, send_command] + ArrayList possibleCommands = new ArrayList(); + if (features.contains("start")) { + possibleCommands.add("start"); + } + + if (features.contains("stop")) { + possibleCommands.add("stop"); + } + + if (features.contains("pause")) { + possibleCommands.add("pause"); + } + + if (features.contains("return_home")) { + possibleCommands.add("return_to_base"); + } + + if (features.contains("locate")) { + possibleCommands.add("locate"); + } + + TextValue value = new TextValue(possibleCommands.toArray(new String[0])); + buildChannel(VACUUM_COMMAND_CHANNEL_ID, value, "Command", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.commandTopic).commandTopic(channelConfiguration.commandTopic, false, 1) + .build(); + + List vacuumStates = List.of("docked", "cleaning", "returning", "paused", "idle", "error"); + TextValue valueState = new TextValue(vacuumStates.toArray(new String[0])); + buildChannel(VACUUM_STATE_CHANNEL_ID, valueState, "State", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.stateTopic, "{{value_json.state}}").build(); + + if (features.contains("battery")) { + // build battery level channel (0-100) + NumberValue batValue = new NumberValue(BigDecimal.ZERO, new BigDecimal(100), new BigDecimal(1), "%"); + buildChannel(VACUUM_BATTERY_CHANNEL_ID, batValue, "Battery Level", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.stateTopic, "{{value_json.battery_level}}").build(); + } + + if (features.contains("fan_speed")) { + // build fan speed channel with values from channelConfiguration.fan_speed_list + TextValue fanValue = new TextValue(channelConfiguration.fanSpeedList); + buildChannel(VACUUM_FAN_SPEED_CHANNEL_ID, fanValue, "Fan speed", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.stateTopic, "{{value_json.fan_speed}}") + .commandTopic(channelConfiguration.setFanSpeedTopic, false, 1).build(); + } + + // {"mainBrush":"220.6","sideBrush":"120.6","filter":"70.6","sensor":"0.0","currentCleanTime":"0.0","currentCleanArea":"0.0","cleanTime":"79.3","cleanArea":"4439.9","cleanCount":183,"last_run_stats":{"startTime":1613503117000,"endTime":1613503136000,"duration":0,"area":"0.0","errorCode":0,"errorDescription":"No + // error","finishedFlag":false},"bin_in_time":1000,"last_bin_out":-1,"last_bin_full":-1,"last_loaded_map":null,"state":"docked","valetudo_state":{"id":8,"name":"Charging"}} + if (features.contains("status")) { + NumberValue currentCleanTimeValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_CURRENT_CLEAN_TIME_CHANNEL_ID, currentCleanTimeValue, "Current Cleaning Time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.currentCleanTime}}") + .build(); + + NumberValue currentCleanAreaValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_CURRENT_CLEAN_AREA_CHANNEL_ID, currentCleanAreaValue, "Current Cleaning Area", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.currentCleanArea}}") + .build(); + + NumberValue cleanTimeValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_CLEAN_TIME_CHANNEL_ID, cleanTimeValue, "Cleaning Time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanTime}}").build(); + + NumberValue cleanAreaValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_CLEAN_AREA_CHANNEL_ID, cleanAreaValue, "Cleaned Area", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanArea}}").build(); + + NumberValue cleaCountValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_CLEAN_COUNT_CHANNEL_ID, cleaCountValue, "Cleaning Counter", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanCount}}").build(); + + DateTimeValue lastStartTime = new DateTimeValue(); + buildChannel(VACUUM_LAST_RUN_START_CHANNEL_ID, lastStartTime, "Last run start time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.startTime}}") + .build(); + + DateTimeValue lastEndTime = new DateTimeValue(); + buildChannel(VACUUM_LAST_RUN_END_CHANNEL_ID, lastEndTime, "Last run end time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.endTime}}") + .build(); + + NumberValue lastRunDurationValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_LAST_RUN_DURATION_CHANNEL_ID, lastRunDurationValue, "Last run duration", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.duration}}") + .build(); + + NumberValue lastRunAreaValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_LAST_RUN_AREA_CHANNEL_ID, lastRunAreaValue, "Last run area", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_run_stats.area}}") + .build(); + + NumberValue lastRunErrorCodeValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_LAST_RUN_ERROR_CODE_CHANNEL_ID, lastRunErrorCodeValue, "Last run error code", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.errorCode}}") + .build(); + + TextValue lastRunErrorDescriptionValue = new TextValue(); + buildChannel(VACUUM_LAST_RUN_ERROR_DESCRIPTION_CHANNEL_ID, lastRunErrorDescriptionValue, + "Last run error description", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.errorDescription}}") + .build(); + + // true/false doesnt map to ON/OFF => use TextValue instead of OnOffValue + TextValue lastRunFinishedFlagValue = new TextValue(); + buildChannel(VACUUM_LAST_RUN_FINISHED_FLAG_CHANNEL_ID, lastRunFinishedFlagValue, "Last run finished flag", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, + "{{value_json.last_run_stats.finishedFlag}}") + .build(); + + // only for valetudo re => advanced channels + DateTimeValue binInValue = new DateTimeValue(); + buildChannel(VACUUM_BIN_IN_TIME_CHANNEL_ID, binInValue, "Bin In Time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.bin_in_time}}") + .isAdvanced(true).build(); + + DateTimeValue lastBinOutValue = new DateTimeValue(); + buildChannel(VACUUM_LAST_BIN_OUT_TIME_CHANNEL_ID, lastBinOutValue, "Last Bin Out Time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_bin_out}}") + .isAdvanced(true).build(); + + DateTimeValue lastBinFullValue = new DateTimeValue(); + buildChannel(VACUUM_LAST_BIN_FULL_TIME_CHANNEL_ID, lastBinFullValue, "Last Bin Full Time", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_bin_full}}") + .isAdvanced(true).build(); + } + + NumberValue mainBrush = new NumberValue(null, null, null, null); + buildChannel(VACUUM_MAIN_BRUSH_CHANNEL_ID, mainBrush, "Main brush usage", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.mainBrush}}").build(); + + NumberValue sideBrush = new NumberValue(null, null, null, null); + buildChannel(VACUUM_SIDE_BRUSH_CHANNEL_ID, sideBrush, "Side brush usage", + componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.sideBrush}}").build(); + + NumberValue filterValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_FILTER_CHANNEL_ID, filterValue, "Filter time", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.filter}}").build(); + + NumberValue sensorValue = new NumberValue(null, null, null, null); + buildChannel(VACUUM_SENSOR_CHANNEL_ID, sensorValue, "Sensor", componentConfiguration.getUpdateListener()) + .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.sensor}}").build(); + + // if we have a custom command channel for zone cleanup, etc => create text channel + if (channelConfiguration.sendCommandTopic != null) { + TextValue customCommandValue = new TextValue(); + buildChannel(VACUUM_CUSMTOM_COMMAND_CHANNEL_ID, customCommandValue, "Custom Command", + componentConfiguration.getUpdateListener()) + .commandTopic(channelConfiguration.sendCommandTopic, false, 1) + .stateTopic(channelConfiguration.sendCommandTopic).build(); + } + } +} From 90e987927a25cf70fab615d7b19b85b227024302 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Mon, 8 Nov 2021 08:20:33 +0100 Subject: [PATCH 068/361] [openuv] Add missing entries to the default properties file (#11540) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/i18n/openuv.properties | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv.properties b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv.properties index f0fdd2f9a5863..c942051dfd144 100644 --- a/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv.properties +++ b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv.properties @@ -9,6 +9,12 @@ thing-type.openuv.openuvapi.label = Open UV API thing-type.openuv.openuvapi.description = Bridge to the OpenUV Project API. In order to receive the data, you must register an account on https://www.openuv.io/auth/google and get your API token. thing-type.openuv.uvreport.label = UV Report thing-type.openuv.uvreport.description = Provides various UV data from the OpenUV Project for a given location. +thing-type.openuv.uvreport.channel.OzoneTime.label = Ozone Observation Time +thing-type.openuv.uvreport.channel.OzoneTime.description = Latest OMI ozone update timestamp. +thing-type.openuv.uvreport.channel.UVMaxTime.label = UV Max Time +thing-type.openuv.uvreport.channel.UVMaxTime.description = Max UV Index time (solar noon) +thing-type.openuv.uvreport.channel.UVTime.label = Report Timestamp +thing-type.openuv.uvreport.channel.UVTime.description = UV Report timestamp. # thing types config @@ -55,12 +61,12 @@ channel-type.config.openuv.SafeExposure.index.option.IV = Moderate brown channel-type.config.openuv.SafeExposure.index.option.V = Dark brown channel-type.config.openuv.SafeExposure.index.option.VI = Black -# Thing status descriptions +# thing status descriptions offline.config-error-unknown-apikey = Parameter 'apikey' must be configured. offline.config-error-invalid-refresh = Parameter 'refresh' must be higher than 3 minutes to stay in free API plan. offline.comm-error-quota-exceeded = Quota Exceeded, going OFFLINE for today, will retry at : {0} -# Discovery result +# discovery result discovery.openuv.uvreport.local.label = Local UV Report From 0a83efd234631b1b30f25770f899dc7426da8f2d Mon Sep 17 00:00:00 2001 From: lolodomo Date: Mon, 8 Nov 2021 08:20:52 +0100 Subject: [PATCH 069/361] [weathercompany] Add missing entries to the default properties file (#11541) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/weathercompany.properties | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.weathercompany/src/main/resources/OH-INF/i18n/weathercompany.properties b/bundles/org.openhab.binding.weathercompany/src/main/resources/OH-INF/i18n/weathercompany.properties index 25017dc49cb77..e95ca293b6c20 100644 --- a/bundles/org.openhab.binding.weathercompany/src/main/resources/OH-INF/i18n/weathercompany.properties +++ b/bundles/org.openhab.binding.weathercompany/src/main/resources/OH-INF/i18n/weathercompany.properties @@ -47,6 +47,19 @@ thing-type.weathercompany.weather-forecast.group.forecastDay5Night.label = Night thing-type.weathercompany.weather-forecast.group.forecastDay5Night.description = This is the night-time weather forecast in 5 days thing-type.weathercompany.weather-observations.label = Weather Company Observations thing-type.weathercompany.weather-observations.description = Current observations from Personal Weather Station +thing-type.weathercompany.weather-observations.channel.currentHumidity.label = Humidity +thing-type.weathercompany.weather-observations.channel.currentPrecipitationRate.label = Precipitation Rate +thing-type.weathercompany.weather-observations.channel.currentPrecipitationTotal.label = Precipitation Total +thing-type.weathercompany.weather-observations.channel.currentPressure.label = Pressure +thing-type.weathercompany.weather-observations.channel.currentSolarRadiation.label = Solar Radiation +thing-type.weathercompany.weather-observations.channel.currentTemperature.label = Temperature +thing-type.weathercompany.weather-observations.channel.currentTemperatureDewPoint.label = Dew Point Temperature +thing-type.weathercompany.weather-observations.channel.currentTemperatureHeatIndex.label = Heat Index Temperature +thing-type.weathercompany.weather-observations.channel.currentTemperatureWindChill.label = Wind Chill Temperature +thing-type.weathercompany.weather-observations.channel.currentUv.label = UV Index +thing-type.weathercompany.weather-observations.channel.currentWindDirection.label = Wind Direction +thing-type.weathercompany.weather-observations.channel.currentWindSpeed.label = Wind Speed +thing-type.weathercompany.weather-observations.channel.currentWindSpeedGust.label = Wind Gust Speed # thing types config @@ -245,7 +258,7 @@ channel-type.weathercompany.wxPhraseLong.description = Wx phrase long channel-type.weathercompany.wxPhraseShort.label = Wx Phrase Short channel-type.weathercompany.wxPhraseShort.description = Wx phrase short -# Thing status descriptions +# thing status descriptions offline.config-error-invalid-api-key = API key is invalid offline.config-error-unset-postal-code = Postal code is not set From b40b637802dbd227e42717de15c5f577a5738889 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Mon, 8 Nov 2021 08:21:12 +0100 Subject: [PATCH 070/361] [kodi] Add missing entries to the default properties file (#11542) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/kodi.properties | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties b/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties index 09e24efef2b3b..b3227c0f3f198 100644 --- a/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties +++ b/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties @@ -12,6 +12,34 @@ binding.config.kodi.callbackUrl.description = url to use for playing notificatio thing-type.kodi.kodi.label = Kodi Mediacenter thing-type.kodi.kodi.description = Kodi Mediacenter Binding +thing-type.kodi.kodi.channel.audio-channels.label = Audio Channels +thing-type.kodi.kodi.channel.audio-codec.label = Audio Codec +thing-type.kodi.kodi.channel.audio-codec.description = Audio codec of currently playing media +thing-type.kodi.kodi.channel.audio-index.label = Audio Index +thing-type.kodi.kodi.channel.audio-language.label = Audio Language +thing-type.kodi.kodi.channel.audio-name.label = Audio Name +thing-type.kodi.kodi.channel.mediaid.label = Kodi Media ID +thing-type.kodi.kodi.channel.mediaid.description = media_id in kodi database +thing-type.kodi.kodi.channel.subtitle-enabled.label = Subtitle Enabled +thing-type.kodi.kodi.channel.subtitle-index.label = Subtitle Index +thing-type.kodi.kodi.channel.subtitle-language.label = Subtitle Language +thing-type.kodi.kodi.channel.subtitle-name.label = Subtitle Name +thing-type.kodi.kodi.channel.uniqueid-douban.label = Douban ID +thing-type.kodi.kodi.channel.uniqueid-douban.description = example usage - http://www.douban.com/subject/3036644/ +thing-type.kodi.kodi.channel.uniqueid-imdb.label = IMDB ID +thing-type.kodi.kodi.channel.uniqueid-imdb.description = example usage - http://www.imdb.com/title/tt7207268/ +thing-type.kodi.kodi.channel.uniqueid-imdbtvshow.label = IMDB TVSHOW ID +thing-type.kodi.kodi.channel.uniqueid-imdbtvshow.description = example usage - http://www.imdb.com/title/tt0426769/ +thing-type.kodi.kodi.channel.uniqueid-tmdb.label = TMDB ID +thing-type.kodi.kodi.channel.uniqueid-tmdb.description = example usage - http://www.themoviedb.org/movie/123456789 +thing-type.kodi.kodi.channel.uniqueid-tmdbepisode.label = TMDB EPISODE ID +thing-type.kodi.kodi.channel.uniqueid-tmdbepisode.description = example usage - http://www.themoviedb.org/tv/12225/season/5/episode/15/ +thing-type.kodi.kodi.channel.uniqueid-tmdbtvshow.label = TMDB TVSHOW ID +thing-type.kodi.kodi.channel.uniqueid-tmdbtvshow.description = example usage - http://www.themoviedb.org/tv/12225/ +thing-type.kodi.kodi.channel.userrating.label = User Rating +thing-type.kodi.kodi.channel.video-codec.label = Video Codec +thing-type.kodi.kodi.channel.video-codec.description = Video codec of currently playing media +thing-type.kodi.kodi.channel.video-index.label = Video Index # thing types config From 0bff404508e6d5adca7eafd53e7462577930a6c9 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Mon, 8 Nov 2021 09:43:10 +0100 Subject: [PATCH 071/361] Add missing entries to the default properties file (#11545) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/avmfritz.properties | 15 ++++++--------- .../resources/OH-INF/i18n/avmfritz_de.properties | 2 -- .../main/resources/OH-INF/thing/channel-types.xml | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties index 24599414d852c..3a60e32708cd2 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties @@ -17,6 +17,8 @@ thing-type.avmfritz.FRITZ_DECT_301.label = FRITZ!DECT 301 thing-type.avmfritz.FRITZ_DECT_301.description = FRITZ!DECT 301 heating thermostat. thing-type.avmfritz.FRITZ_DECT_400.label = FRITZ!DECT 400 thing-type.avmfritz.FRITZ_DECT_400.description = FRITZ!DECT400 switch. +thing-type.avmfritz.FRITZ_DECT_400.channel.press.label = Button Press +thing-type.avmfritz.FRITZ_DECT_400.channel.press.description = Triggeres SHORT_PRESSED or LONG_PRESSED when a button was pressed. thing-type.avmfritz.FRITZ_DECT_440.label = FRITZ!DECT 440 thing-type.avmfritz.FRITZ_DECT_440.description = FRITZ!DECT440 switch. thing-type.avmfritz.FRITZ_DECT_440.group.bottom-left.label = Bottom Left Button @@ -43,6 +45,8 @@ thing-type.avmfritz.HAN_FUN_ON_OFF.label = HAN-FUN On / Off Device thing-type.avmfritz.HAN_FUN_ON_OFF.description = HAN-FUN switchable device (e.g. SmartHome Zwischenstecker innen / SmartHome Zwischenstecker außen) thing-type.avmfritz.HAN_FUN_SWITCH.label = HAN-FUN Switch thing-type.avmfritz.HAN_FUN_SWITCH.description = HAN-FUN switch (e.g. SmartHome Wandtaster). +thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.label = Button Press +thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.description = Triggeres PRESSED when a button was pressed. thing-type.avmfritz.fritzbox.label = FRITZ!Box thing-type.avmfritz.fritzbox.description = A FRITZ!Box router. @@ -139,6 +143,7 @@ channel-type.avmfritz.incoming_call.label = Incoming Call channel-type.avmfritz.incoming_call.description = Details about incoming call. channel-type.avmfritz.last_change.label = Last Change channel-type.avmfritz.last_change.description = States the last time the button was pressed. +channel-type.avmfritz.last_change.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS channel-type.avmfritz.locked.label = Device Locked (external) channel-type.avmfritz.locked.description = Device is locked for switching over external sources. channel-type.avmfritz.mode.label = Mode @@ -148,6 +153,7 @@ channel-type.avmfritz.mode.state.option.AUTOMATIC = Automatic channel-type.avmfritz.mode.state.option.VACATION = Vacation channel-type.avmfritz.next_change.label = Next Setpoint Change channel-type.avmfritz.next_change.description = Next change of Setpoint Temperature. +channel-type.avmfritz.next_change.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS channel-type.avmfritz.next_temp.label = Next Setpoint Temperature channel-type.avmfritz.next_temp.description = Next Setpoint Temperature. channel-type.avmfritz.outgoing_call.label = Outgoing Call @@ -178,15 +184,6 @@ channel-type.avmfritz.voltage.description = Current voltage. channel-type.config.avmfritz.temperature.offset.label = Temperature Offset channel-type.config.avmfritz.temperature.offset.description = Current temperature offset (in °C). -# channel types - -channel-type.avmfritz.last_change.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS -channel-type.avmfritz.next_change.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS -thing-type.avmfritz.FRITZ_DECT_400.channel.press.label = Button Press -thing-type.avmfritz.FRITZ_DECT_400.channel.press.description = Triggers SHORT_PRESSED or LONG_PRESSED when a button was pressed. -thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.label = Button Press -thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.description = Triggers PRESSED when a button was pressed. - # thing actions setBoostModeModeActionLabel = set the Boost mode diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties index 7a5ac04374895..aa46a83e155cf 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties @@ -203,7 +203,6 @@ channel-type.avmfritz.radiator_mode.state.option.WINDOW_OPEN = Fenster-Auf channel-type.avmfritz.next_change.label = Nächste Änderung channel-type.avmfritz.next_change.description = Zeigt den Zeitpunkt der nächsten Änderung der Solltemperatur des Heizkörperreglers an. -channel-type.avmfritz.next_change.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS channel-type.avmfritz.next_temp.label = Nächste Solltemperatur channel-type.avmfritz.next_temp.description = Zeigt die nächste Solltemperatur des Heizkörperreglers an. @@ -222,7 +221,6 @@ channel-type.avmfritz.rollershutter.description = Steuert den Rollladen und zeig channel-type.avmfritz.last_change.label = Letzte Änderung channel-type.avmfritz.last_change.description = Zeigt an, wann der Schalter zuletzt gedrückt wurde. -channel-type.avmfritz.last_change.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS # channel types config channel-type.config.avmfritz.temperature.offset.label = Temperatur-Offset diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml index 9c64ede171027..2c80f7ff878ec 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml @@ -205,7 +205,7 @@ Next change of Setpoint Temperature. Time - + @@ -229,7 +229,7 @@ States the last time the button was pressed. Time - + From 32be93555bdb73d9bc8bab81d606dba12269fd50 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Mon, 8 Nov 2021 10:57:57 +0100 Subject: [PATCH 072/361] [deconz] Added default i18n properties file (#11546) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/deconz.properties | 189 ++++++++++++++++++ .../OH-INF/i18n/deconz_de.properties | 4 +- 2 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz.properties diff --git a/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz.properties b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz.properties new file mode 100644 index 0000000000000..c858cde0bd820 --- /dev/null +++ b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz.properties @@ -0,0 +1,189 @@ +# binding + +binding.deconz.name = Dresden Elektronik deCONZ Binding +binding.deconz.description = Allows to use the real-time channel of the deCONZ software for Zigbee sensors and switches. deCONZ is the accompanying software for the Raspbee and Conbee Zigbee dongles from Dresden Elektronik. Is meant to be used together with the HUE binding which makes the lights and plugs available. + +# thing types + +thing-type.deconz.alarmsensor.label = Alarm Sensor +thing-type.deconz.alarmsensor.description = An alarm sensor +thing-type.deconz.batterysensor.label = Battery Sensor +thing-type.deconz.batterysensor.description = A battery sensor +thing-type.deconz.carbonmonoxidesensor.label = Carbon-monoxide Sensor +thing-type.deconz.colorcontrol.label = Color Controller +thing-type.deconz.colorlight.label = Color Light +thing-type.deconz.colorlight.description = A dimmable light with adjustable color. +thing-type.deconz.colortemperaturelight.label = Color-Temperature Light +thing-type.deconz.colortemperaturelight.description = A dimmable light with adjustable color temperature. +thing-type.deconz.consumptionsensor.label = Consumption Sensor +thing-type.deconz.consumptionsensor.description = A consumption sensor +thing-type.deconz.daylightsensor.label = Daylight Sensor +thing-type.deconz.daylightsensor.description = A daylight sensor +thing-type.deconz.deconz.label = deCONZ +thing-type.deconz.deconz.description = A running deCONZ software instance. +thing-type.deconz.dimmablelight.label = Dimmable Light +thing-type.deconz.dimmablelight.description = A dimmable light. +thing-type.deconz.doorlock.label = Doorlock +thing-type.deconz.doorlock.description = A doorlock that can be locked (ON) or unlocked (OFF). +thing-type.deconz.extendedcolorlight.label = Color Light +thing-type.deconz.extendedcolorlight.description = A dimmable light with adjustable color. +thing-type.deconz.firesensor.label = Fire Sensor +thing-type.deconz.firesensor.description = A fire sensor +thing-type.deconz.humiditysensor.label = Humidity Sensor +thing-type.deconz.humiditysensor.description = A humidity sensor +thing-type.deconz.lightgroup.label = Light Group +thing-type.deconz.lightsensor.label = Light Sensor +thing-type.deconz.lightsensor.description = A light sensor +thing-type.deconz.onofflight.label = On/Off Light +thing-type.deconz.onofflight.description = A light that can be turned on or off. +thing-type.deconz.openclosesensor.label = Open/Close Sensor +thing-type.deconz.openclosesensor.description = A open/close sensor +thing-type.deconz.powersensor.label = Power Sensor +thing-type.deconz.powersensor.description = A power sensor +thing-type.deconz.presencesensor.label = Presence Sensor +thing-type.deconz.presencesensor.description = A Presence sensor +thing-type.deconz.pressuresensor.label = Pressure Sensor +thing-type.deconz.pressuresensor.description = A pressure senor +thing-type.deconz.switch.label = Switch/Button +thing-type.deconz.switch.description = A switch or button +thing-type.deconz.temperaturesensor.label = Temperature Sensor +thing-type.deconz.temperaturesensor.description = A temperature sensor +thing-type.deconz.thermostat.label = Thermostat +thing-type.deconz.thermostat.description = A Thermostat sensor/actor +thing-type.deconz.vibrationsensor.label = Vibration Sensor +thing-type.deconz.vibrationsensor.description = A vibration sensor +thing-type.deconz.warningdevice.label = Warning Device +thing-type.deconz.warningdevice.description = A warning device +thing-type.deconz.waterleakagesensor.label = Water Leakage Sensor +thing-type.deconz.waterleakagesensor.description = A water leakage sensor +thing-type.deconz.windowcovering.label = Window Covering +thing-type.deconz.windowcovering.description = A device to cover windows. + +# thing types config + +thing-type.config.deconz.bridge.apikey.label = API Key +thing-type.config.deconz.bridge.apikey.description = If no API Key is provided, a new one will be requested. You need to authorize the access on the deCONZ web interface. +thing-type.config.deconz.bridge.host.label = Host Address +thing-type.config.deconz.bridge.host.description = IP address or host name of deCONZ interface. +thing-type.config.deconz.bridge.httpPort.label = HTTP Port +thing-type.config.deconz.bridge.httpPort.description = Port of the deCONZ HTTP interface. +thing-type.config.deconz.bridge.port.label = Websocket Port +thing-type.config.deconz.bridge.port.description = Port of the deCONZ Websocket. +thing-type.config.deconz.bridge.timeout.label = Timeout +thing-type.config.deconz.bridge.timeout.description = Timeout for asynchronous HTTP requests (in milliseconds). +thing-type.config.deconz.colorlight.colormode.label = Color Mode +thing-type.config.deconz.colorlight.colormode.description = Override the default color mode (auto-detect) +thing-type.config.deconz.colorlight.colormode.option.hs = HSB +thing-type.config.deconz.colorlight.colormode.option.xy = XY +thing-type.config.deconz.colorlight.id.label = Device ID +thing-type.config.deconz.colorlight.id.description = The deCONZ bridge assigns an integer number ID to each device. +thing-type.config.deconz.colorlight.transitiontime.label = Transition Time +thing-type.config.deconz.colorlight.transitiontime.description = Time to move between two states. If empty, the default of the device is used. Resolution is 1/10 second. +thing-type.config.deconz.light.id.label = Device ID +thing-type.config.deconz.light.id.description = The deCONZ bridge assigns an integer number ID to each device. +thing-type.config.deconz.light.transitiontime.label = Transition Time +thing-type.config.deconz.light.transitiontime.description = Time to move between two states. If empty, the default of the device is used. Resolution is 1/10 second. +thing-type.config.deconz.lightgroup.colormode.label = Color Mode +thing-type.config.deconz.lightgroup.colormode.description = Override the default color mode (auto-detect) +thing-type.config.deconz.lightgroup.colormode.option.hs = HSB +thing-type.config.deconz.lightgroup.colormode.option.xy = XY +thing-type.config.deconz.lightgroup.id.label = Device ID +thing-type.config.deconz.lightgroup.id.description = The deCONZ bridge assigns an integer number ID to each group. +thing-type.config.deconz.sensor.id.label = Device ID +thing-type.config.deconz.sensor.id.description = The deCONZ bridge assigns an integer number ID to each device. +thing-type.config.deconz.sensor.lastSeenPolling.label = LastSeen Poll Interval +thing-type.config.deconz.sensor.lastSeenPolling.description = Interval to poll the deCONZ Gateway for this sensor's "last_seen" channel. Polling is disabled when set to 0 (default: 1440, once per day). + +# channel types + +channel-type.deconz.alarm.label = Alarm +channel-type.deconz.alarm.description = Alarm was triggered. +channel-type.deconz.alert.label = Alert +channel-type.deconz.all_on.label = All On +channel-type.deconz.all_on.description = "On" if all lights in this group are "On", otherwise "Off". +channel-type.deconz.any_on.label = Any On +channel-type.deconz.any_on.description = "On" if any light in this group is "On", otherwise "Off". +channel-type.deconz.button.label = Button +channel-type.deconz.button.description = The Button that was last pressed on the switch. +channel-type.deconz.buttonevent.label = Button Trigger +channel-type.deconz.buttonevent.description = This channel is triggered on a button event. The trigger payload consists of the button event number. +channel-type.deconz.carbonmonoxide.label = Carbon-monoxide +channel-type.deconz.carbonmonoxide.description = Carbon-monoxide was detected. +channel-type.deconz.consumption.label = Consumption +channel-type.deconz.consumption.description = Current consumption +channel-type.deconz.ct.label = Color Temperature +channel-type.deconz.ct.description = Controls the color temperature of the light in Kelvin +channel-type.deconz.current.label = Current +channel-type.deconz.current.description = Current current +channel-type.deconz.dark.label = Dark +channel-type.deconz.dark.description = Light level is below the darkness threshold. +channel-type.deconz.daylight.label = Daylight +channel-type.deconz.daylight.description = Light level is above the daylight threshold. +channel-type.deconz.effect.label = Effect Channel +channel-type.deconz.effectSpeed.label = Effect Speed Channel +channel-type.deconz.fire.label = Fire +channel-type.deconz.fire.description = A fire was detected. +channel-type.deconz.gesture.label = Gesture +channel-type.deconz.gesture.description = A gesture that was performed with the switch. +channel-type.deconz.gesture.state.option.0 = None +channel-type.deconz.gesture.state.option.1 = Shake +channel-type.deconz.gesture.state.option.2 = Drop +channel-type.deconz.gesture.state.option.3 = Flip 90 +channel-type.deconz.gesture.state.option.4 = Flip 180 +channel-type.deconz.gesture.state.option.5 = Push +channel-type.deconz.gesture.state.option.6 = Double Tap +channel-type.deconz.gesture.state.option.7 = Rotate Clockwise +channel-type.deconz.gesture.state.option.8 = Rotate Counter Clockwise +channel-type.deconz.gestureevent.label = Gesture Trigger +channel-type.deconz.gestureevent.description = This channel is triggered on a gesture event. The trigger payload consists of the gesture event number. +channel-type.deconz.heatsetpoint.label = Target Temperature +channel-type.deconz.heatsetpoint.description = Target temperature +channel-type.deconz.humidity.label = Humidity +channel-type.deconz.humidity.description = Current humidity +channel-type.deconz.last_seen.label = Last Seen +channel-type.deconz.last_seen.description = The date and time when the sensor was last seen. +channel-type.deconz.last_seen.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.deconz.last_updated.label = Last Updated +channel-type.deconz.last_updated.description = The date and time when the sensor was last updated. +channel-type.deconz.last_updated.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.deconz.light.label = Lightlevel +channel-type.deconz.light.description = A light level +channel-type.deconz.light.state.option.daylight = Daylight +channel-type.deconz.light.state.option.sunset = Sunset +channel-type.deconz.light.state.option.dark = Dark +channel-type.deconz.light_level.label = Light Level +channel-type.deconz.light_level.description = Current light level. +channel-type.deconz.lightlux.label = Illuminance +channel-type.deconz.lightlux.description = Current light illuminance +channel-type.deconz.lock.label = Lock +channel-type.deconz.mode.label = Mode +channel-type.deconz.mode.description = Current mode +channel-type.deconz.mode.state.option.AUTO = auto +channel-type.deconz.mode.state.option.HEAT = heat +channel-type.deconz.mode.state.option.OFF = off +channel-type.deconz.offset.label = Offset +channel-type.deconz.offset.description = Temperature offset +channel-type.deconz.ontime.label = On Time +channel-type.deconz.ontime.description = Time that the light stays on before switched off automatically (0=forever) +channel-type.deconz.open.label = Open/Close +channel-type.deconz.open.description = Open/Close detected +channel-type.deconz.position.label = Position +channel-type.deconz.power.label = Power +channel-type.deconz.power.description = Current power usage +channel-type.deconz.pressure.label = Pressure +channel-type.deconz.pressure.description = Current pressure +channel-type.deconz.scene.label = Recall Scene +channel-type.deconz.tampered.label = Tampered +channel-type.deconz.tampered.description = A zone is being tampered. +channel-type.deconz.temperature.label = Temperature +channel-type.deconz.temperature.description = Current temperature +channel-type.deconz.value.label = Daylight Value +channel-type.deconz.value.description = Dawn is around 130, sunrise at 140, sunset at 190, and dusk at 210 +channel-type.deconz.valve.label = Valve position +channel-type.deconz.valve.description = Current valve position +channel-type.deconz.vibration.label = Vibration +channel-type.deconz.vibration.description = Vibration was detected. +channel-type.deconz.voltage.label = Voltage +channel-type.deconz.voltage.description = Current voltage +channel-type.deconz.waterleakage.label = Water Leakage +channel-type.deconz.waterleakage.description = Water leakage detected diff --git a/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties index 6977415258a37..e4363e1f2b56f 100644 --- a/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties +++ b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties @@ -15,7 +15,7 @@ channel-type.deconz.ct.description = Steuert die Farbtemperatur des Lichts in Ke channel-type.deconz.last_updated.label = Letzte Aktualisierung channel-type.deconz.last_updated.description = Zeit, zu der sich dieser Wert geändert hat. -channel-type.deconz.last_updated.options.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS +channel-type.deconz.last_updated.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS channel-type.deconz.last_seen.label = Zuletzt Gesehen channel-type.deconz.last_seen.description = Zeit, zu der sich dieser Wert geändert hat. -channel-type.deconz.last_seen.options.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS +channel-type.deconz.last_seen.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS From 251d74b043fba8f98cdda3b44d5afdb6b1cf36c3 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Mon, 8 Nov 2021 12:58:29 +0100 Subject: [PATCH 073/361] [openhabcloud] Added default i18n properties file (#11547) * Added default i18n properties file * Added translation property for service label Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../io/openhabcloud/internal/CloudService.java | 4 +++- .../src/main/resources/OH-INF/config/config.xml | 2 +- .../resources/OH-INF/i18n/openhabcloud.properties | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties diff --git a/bundles/org.openhab.io.openhabcloud/src/main/java/org/openhab/io/openhabcloud/internal/CloudService.java b/bundles/org.openhab.io.openhabcloud/src/main/java/org/openhab/io/openhabcloud/internal/CloudService.java index df9137673e1e8..e41e9f27c3018 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/java/org/openhab/io/openhabcloud/internal/CloudService.java +++ b/bundles/org.openhab.io.openhabcloud/src/main/java/org/openhab/io/openhabcloud/internal/CloudService.java @@ -67,9 +67,11 @@ @Component(service = { CloudService.class, EventSubscriber.class, ActionService.class }, configurationPid = "org.openhab.openhabcloud", property = Constants.SERVICE_PID + "=org.openhab.openhabcloud") -@ConfigurableService(category = "io", label = "openHAB Cloud", description_uri = "io:openhabcloud") +@ConfigurableService(category = "io", label = "openHAB Cloud", description_uri = CloudService.CONFIG_URI) public class CloudService implements ActionService, CloudClientListener, EventSubscriber { + protected static final String CONFIG_URI = "io:openhabcloud"; + private static final String CFG_EXPOSE = "expose"; private static final String CFG_BASE_URL = "baseURL"; private static final String CFG_MODE = "mode"; diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/config/config.xml index 2146c45efe0d9..d870ed859e11c 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/config/config.xml @@ -21,7 +21,7 @@ - Base URL for the openHAB Cloud server + Base URL for the openHAB Cloud server. https://myopenhab.org/ diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties new file mode 100644 index 0000000000000..cb76d5404a13b --- /dev/null +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties @@ -0,0 +1,14 @@ +# service + +service.io.openhabcloud.label = openHAB Cloud + +# bundle config + +io.config.openhabcloud.baseURL.label = Base URL +io.config.openhabcloud.baseURL.description = Base URL for the openHAB Cloud server. +io.config.openhabcloud.expose.label = Items to Expose +io.config.openhabcloud.expose.description = List of items that are made accessible to IFTTT and similar services. +io.config.openhabcloud.mode.label = Mode +io.config.openhabcloud.mode.description = What features of the openHAB Cloud service should be used. +io.config.openhabcloud.mode.option.notification = Notifications +io.config.openhabcloud.mode.option.remote = Notifications & Remote Access From 333d9088d4785dd341a3ae43fd59f96ca190e393 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Mon, 8 Nov 2021 13:53:42 +0100 Subject: [PATCH 074/361] [hue] Internationalization of discovery results (#11501) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../hue/internal/HueThingHandlerFactory.java | 11 +++++++++-- .../discovery/HueDeviceDiscoveryService.java | 15 ++++++++++++--- .../hue/internal/handler/HueBridgeHandler.java | 17 ++++++++++++++++- .../main/resources/OH-INF/i18n/hue.properties | 4 ++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueThingHandlerFactory.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueThingHandlerFactory.java index fb13efd35140a..e82cdec945439 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueThingHandlerFactory.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueThingHandlerFactory.java @@ -33,6 +33,8 @@ import org.openhab.binding.hue.internal.handler.sensors.TapSwitchHandler; import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler; import org.openhab.core.config.core.Configuration; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -68,10 +70,15 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory { .flatMap(i -> i).collect(Collectors.toSet())); private final HueStateDescriptionProvider stateDescriptionProvider; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; @Activate - public HueThingHandlerFactory(final @Reference HueStateDescriptionProvider stateDescriptionProvider) { + public HueThingHandlerFactory(final @Reference HueStateDescriptionProvider stateDescriptionProvider, + final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) { this.stateDescriptionProvider = stateDescriptionProvider; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; } @Override @@ -142,7 +149,7 @@ private ThingUID getThingUID(ThingTypeUID thingTypeUID, String id, @Nullable Thi @Override protected @Nullable ThingHandler createHandler(Thing thing) { if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { - return new HueBridgeHandler((Bridge) thing, stateDescriptionProvider); + return new HueBridgeHandler((Bridge) thing, stateDescriptionProvider, i18nProvider, localeProvider); } else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { return new HueLightHandler(thing, stateDescriptionProvider); } else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueDeviceDiscoveryService.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueDeviceDiscoveryService.java index 019eb36393f42..b86639169f34b 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueDeviceDiscoveryService.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/discovery/HueDeviceDiscoveryService.java @@ -111,8 +111,11 @@ public HueDeviceDiscoveryService() { @Override public void setThingHandler(@Nullable ThingHandler handler) { if (handler instanceof HueBridgeHandler) { - hueBridgeHandler = (HueBridgeHandler) handler; + HueBridgeHandler localHandler = (HueBridgeHandler) handler; + hueBridgeHandler = localHandler; bridgeUID = handler.getThing().getUID(); + i18nProvider = localHandler.getI18nProvider(); + localeProvider = localHandler.getLocaleProvider(); } } @@ -275,8 +278,14 @@ public void addGroupDiscovery(FullGroup group) { Map properties = new HashMap<>(); properties.put(GROUP_ID, group.getId()); - String name = String.format("%s (%s)", "0".equals(group.getId()) ? "All lights" : group.getName(), - group.getType()); + String name; + if ("0".equals(group.getId())) { + name = "@text/discovery.group.all_lights.label"; + } else if ("Room".equals(group.getType())) { + name = group.getName(); + } else { + name = String.format("%s (%s)", group.getName(), group.getType()); + } DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(THING_TYPE_GROUP) .withProperties(properties).withBridge(localBridgeUID).withRepresentationProperty(GROUP_ID) .withLabel(name).build(); diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java index 0a9a577c9e8b1..19f377e52a3bc 100644 --- a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java +++ b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java @@ -54,6 +54,8 @@ import org.openhab.binding.hue.internal.exceptions.UnauthorizedException; import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.status.ConfigStatusMessage; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.HSBType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StringType; @@ -98,6 +100,8 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl private final Logger logger = LoggerFactory.getLogger(HueBridgeHandler.class); private final HueStateDescriptionProvider stateDescriptionOptionProvider; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; private final Map lastLightStates = new ConcurrentHashMap<>(); private final Map lastSensorStates = new ConcurrentHashMap<>(); @@ -403,9 +407,12 @@ private void setBridgeSceneChannelStateOptions(List scenes, Map consoleScenesList = new ArrayList<>(); - public HueBridgeHandler(Bridge bridge, HueStateDescriptionProvider stateDescriptionOptionProvider) { + public HueBridgeHandler(Bridge bridge, HueStateDescriptionProvider stateDescriptionOptionProvider, + TranslationProvider i18nProvider, LocaleProvider localeProvider) { super(bridge); this.stateDescriptionOptionProvider = stateDescriptionOptionProvider; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; } @Override @@ -1040,4 +1047,12 @@ public Collection getConfigStatus() { return List.of(); } } + + public TranslationProvider getI18nProvider() { + return i18nProvider; + } + + public LocaleProvider getLocaleProvider() { + return localeProvider; + } } diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties index a7609ea22cb2f..fa842293b4317 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties @@ -225,3 +225,7 @@ actionInputFadeTimeLabel = FadeTime actionInputFadeTimeDesc = The fade time to use for the light command in ms. actionLabel = send a light command with a custom fade time actionDesc = Send a light command with a custom fade time. + +# discovery results + +discovery.group.all_lights.label = All lights From 804f83d847f7bb6b734b45e5bed426e99e49d5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Tue, 9 Nov 2021 08:59:13 +0100 Subject: [PATCH 075/361] [AirQuality] Tagging channels, prepared for Crowdin, dynamic channels (#11192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding semantic tags Adding alert level and code refined. Signed-off-by: Gaël L'hopital * Commiting intermediate work Signed-off-by: Gaël L'hopital * Complete review of the binding. Added measures for each pollutant. Added extensible channel for pollutant sensibility. Signed-off-by: clinique * Finishing translation Signed-off-by: Gaël L'hopital * One last code cleansing to be ready to push Signed-off-by: Gaël L'hopital * Documentation updates Signed-off-by: Gaël L'hopital * Spotless apply Signed-off-by: Gaël L'hopital * Correcting conflicting file Signed-off-by: Gaël L'hopital * Code review correction Signed-off-by: Gael L'hopital * Introducing a bridge to Api Signed-off-by: clinique * Code review correction Signed-off-by: clinique Signed-off-by: Michael Schmidt --- .../org.openhab.binding.airquality/README.md | 143 ++++---- .../internal/AirQualityBindingConstants.java | 74 ++-- .../internal/AirQualityException.java | 46 +++ .../internal/AirQualityHandlerFactory.java | 32 +- .../airquality/internal/api/ApiBridge.java | 88 +++++ .../airquality/internal/api/Appreciation.java | 43 +++ .../internal/api/ConcentrationRange.java | 45 +++ .../airquality/internal/api/Index.java | 65 ++++ .../airquality/internal/api/Pollutant.java | 96 ++++++ .../dto/AirQualityCity.java} | 10 +- .../dto/AirQualityData.java} | 35 +- .../dto/AirQualityResponse.java} | 12 +- .../dto/AirQualityTime.java} | 20 +- .../{json => api/dto}/AirQualityValue.java | 12 +- .../dto/Attribution.java} | 5 +- .../{ => config}/AirQualityConfiguration.java | 18 +- .../config/SensitiveGroupConfiguration.java | 37 ++ .../discovery/AirQualityDiscoveryService.java | 102 +++--- .../handler/AirQualityBridgeHandler.java | 76 ++++ .../internal/handler/AirQualityHandler.java | 285 --------------- .../handler/AirQualityStationHandler.java | 298 ++++++++++++++++ .../main/resources/OH-INF/binding/binding.xml | 1 - .../OH-INF/i18n/airquality.properties | 62 ++++ .../OH-INF/i18n/airquality_fr.properties | 76 ++-- .../resources/OH-INF/thing/thing-types.xml | 324 ++++++++++-------- .../src/main/resources/picto/good.svg | 17 + .../src/main/resources/picto/hazardous.svg | 19 + .../src/main/resources/picto/moderate.svg | 17 + .../src/main/resources/picto/unhealthy.svg | 17 + .../main/resources/picto/unhealthy_fsg.svg | 13 + .../main/resources/picto/very_unhealthy.svg | 18 + 31 files changed, 1391 insertions(+), 715 deletions(-) create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityException.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ApiBridge.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Appreciation.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ConcentrationRange.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Index.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Pollutant.java rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json/AirQualityJsonCity.java => api/dto/AirQualityCity.java} (81%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json/AirQualityJsonData.java => api/dto/AirQualityData.java} (65%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json/AirQualityJsonResponse.java => api/dto/AirQualityResponse.java} (75%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json/AirQualityJsonTime.java => api/dto/AirQualityTime.java} (63%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json => api/dto}/AirQualityValue.java (74%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{json/Attribute.java => api/dto/Attribution.java} (91%) rename bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/{ => config}/AirQualityConfiguration.java (56%) create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/SensitiveGroupConfiguration.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityBridgeHandler.java delete mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityHandler.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityStationHandler.java create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality.properties create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/good.svg create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/hazardous.svg create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/moderate.svg create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy.svg create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy_fsg.svg create mode 100644 bundles/org.openhab.binding.airquality/src/main/resources/picto/very_unhealthy.svg diff --git a/bundles/org.openhab.binding.airquality/README.md b/bundles/org.openhab.binding.airquality/README.md index 0a21a20f445f4..8d54e36152304 100644 --- a/bundles/org.openhab.binding.airquality/README.md +++ b/bundles/org.openhab.binding.airquality/README.md @@ -11,26 +11,32 @@ To use this binding, you first need to [register and get your API token](https:/ ## Supported Things -There is exactly one supported thing type, which represents the air quality information for an observation location. -It has the `aqi` id. -Of course, you can add multiple Things, e.g. for measuring AQI for different locations. +Bridge: The binding supports a bridge to connect to the [AQIcn.org service](https://aqicn.org). A bridge uses the thing ID "api". + +Station: Represents the air quality information for an observation location. + +Of course, you can add multiple Stations, e.g. for measuring AQI for different locations. ## Discovery Local Air Quality can be autodiscovered based on system location. -You will have complete default configuration with your apiKey. +You will created a Bridge with your apiKey. -## Binding Configuration +## Bridge Configuration + +The bridge configuration only holds the api key : + +| Parameter | Description | +|-----------|-------------------------------------------------------------------------| +| apiKey | Data-platform token to access the AQIcn.org service. Mandatory. | -The binding has no configuration options, all configuration is done at Thing level. ## Thing Configuration -The thing has a few configuration parameters: +The 'Station' thing has a few configuration parameters: | Parameter | Description | |-----------|-------------------------------------------------------------------------| -| apikey | Data-platform token to access the AQIcn.org service. Mandatory. | | location | Geo coordinates to be considered by the service. | | stationId | Unique ID of the measuring station. | | refresh | Refresh interval in minutes. Optional, the default value is 60 minutes. | @@ -45,59 +51,75 @@ For the location parameter, the following syntax is allowed (comma separated lat If you always want to receive data from specific station and you know its unique ID, you can enter it instead of the coordinates. This `stationId` can be found by using the following link: -https://api.waqi.info/search/?token=TOKEN&keyword=NAME, replacing TOKEN by your apikey and NAME by the station you are looking for. +https://api.waqi.info/search/?token=TOKEN&keyword=NAME, replacing TOKEN by your apiKey and NAME by the station you are looking for. + +### Thing properties + +Once created, at first execution, the station's properties will be filled with informations gathered from the web service : + +- Nearest measuring station location +- Measuring station ID +- Latitude/longitude of measuring station + ## Channels -The AirQuality information that is retrieved is available as these channels: +The AirQuality information that is retrieved for a given is available as these channels: + +### AQI Channels Group - Global Results + +| Channel ID | Item Type | Description | +|-----------------|----------------------|----------------------------------------------| +| alert-level | Number | Alert level (*) associated to AQI Index. | +| index | Number | Air Quality Index | +| timestamp | DateTime | Observation date and time | +| dominent | String | Dominent Pollutant | +| icon | Image | Pictogram associated to alert-level | +| color | Color | Color associated to alert level. | + +### Weather Channels Group | Channel ID | Item Type | Description | |-----------------|----------------------|----------------------------------------------| -| aqiLevel | Number | Air Quality Index | -| aqiColor | Color | Color associated to given AQI Index. | -| aqiDescription | String | AQI Description | -| locationName | String | Nearest measuring station location | -| stationId | Number | Measuring station ID | -| stationLocation | Location | Latitude/longitude of measuring station | -| pm25 | Number | Fine particles pollution level (PM2.5) | -| pm10 | Number | Coarse dust particles pollution level (PM10) | -| o3 | Number | Ozone level (O3) | -| no2 | Number | Nitrogen Dioxide level (NO2) | -| co | Number | Carbon monoxide level (CO) | -| so2 | Number | Sulfur dioxide level (SO2) | -| observationTime | DateTime | Observation date and time | | temperature | Number:Temperature | Temperature in Celsius degrees | | pressure | Number:Pressure | Pressure level | | humidity | Number:Dimensionless | Humidity level | -| dominentpol | String | Dominent Polutor | +| dew-point | Number:Temperature | Dew point temperature | +| wind-speed | Number:Speed | Wind speed | + +### Pollutants Channels Group + +For each pollutant (PM25, PM10, O3, NO2, CO, SO2) , depending upon availability of the station, +you will be provided with the following informations + +| Channel ID | Item Type | Description | +|-----------------|----------------------|----------------------------------------------| +| value | Number:Density | Measured density of the pollutant | +| index | Number | AQI Index of the single pollutant | +| alert-level | Number | Alert level associate to the index | -`AQI Description` item provides a human-readable output that can be interpreted e.g. by MAP transformation. -*Note that channels like* `pm25`, `pm10`, `o3`, `no2`, `co`, `so2` *can sometimes return* `UNDEF` *value due to the fact that some stations don't provide measurements for them.* +(*) The alert level is described by a color : + +| Code | Color | Description | +|------|--------|--------------------------------| +| 0 | Green | Good | +| 1 | Yellow | Moderate | +| 2 | Orange | Unhealthy for Sensitive Groups | +| 3 | Red | Unhealthy | +| 4 | Purple | Very Unhealthy | +| 5 | Maroon | Hazardous | + ## Full Example -airquality.map: - -```text --=- -UNDEF=No data -NULL=No data -NO_DATA=No data -GOOD=Good -MODERATE=Moderate -UNHEALTHY_FOR_SENSITIVE=Unhealthy for sensitive groups -UNHEALTHY=Unhealthy -VERY_UNHEALTHY=Very unhealthy -HAZARDOUS=Hazardous -``` airquality.things: ```java -airquality:aqi:home "AirQuality" @ "Krakow" [ apikey="XXXXXXXXXXXX", location="50.06465,19.94498", refresh=60 ] -airquality:aqi:warsaw "AirQuality in Warsaw" [ apikey="XXXXXXXXXXXX", location="52.22,21.01", refresh=60 ] -airquality:aqi:brisbane "AirQuality in Brisbane" [ apikey="XXXXXXXXXXXX", stationId=5115 ] +Bridge airquality:api:main "Bridge" [apiKey="xxxyyyzzz"] { + station MyHouse "Krakow"[location="50.06465,19.94498", refresh=60] +} ``` airquality.items: @@ -105,24 +127,19 @@ airquality.items: ```java Group AirQuality -Number Aqi_Level "Air Quality Index" (AirQuality) { channel="airquality:aqi:home:aqiLevel" } -String Aqi_Description "AQI Level [MAP(airquality.map):%s]" (AirQuality) { channel="airquality:aqi:home:aqiDescription" } - -Number Aqi_Pm25 "PM\u2082\u2085 Level" (AirQuality) { channel="airquality:aqi:home:pm25" } -Number Aqi_Pm10 "PM\u2081\u2080 Level" (AirQuality) { channel="airquality:aqi:home:pm10" } -Number Aqi_O3 "O\u2083 Level" (AirQuality) { channel="airquality:aqi:home:o3" } -Number Aqi_No2 "NO\u2082 Level" (AirQuality) { channel="airquality:aqi:home:no2" } -Number Aqi_Co "CO Level" (AirQuality) { channel="airquality:aqi:home:co" } -Number Aqi_So2 "SO\u2082 Level" (AirQuality) { channel="airquality:aqi:home:so2" } +Number Aqi_Level "Air Quality Index" (AirQuality) { channel="airquality:station:local:aqi#index" } +Number Aqi_Pm25 "PM\u2082\u2085 Level" (AirQuality) { channel="airquality:station:local:pm25#value" } +Number Aqi_Pm10 "PM\u2081\u2080 Level" (AirQuality) { channel="airquality:station:local:pm10#value" } +Number Aqi_O3 "O\u2083 Level" (AirQuality) { channel="airquality:station:local:o3#value" } +Number Aqi_No2 "NO\u2082 Level" (AirQuality) { channel="airquality:station:local:no2#value" } +Number Aqi_Co "CO Level" (AirQuality) { channel="airquality:station:local:co#value" } +Number Aqi_So2 "SO\u2082 Level" (AirQuality) { channel="airquality:station:local:so2#value" } -String Aqi_LocationName "Measuring Location" (AirQuality) { channel="airquality:aqi:home:locationName" } -Location Aqi_StationGeo "Station Location" (AirQuality) { channel="airquality:aqi:home:stationLocation" } -Number Aqi_StationId "Station ID" (AirQuality) { channel="airquality:aqi:home:stationId" } -DateTime Aqi_ObservationTime "Time of observation [%1$tH:%1$tM]" (AirQuality) { channel="airquality:aqi:home:observationTime" } +DateTime Aqi_ObservationTime "Time of observation [%1$tH:%1$tM]" (AirQuality) { channel="airquality:station:local:aqi#timestamp" } -Number:Temperature Aqi_Temperature "Temperature" (AirQuality) { channel="airquality:aqi:home:temperature" } -Number:Pressure Aqi_Pressure "Pressure" (AirQuality) { channel="airquality:aqi:home:pressure" } -Number:Dimensionless Aqi_Humidity "Humidity" (AirQuality) { channel="airquality:aqi:home:humidity" } +Number:Temperature Aqi_Temperature "Temperature" (AirQuality) { channel="airquality:station:local:weather#temperature" } +Number:Pressure Aqi_Pressure "Pressure" (AirQuality) { channel="airquality:station:local:weather#pressure" } +Number:Dimensionless Aqi_Humidity "Humidity" (AirQuality) { channel="airquality:station:localweather#humidity" } ``` airquality.sitemap: @@ -143,7 +160,7 @@ sitemap airquality label="Air Quality" { Aqi_Description=="HAZARDOUS"="#7e0023", =="VERY_UNHEALTHY"="#660099", =="UNHEALTHY"="#cc0033", - =="UNHEALTHY_FOR_SENSITIVE"="#ff9933", + =="UNHEALTHY_FSG"="#ff9933", =="MODERATE"="#ffde33", =="GOOD"="#009966" ] @@ -159,16 +176,12 @@ sitemap airquality label="Air Quality" { } Frame { - Text item=Aqi_LocationName Text item=Aqi_ObservationTime Text item=Aqi_Temperature Text item=Aqi_Pressure Text item=Aqi_Humidity } - Frame label="Station Location" { - Mapview item=Aqi_StationGeo height=10 - } } ``` @@ -189,7 +202,7 @@ then hsb = "280,100,60" case "UNHEALTHY": hsb = "345,100,80" - case "UNHEALTHY_FOR_SENSITIVE": + case "UNHEALTHY_FSG": hsb = "30,80,100" case "MODERATE": hsb = "50,80,100" diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityBindingConstants.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityBindingConstants.java index 0bb6f84476aee..d738cf83a05b9 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityBindingConstants.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityBindingConstants.java @@ -12,74 +12,44 @@ */ package org.openhab.binding.airquality.internal; -import static org.openhab.core.library.unit.MetricPrefix.HECTO; - -import java.util.Collections; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.measure.Unit; -import javax.measure.quantity.Dimensionless; -import javax.measure.quantity.Pressure; -import javax.measure.quantity.Temperature; - import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.library.types.StringType; -import org.openhab.core.library.unit.SIUnits; -import org.openhab.core.library.unit.Units; import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.types.State; /** * The {@link AirQualityBinding} class defines common constants, which are * used across the whole binding. * - * @author Kuba Wolanin - Initial contribution - * @author Łukasz Dywicki - Initial contribution + * @author Gaël L'hopital - Initial contribution */ @NonNullByDefault public class AirQualityBindingConstants { - public static final String BINDING_ID = "airquality"; + private static final String BINDING_ID = "airquality"; public static final String LOCAL = "local"; - // List of all Thing Type UIDs - public static final ThingTypeUID THING_TYPE_AQI = new ThingTypeUID(BINDING_ID, "aqi"); + // List of thing properties + public static final String ATTRIBUTIONS = "Attributions"; + public static final String DISTANCE = "Distance"; + + // List of all Channel groups id's + public static final String AQI = "aqi"; + public static final String SENSITIVE = "sensitive-group"; // List of all Channel id's - public static final String AQI = "aqiLevel"; - public static final String AQI_COLOR = "aqiColor"; - public static final String AQIDESCRIPTION = "aqiDescription"; - public static final String PM25 = "pm25"; - public static final String PM10 = "pm10"; - public static final String O3 = "o3"; - public static final String NO2 = "no2"; - public static final String CO = "co"; - public static final String SO2 = "so2"; - public static final String LOCATIONNAME = "locationName"; - public static final String STATIONLOCATION = "stationLocation"; - public static final String STATIONID = "stationId"; - public static final String OBSERVATIONTIME = "observationTime"; + public static final String INDEX = "index"; + public static final String VALUE = "value"; + public static final String ALERT_LEVEL = "alert-level"; public static final String TEMPERATURE = "temperature"; public static final String PRESSURE = "pressure"; public static final String HUMIDITY = "humidity"; - public static final String DOMINENTPOL = "dominentpol"; - - public static final State GOOD = new StringType("GOOD"); - public static final State MODERATE = new StringType("MODERATE"); - public static final State UNHEALTHY_FOR_SENSITIVE = new StringType("UNHEALTHY_FOR_SENSITIVE"); - public static final State UNHEALTHY = new StringType("UNHEALTHY"); - public static final State VERY_UNHEALTHY = new StringType("VERY_UNHEALTHY"); - public static final State HAZARDOUS = new StringType("HAZARDOUS"); - - public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_AQI); - public static final Set SUPPORTED_CHANNEL_IDS = Stream.of(AQI, AQIDESCRIPTION, PM25, PM10, O3, NO2, CO, SO2, - LOCATIONNAME, STATIONLOCATION, STATIONID, OBSERVATIONTIME, TEMPERATURE, PRESSURE, HUMIDITY) - .collect(Collectors.toSet()); - - // Units of measurement of the data delivered by the API - public static final Unit API_TEMPERATURE_UNIT = SIUnits.CELSIUS; - public static final Unit API_HUMIDITY_UNIT = Units.PERCENT; - public static final Unit API_PRESSURE_UNIT = HECTO(SIUnits.PASCAL); + public static final String DEW_POINT = "dew-point"; + public static final String WIND_SPEED = "wind-speed"; + public static final String TIMESTAMP = "timestamp"; + public static final String DOMINENT = "dominent"; + public static final String ICON = "icon"; + public static final String COLOR = "color"; + + // Thing Type UIDs + public static final ThingTypeUID THING_TYPE_STATION = new ThingTypeUID(BINDING_ID, "station"); + public static final ThingTypeUID BRIDGE_TYPE_API = new ThingTypeUID(BINDING_ID, "api"); } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityException.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityException.java new file mode 100644 index 0000000000000..57be6ca59953d --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityException.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * An exception that occurred while operating the binding + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class AirQualityException extends Exception { + private static final long serialVersionUID = -3398100220952729815L; + private int statusCode = -1; + + public AirQualityException(String message, Exception e) { + super(message, e); + } + + public AirQualityException(String message) { + super(message); + } + + public int getStatusCode() { + return statusCode; + } + + @Override + public @Nullable String getMessage() { + String message = super.getMessage(); + return message == null ? null + : String.format("Rest call failed: statusCode=%d, message=%s", statusCode, message); + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityHandlerFactory.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityHandlerFactory.java index b9bfa09ff480f..8b54f9b0ee118 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityHandlerFactory.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityHandlerFactory.java @@ -14,10 +14,15 @@ import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*; +import java.util.Set; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.airquality.internal.handler.AirQualityHandler; +import org.openhab.binding.airquality.internal.handler.AirQualityBridgeHandler; +import org.openhab.binding.airquality.internal.handler.AirQualityStationHandler; +import org.openhab.core.i18n.LocationProvider; import org.openhab.core.i18n.TimeZoneProvider; +import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; @@ -27,23 +32,25 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; -import com.google.gson.Gson; - /** - * The {@link AirQualityHandlerFactory} is responsible for creating things and thing - * handlers. + * The {@link AirQualityHandlerFactory} is responsible for creating thing and thing + * handler. * - * @author Kuba Wolanin - Initial contribution + * @author Gaël L'hopital - Initial contribution */ @Component(service = ThingHandlerFactory.class, configurationPid = "binding.airquality") @NonNullByDefault public class AirQualityHandlerFactory extends BaseThingHandlerFactory { - private final Gson gson = new Gson(); + private static final Set SUPPORTED_THING_TYPES = Set.of(BRIDGE_TYPE_API, THING_TYPE_STATION); + private final TimeZoneProvider timeZoneProvider; + private final LocationProvider locationProvider; @Activate - public AirQualityHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider) { + public AirQualityHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider, + final @Reference LocationProvider locationProvider) { this.timeZoneProvider = timeZoneProvider; + this.locationProvider = locationProvider; } @Override @@ -55,10 +62,9 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (THING_TYPE_AQI.equals(thingTypeUID)) { - return new AirQualityHandler(thing, gson, timeZoneProvider); - } - - return null; + return THING_TYPE_STATION.equals(thingTypeUID) + ? new AirQualityStationHandler(thing, timeZoneProvider, locationProvider) + : BRIDGE_TYPE_API.equals(thingTypeUID) ? new AirQualityBridgeHandler((Bridge) thing, locationProvider) + : null; } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ApiBridge.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ApiBridge.java new file mode 100644 index 0000000000000..413a18b7aed98 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ApiBridge.java @@ -0,0 +1,88 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.api; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.airquality.internal.AirQualityException; +import org.openhab.binding.airquality.internal.api.dto.AirQualityData; +import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse; +import org.openhab.binding.airquality.internal.api.dto.AirQualityResponse.ResponseStatus; +import org.openhab.core.io.net.http.HttpUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link ApiBridge} is the interface between handlers + * and the actual web service + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class ApiBridge { + private static final Gson GSON = new Gson(); + private static final String URL = "http://api.waqi.info/feed/%query%/?token=%apiKey%"; + private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); + + private final Logger logger = LoggerFactory.getLogger(ApiBridge.class); + private final String apiKey; + + public ApiBridge(String apiKey) { + this.apiKey = apiKey; + } + + /** + * Build request URL from configuration data + * + * @return a valid URL for the aqicn.org service + * @throws AirQualityException + */ + private String buildRequestURL(String key, int stationId, String location) { + String geoStr = stationId != 0 ? String.format("@%d", stationId) + : String.format("geo:%s", + location.replace(" ", "").replace(",", ";").replace("\"", "").replace("'", "").trim()); + + return URL.replace("%apiKey%", key).replace("%query%", geoStr); + } + + /** + * Request new air quality data to the aqicn.org service + * + * @return an air quality data object mapping the JSON response + * @throws AirQualityException + */ + public AirQualityData getData(int stationId, String location, int retryCounter) throws AirQualityException { + String urlStr = buildRequestURL(apiKey, stationId, location); + logger.debug("URL = {}", urlStr); + + try { + String response = HttpUtil.executeUrl("GET", urlStr, null, null, null, REQUEST_TIMEOUT_MS); + logger.debug("aqiResponse = {}", response); + AirQualityResponse result = GSON.fromJson(response, AirQualityResponse.class); + if (result != null && result.getStatus() == ResponseStatus.OK) { + return result.getData(); + } else if (retryCounter == 0) { + logger.debug("Error in aqicn.org, retrying once"); + return getData(stationId, location, retryCounter + 1); + } + throw new AirQualityException("Error in aqicn.org response: Missing data sub-object"); + } catch (IOException | JsonSyntaxException e) { + throw new AirQualityException("Communication error", e); + } + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Appreciation.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Appreciation.java new file mode 100644 index 0000000000000..f80c71207e03f --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Appreciation.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.types.State; + +/** + * The {@link Appreciation} enum lists all possible appreciation + * of the AQI Level associated with their standard color. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public enum Appreciation { + GOOD(HSBType.fromRGB(0, 228, 0)), + MODERATE(HSBType.fromRGB(255, 255, 0)), + UNHEALTHY_FSG(HSBType.fromRGB(255, 126, 0)), + UNHEALTHY(HSBType.fromRGB(255, 0, 0)), + VERY_UNHEALTHY(HSBType.fromRGB(143, 63, 151)), + HAZARDOUS(HSBType.fromRGB(126, 0, 35)); + + private HSBType color; + + Appreciation(HSBType color) { + this.color = color; + } + + public State getColor() { + return color; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ConcentrationRange.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ConcentrationRange.java new file mode 100644 index 0000000000000..e40e42f556c47 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/ConcentrationRange.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link ConcentrationRange} is responsible to store the range of + * a given physical measure associated with the corresponding AQI + * index. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class ConcentrationRange { + private final double min; + private final double span; + private final Index index; + + ConcentrationRange(double min, double max, Index index) { + this.min = min; + this.span = max - min; + this.index = index; + } + + /* + * Computes the concentration corresponding to the index + * if contained in the range + * + * @return : a physical concentration or -1 if not in range + */ + double getConcentration(double idx) { + return index.contains(idx) ? span / index.getSpan() * (idx - index.getMin()) + min : -1; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Index.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Index.java new file mode 100644 index 0000000000000..09b7ed65c5646 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Index.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.api; + +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link Index} enum lists standard ranges of AQI indices + * along with their appreciation category. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public enum Index { + ZERO(0, 50, Appreciation.GOOD), + FIFTY(51, 100, Appreciation.MODERATE), + ONE_HUNDRED(101, 150, Appreciation.UNHEALTHY_FSG), + ONE_HUNDRED_FIFTY(151, 200, Appreciation.UNHEALTHY), + TWO_HUNDRED(201, 300, Appreciation.VERY_UNHEALTHY), + THREE_HUNDRED(301, 400, Appreciation.HAZARDOUS), + FOUR_HUNDRED(401, 500, Appreciation.HAZARDOUS); + + private double min; + private double max; + private Appreciation category; + + Index(double min, double max, Appreciation category) { + this.min = min; + this.max = max; + this.category = category; + } + + public double getMin() { + return min; + } + + public double getSpan() { + return max - min; + } + + boolean contains(double idx) { + return min <= idx && idx <= max; + } + + public static @Nullable Index find(double idx) { + return Stream.of(Index.values()).filter(i -> i.contains(idx)).findFirst().orElse(null); + } + + public Appreciation getCategory() { + return category; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Pollutant.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Pollutant.java new file mode 100644 index 0000000000000..e82c971dddf6d --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/Pollutant.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.api; + +import static org.openhab.binding.airquality.internal.api.Index.*; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Set; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * The {@link Pollutant} enum lists all measures + * of the AQI Level associated with their standard color. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public enum Pollutant { + PM25(Units.MICROGRAM_PER_CUBICMETRE, 1, + Set.of(SensitiveGroup.RESPIRATORY, SensitiveGroup.HEART, SensitiveGroup.ELDERLY, SensitiveGroup.CHILDREN), + new ConcentrationRange(0, 12, ZERO), new ConcentrationRange(12.1, 35.4, FIFTY), + new ConcentrationRange(35.5, 55.4, ONE_HUNDRED), new ConcentrationRange(55.5, 150.4, ONE_HUNDRED_FIFTY), + new ConcentrationRange(150.5, 250.4, TWO_HUNDRED), new ConcentrationRange(250.5, 350.4, THREE_HUNDRED), + new ConcentrationRange(350.5, 500.4, FOUR_HUNDRED)), + PM10(Units.MICROGRAM_PER_CUBICMETRE, 0, Set.of(SensitiveGroup.RESPIRATORY), new ConcentrationRange(0, 54, ZERO), + new ConcentrationRange(55, 154, FIFTY), new ConcentrationRange(155, 254, ONE_HUNDRED), + new ConcentrationRange(255, 354, ONE_HUNDRED_FIFTY), new ConcentrationRange(355, 424, TWO_HUNDRED), + new ConcentrationRange(425, 504, THREE_HUNDRED), new ConcentrationRange(505, 604, FOUR_HUNDRED)), + NO2(Units.PARTS_PER_BILLION, 0, + Set.of(SensitiveGroup.ASTHMA, SensitiveGroup.RESPIRATORY, SensitiveGroup.ELDERLY, SensitiveGroup.CHILDREN), + new ConcentrationRange(0, 53, ZERO), new ConcentrationRange(54, 100, FIFTY), + new ConcentrationRange(101, 360, ONE_HUNDRED), new ConcentrationRange(361, 649, ONE_HUNDRED_FIFTY), + new ConcentrationRange(650, 1249, TWO_HUNDRED), new ConcentrationRange(1250, 1649, THREE_HUNDRED), + new ConcentrationRange(1650, 2049, FOUR_HUNDRED)), + SO2(Units.PARTS_PER_BILLION, 0, Set.of(SensitiveGroup.ASTHMA), new ConcentrationRange(0, 35, ZERO), + new ConcentrationRange(36, 75, FIFTY), new ConcentrationRange(76, 185, ONE_HUNDRED), + new ConcentrationRange(186, 304, ONE_HUNDRED_FIFTY), new ConcentrationRange(305, 604, TWO_HUNDRED), + new ConcentrationRange(605, 804, THREE_HUNDRED), new ConcentrationRange(805, 1004, FOUR_HUNDRED)), + CO(Units.PARTS_PER_BILLION, 1, Set.of(SensitiveGroup.HEART), new ConcentrationRange(0, 4.4, ZERO), + new ConcentrationRange(4.5, 9.4, FIFTY), new ConcentrationRange(9.5, 12.4, ONE_HUNDRED), + new ConcentrationRange(12.5, 15.4, ONE_HUNDRED_FIFTY), new ConcentrationRange(15.5, 30.4, TWO_HUNDRED), + new ConcentrationRange(30.5, 40.4, THREE_HUNDRED), new ConcentrationRange(40.5, 50.4, FOUR_HUNDRED)), + O3(Units.PARTS_PER_BILLION, 3, Set.of(SensitiveGroup.CHILDREN, SensitiveGroup.ASTHMA), + new ConcentrationRange(0, 54, ZERO), new ConcentrationRange(55, 124, FIFTY), + new ConcentrationRange(125, 164, ONE_HUNDRED), new ConcentrationRange(165, 204, ONE_HUNDRED_FIFTY), + new ConcentrationRange(205, 404, TWO_HUNDRED), new ConcentrationRange(405, 504, THREE_HUNDRED), + new ConcentrationRange(505, 604, FOUR_HUNDRED)); + + public static enum SensitiveGroup { + RESPIRATORY, + HEART, + ELDERLY, + CHILDREN, + ASTHMA; + } + + public final Set sensitiveGroups; + private final Unit unit; + private final Set breakpoints; + private final int scale; + + Pollutant(Unit unit, int scale, Set groups, ConcentrationRange... concentrations) { + this.sensitiveGroups = groups; + this.unit = unit; + this.breakpoints = Set.of(concentrations); + this.scale = scale; + } + + public State toQuantity(double idx) { + for (ConcentrationRange concentration : breakpoints) { + double equivalent = concentration.getConcentration(idx); + if (equivalent != -1) { + return new QuantityType<>(BigDecimal.valueOf(equivalent).setScale(scale, RoundingMode.HALF_UP), unit); + } + } + return UnDefType.UNDEF; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonCity.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityCity.java similarity index 81% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonCity.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityCity.java index d4455479a72f0..9789933735456 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonCity.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityCity.java @@ -10,9 +10,8 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -20,17 +19,16 @@ import org.eclipse.jdt.annotation.Nullable; /** - * The {@link AirQualityJsonCity} is responsible for storing + * The {@link AirQualityCity} is responsible for storing * the "city" node from the waqi.org JSON response * * @author Kuba Wolanin - Initial contribution */ @NonNullByDefault -public class AirQualityJsonCity { - +public class AirQualityCity { private String name = ""; private @Nullable String url; - private List geo = new ArrayList<>(); + private List geo = List.of(); public String getName() { return name; diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonData.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityData.java similarity index 65% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonData.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityData.java index 6ebd8890d8ee8..49998a7128853 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonData.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityData.java @@ -10,32 +10,30 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.airquality.internal.api.Pollutant; /** - * The {@link AirQualityJsonData} is responsible for storing + * The {@link AirQualityData} is responsible for storing * the "data" node from the waqi.org JSON response * * @author Kuba Wolanin - Initial contribution */ @NonNullByDefault -public class AirQualityJsonData { - +public class AirQualityData { private int aqi; private int idx; - private @NonNullByDefault({}) AirQualityJsonTime time; - private @NonNullByDefault({}) AirQualityJsonCity city; - private List attributions = new ArrayList<>(); - private Map iaqi = new HashMap<>(); + private @NonNullByDefault({}) AirQualityTime time; + private @NonNullByDefault({}) AirQualityCity city; + private List attributions = List.of(); + private Map iaqi = Map.of(); private String dominentpol = ""; /** @@ -61,7 +59,7 @@ public int getStationId() { * * @return {AirQualityJsonTime} */ - public AirQualityJsonTime getTime() { + public AirQualityTime getTime() { return time; } @@ -70,20 +68,18 @@ public AirQualityJsonTime getTime() { * * @return {AirQualityJsonCity} */ - public AirQualityJsonCity getCity() { + public AirQualityCity getCity() { return city; } /** * Collects a list of attributions (vendors making data available) * and transforms it into readable string. - * Currently displayed in Thing Status description when ONLINE * * @return {String} */ public String getAttributions() { - String attributionsString = attributions.stream().map(Attribute::getName).collect(Collectors.joining(", ")); - return "Attributions : " + attributionsString; + return attributions.stream().map(Attribution::getName).collect(Collectors.joining(", ")); } public String getDominentPol() { @@ -92,9 +88,10 @@ public String getDominentPol() { public double getIaqiValue(String key) { AirQualityValue result = iaqi.get(key); - if (result != null) { - return result.getValue(); - } - return -1; + return result != null ? result.getValue() : -1; + } + + public double getIaqiValue(Pollutant pollutant) { + return getIaqiValue(pollutant.name().toLowerCase()); } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonResponse.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityResponse.java similarity index 75% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonResponse.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityResponse.java index 3fec19c5217b7..9a00008f854a1 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonResponse.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityResponse.java @@ -10,20 +10,20 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; import org.eclipse.jdt.annotation.NonNullByDefault; import com.google.gson.annotations.SerializedName; /** - * The {@link AirQualityJsonResponse} is the Java class used to map the JSON + * The {@link AirQualityResponse} is the Java class used to map the JSON * response to the aqicn.org request. * * @author Kuba Wolanin - Initial contribution */ @NonNullByDefault -public class AirQualityJsonResponse { +public class AirQualityResponse { public static enum ResponseStatus { NONE, @@ -34,15 +34,13 @@ public static enum ResponseStatus { } private ResponseStatus status = ResponseStatus.NONE; - - @SerializedName("data") - private @NonNullByDefault({}) AirQualityJsonData data; + private @NonNullByDefault({}) AirQualityData data; public ResponseStatus getStatus() { return status; } - public AirQualityJsonData getData() { + public AirQualityData getData() { return data; } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonTime.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityTime.java similarity index 63% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonTime.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityTime.java index d2faa6199b49c..4a455412deec0 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityJsonTime.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityTime.java @@ -10,32 +10,22 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import org.eclipse.jdt.annotation.NonNullByDefault; -import com.google.gson.annotations.SerializedName; - /** - * The {@link AirQualityJsonTime} is responsible for storing + * The {@link AirQualityTime} is responsible for storing * the "time" node from the waqi.org JSON response * - * @author Kuba Wolanin - Initial contribution - * @author Gaël L'hopital - Use ZonedDateTime instead of Calendar + * @author Gaël L'hopital - Initial contribution */ @NonNullByDefault -public class AirQualityJsonTime { - - @SerializedName("s") - private String dateString = ""; - - @SerializedName("tz") - private String timeZone = ""; - - private String iso = ""; +public class AirQualityTime { + private String iso = ""; // ISO representation of the timestamp, including TZ /** * Get observation time diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityValue.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityValue.java similarity index 74% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityValue.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityValue.java index df72ea85d88f0..bddfb58bc8429 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/AirQualityValue.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/AirQualityValue.java @@ -10,24 +10,20 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; import org.eclipse.jdt.annotation.NonNullByDefault; -import com.google.gson.annotations.SerializedName; - /** * Wrapper type around values reported by aqicn index values. * * @author Łukasz Dywicki - Initial contribution */ @NonNullByDefault -public class AirQualityValue { - - @SerializedName("v") - private double value; +class AirQualityValue { + private double v; public double getValue() { - return value; + return v; } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/Attribute.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/Attribution.java similarity index 91% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/Attribute.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/Attribution.java index 4db98ccb7ac00..85d49f7379241 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/json/Attribute.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/api/dto/Attribution.java @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal.json; +package org.openhab.binding.airquality.internal.api.dto; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -21,8 +21,7 @@ * @author Łukasz Dywicki - Initial contribution */ @NonNullByDefault -public class Attribute { - +class Attribution { private @NonNullByDefault({}) String name; private @Nullable String url; private @Nullable String logo; diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityConfiguration.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/AirQualityConfiguration.java similarity index 56% rename from bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityConfiguration.java rename to bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/AirQualityConfiguration.java index 61efbc56c5285..dbad96a7b2c26 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/AirQualityConfiguration.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/AirQualityConfiguration.java @@ -10,10 +10,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ -package org.openhab.binding.airquality.internal; +package org.openhab.binding.airquality.internal.config; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airquality.internal.AirQualityException; /** * The {@link AirQualityConfiguration} is the class used to match the @@ -23,11 +23,19 @@ */ @NonNullByDefault public class AirQualityConfiguration { - public static final String LOCATION = "location"; + public static final String STATION_ID = "stationId"; - public String apikey = ""; public String location = ""; - public @Nullable Integer stationId; + public int stationId = 0; public int refresh = 60; + + public void checkValid() throws AirQualityException { + if (location.trim().isEmpty() && stationId == 0) { + throw new AirQualityException("Either 'location' or 'stationId' is mandatory and must be configured"); + } + if (refresh < 30) { + throw new AirQualityException("Parameter 'refresh' must be at least 30 minutes"); + } + } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/SensitiveGroupConfiguration.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/SensitiveGroupConfiguration.java new file mode 100644 index 0000000000000..09e376cea9d07 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/config/SensitiveGroupConfiguration.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airquality.internal.api.Pollutant.SensitiveGroup; + +/** + * The {@link SensitiveGroupConfiguration} is the class used to match the + * sensitive-group channel configuration. + * + * @author Gaël L"hopital - Initial contribution + */ +@NonNullByDefault +public class SensitiveGroupConfiguration { + private String group = "RESPIRATORY"; + + public @Nullable SensitiveGroup asSensitiveGroup() { + try { + SensitiveGroup value = SensitiveGroup.valueOf(group); + return value; + } catch (IllegalArgumentException e) { + return null; + } + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/discovery/AirQualityDiscoveryService.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/discovery/AirQualityDiscoveryService.java index 0da240541e105..85cef9c804871 100644 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/discovery/AirQualityDiscoveryService.java +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/discovery/AirQualityDiscoveryService.java @@ -13,26 +13,24 @@ package org.openhab.binding.airquality.internal.discovery; import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*; -import static org.openhab.binding.airquality.internal.AirQualityConfiguration.LOCATION; +import static org.openhab.binding.airquality.internal.config.AirQualityConfiguration.LOCATION; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.Collections; +import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airquality.internal.handler.AirQualityBridgeHandler; import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.i18n.LocationProvider; import org.openhab.core.library.types.PointType; +import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; -import org.osgi.service.component.annotations.Activate; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Modified; -import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,80 +41,60 @@ */ @Component(service = DiscoveryService.class, configurationPid = "discovery.airquality") @NonNullByDefault -public class AirQualityDiscoveryService extends AbstractDiscoveryService { - private final Logger logger = LoggerFactory.getLogger(AirQualityDiscoveryService.class); +public class AirQualityDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { + private static final int DISCOVER_TIMEOUT_SECONDS = 2; + private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_STATION); - private static final int DISCOVER_TIMEOUT_SECONDS = 10; - private static final int LOCATION_CHANGED_CHECK_INTERVAL = 60; + private final Logger logger = LoggerFactory.getLogger(AirQualityDiscoveryService.class); - private final LocationProvider locationProvider; - private @Nullable ScheduledFuture discoveryJob; - private @Nullable PointType previousLocation; + private @Nullable LocationProvider locationProvider; + private @Nullable AirQualityBridgeHandler bridgeHandler; /** * Creates a AirQualityDiscoveryService with enabled autostart. */ - @Activate - public AirQualityDiscoveryService(@Reference LocationProvider locationProvider) { - super(SUPPORTED_THING_TYPES, DISCOVER_TIMEOUT_SECONDS, true); - this.locationProvider = locationProvider; + public AirQualityDiscoveryService() { + super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, false); } @Override - protected void activate(@Nullable Map configProperties) { - super.activate(configProperties); + public void setThingHandler(@Nullable ThingHandler handler) { + if (handler instanceof AirQualityBridgeHandler) { + final AirQualityBridgeHandler bridgeHandler = (AirQualityBridgeHandler) handler; + this.bridgeHandler = bridgeHandler; + this.locationProvider = bridgeHandler.getLocationProvider(); + } } @Override - @Modified - protected void modified(@Nullable Map configProperties) { - super.modified(configProperties); + public @Nullable ThingHandler getThingHandler() { + return bridgeHandler; } @Override - protected void startScan() { - logger.debug("Starting Air Quality discovery scan"); - PointType location = locationProvider.getLocation(); - if (location == null) { - logger.debug("LocationProvider.getLocation() is not set -> Will not provide any discovery results"); - return; - } - createResults(location); + public void deactivate() { + super.deactivate(); } @Override - protected void startBackgroundDiscovery() { - if (discoveryJob == null) { - discoveryJob = scheduler.scheduleWithFixedDelay(() -> { - PointType currentLocation = locationProvider.getLocation(); - if (currentLocation != null && !Objects.equals(currentLocation, previousLocation)) { - logger.debug("Location has been changed from {} to {}: Creating new discovery results", - previousLocation, currentLocation); - createResults(currentLocation); - previousLocation = currentLocation; - } - }, 0, LOCATION_CHANGED_CHECK_INTERVAL, TimeUnit.SECONDS); - logger.debug("Scheduled Air Qualitylocation-changed job every {} seconds", LOCATION_CHANGED_CHECK_INTERVAL); + protected void startScan() { + logger.debug("Starting Air Quality discovery scan"); + LocationProvider provider = locationProvider; + if (provider != null) { + PointType location = provider.getLocation(); + AirQualityBridgeHandler bridge = this.bridgeHandler; + if (location == null || bridge == null) { + logger.debug("LocationProvider.getLocation() is not set -> Will not provide any discovery results"); + return; + } + createResults(location, bridge.getThing().getUID()); } } - public void createResults(PointType location) { - ThingUID localAirQualityThing = new ThingUID(THING_TYPE_AQI, LOCAL); - Map properties = new HashMap<>(); - properties.put(LOCATION, String.format("%s,%s", location.getLatitude(), location.getLongitude())); + public void createResults(PointType location, ThingUID bridgeUID) { + ThingUID localAirQualityThing = new ThingUID(THING_TYPE_STATION, bridgeUID, LOCAL); thingDiscovered(DiscoveryResultBuilder.create(localAirQualityThing).withLabel("Local Air Quality") - .withProperties(properties).build()); - } - - @Override - protected void stopBackgroundDiscovery() { - logger.debug("Stopping Air Quality background discovery"); - ScheduledFuture job = this.discoveryJob; - if (job != null && !job.isCancelled()) { - if (job.cancel(true)) { - discoveryJob = null; - logger.debug("Stopped Air Quality background discovery"); - } - } + .withProperty(LOCATION, String.format("%s,%s", location.getLatitude(), location.getLongitude())) + .withBridge(bridgeUID).build()); } } diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityBridgeHandler.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityBridgeHandler.java new file mode 100644 index 0000000000000..75974083337d6 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityBridgeHandler.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.handler; + +import java.util.Collection; +import java.util.Collections; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airquality.internal.api.ApiBridge; +import org.openhab.binding.airquality.internal.discovery.AirQualityDiscoveryService; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.openhab.core.types.Command; + +/** + * The {@link AirQualityBridgeHandler} is responsible for handling communication + * with the service via the API. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class AirQualityBridgeHandler extends BaseBridgeHandler { + private final LocationProvider locationProvider; + private @Nullable ApiBridge apiBridge; + + public AirQualityBridgeHandler(Bridge bridge, LocationProvider locationProvider) { + super(bridge); + this.locationProvider = locationProvider; + } + + @Override + public void initialize() { + String apiKey = (String) getConfig().get("apiKey"); + if (apiKey != null && apiKey.length() != 0) { + apiBridge = new ApiBridge(apiKey); + updateStatus(ThingStatus.ONLINE); + } else { + apiBridge = null; + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/null-or-empty-api-key"); + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // We do nothing + } + + public @Nullable ApiBridge getApiBridge() { + return apiBridge; + } + + @Override + public Collection> getServices() { + return Collections.singleton(AirQualityDiscoveryService.class); + } + + public LocationProvider getLocationProvider() { + return locationProvider; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityHandler.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityHandler.java deleted file mode 100644 index 3caf969eddc2f..0000000000000 --- a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityHandler.java +++ /dev/null @@ -1,285 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.airquality.internal.handler; - -import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.airquality.internal.AirQualityConfiguration; -import org.openhab.binding.airquality.internal.json.AirQualityJsonData; -import org.openhab.binding.airquality.internal.json.AirQualityJsonResponse; -import org.openhab.binding.airquality.internal.json.AirQualityJsonResponse.ResponseStatus; -import org.openhab.core.i18n.TimeZoneProvider; -import org.openhab.core.io.net.http.HttpUtil; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.HSBType; -import org.openhab.core.library.types.PointType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StringType; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.openhab.core.thing.binding.BaseThingHandler; -import org.openhab.core.types.Command; -import org.openhab.core.types.RefreshType; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; - -/** - * The {@link AirQualityHandler} is responsible for handling commands, which are - * sent to one of the channels. - * - * @author Kuba Wolanin - Initial contribution - * @author Łukasz Dywicki - Initial contribution - */ -@NonNullByDefault -public class AirQualityHandler extends BaseThingHandler { - private static final String URL = "http://api.waqi.info/feed/%QUERY%/?token=%apikey%"; - private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); - private final Logger logger = LoggerFactory.getLogger(AirQualityHandler.class); - private @Nullable ScheduledFuture refreshJob; - - private final Gson gson; - - private int retryCounter = 0; - private final TimeZoneProvider timeZoneProvider; - - public AirQualityHandler(Thing thing, Gson gson, TimeZoneProvider timeZoneProvider) { - super(thing); - this.gson = gson; - this.timeZoneProvider = timeZoneProvider; - } - - @Override - public void initialize() { - logger.debug("Initializing Air Quality handler."); - - AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class); - logger.debug("config apikey = (omitted from logging)"); - logger.debug("config location = {}", config.location); - logger.debug("config stationId = {}", config.stationId); - logger.debug("config refresh = {}", config.refresh); - - List errorMsg = new ArrayList<>(); - - if (config.apikey.trim().isEmpty()) { - errorMsg.add("Parameter 'apikey' is mandatory and must be configured"); - } - if (config.location.trim().isEmpty() && config.stationId == null) { - errorMsg.add("Parameter 'location' or 'stationId' is mandatory and must be configured"); - } - if (config.refresh < 30) { - errorMsg.add("Parameter 'refresh' must be at least 30 minutes"); - } - - if (errorMsg.isEmpty()) { - ScheduledFuture job = this.refreshJob; - if (job == null || job.isCancelled()) { - refreshJob = scheduler.scheduleWithFixedDelay(this::updateAndPublishData, 0, config.refresh, - TimeUnit.MINUTES); - } - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.join(", ", errorMsg)); - } - } - - private void updateAndPublishData() { - retryCounter = 0; - AirQualityJsonData aqiResponse = getAirQualityData(); - if (aqiResponse != null) { - // Update all channels from the updated AQI data - getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID().getId())).forEach(channel -> { - String channelId = channel.getUID().getId(); - State state = getValue(channelId, aqiResponse); - updateState(channelId, state); - }); - } - } - - @Override - public void dispose() { - logger.debug("Disposing the Air Quality handler."); - ScheduledFuture job = this.refreshJob; - if (job != null && !job.isCancelled()) { - job.cancel(true); - refreshJob = null; - } - } - - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (command instanceof RefreshType) { - updateAndPublishData(); - } else { - logger.debug("The Air Quality binding is read-only and can not handle command {}", command); - } - } - - /** - * Build request URL from configuration data - * - * @return a valid URL for the aqicn.org service - */ - private String buildRequestURL() { - AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class); - - String location = config.location.trim(); - Integer stationId = config.stationId; - - String geoStr = "geo:" + location.replace(" ", "").replace(",", ";").replace("\"", "").replace("'", "").trim(); - - String urlStr = URL.replace("%apikey%", config.apikey.trim()); - - return urlStr.replace("%QUERY%", stationId == null ? geoStr : "@" + stationId); - } - - /** - * Request new air quality data to the aqicn.org service - * - * @param location geo-coordinates from config - * @param stationId station ID from config - * @return the air quality data object mapping the JSON response or null in case of error - */ - private @Nullable AirQualityJsonData getAirQualityData() { - String errorMsg; - - String urlStr = buildRequestURL(); - logger.debug("URL = {}", urlStr); - - try { - String response = HttpUtil.executeUrl("GET", urlStr, null, null, null, REQUEST_TIMEOUT_MS); - logger.debug("aqiResponse = {}", response); - AirQualityJsonResponse result = gson.fromJson(response, AirQualityJsonResponse.class); - if (result.getStatus() == ResponseStatus.OK) { - AirQualityJsonData data = result.getData(); - String attributions = data.getAttributions(); - updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, attributions); - return data; - } else { - retryCounter++; - if (retryCounter == 1) { - logger.warn("Error in aqicn.org, retrying once"); - return getAirQualityData(); - } - errorMsg = "Missing data sub-object"; - logger.warn("Error in aqicn.org response: {}", errorMsg); - } - } catch (IOException e) { - errorMsg = e.getMessage(); - } catch (JsonSyntaxException e) { - errorMsg = "Configuration is incorrect"; - logger.warn("Error running aqicn.org request: {}", errorMsg); - } - - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errorMsg); - return null; - } - - public State getValue(String channelId, AirQualityJsonData aqiResponse) { - String[] fields = channelId.split("#"); - - switch (fields[0]) { - case AQI: - return new DecimalType(aqiResponse.getAqi()); - case AQIDESCRIPTION: - return getAqiDescription(aqiResponse.getAqi()); - case PM25: - case PM10: - case O3: - case NO2: - case CO: - case SO2: - double value = aqiResponse.getIaqiValue(fields[0]); - return value != -1 ? new DecimalType(value) : UnDefType.UNDEF; - case TEMPERATURE: - double temp = aqiResponse.getIaqiValue("t"); - return temp != -1 ? new QuantityType<>(temp, API_TEMPERATURE_UNIT) : UnDefType.UNDEF; - case PRESSURE: - double press = aqiResponse.getIaqiValue("p"); - return press != -1 ? new QuantityType<>(press, API_PRESSURE_UNIT) : UnDefType.UNDEF; - case HUMIDITY: - double hum = aqiResponse.getIaqiValue("h"); - return hum != -1 ? new QuantityType<>(hum, API_HUMIDITY_UNIT) : UnDefType.UNDEF; - case LOCATIONNAME: - return new StringType(aqiResponse.getCity().getName()); - case STATIONID: - return new DecimalType(aqiResponse.getStationId()); - case STATIONLOCATION: - return new PointType(aqiResponse.getCity().getGeo()); - case OBSERVATIONTIME: - return new DateTimeType( - aqiResponse.getTime().getObservationTime().withZoneSameLocal(timeZoneProvider.getTimeZone())); - case DOMINENTPOL: - return new StringType(aqiResponse.getDominentPol()); - case AQI_COLOR: - return getAsHSB(aqiResponse.getAqi()); - default: - return UnDefType.UNDEF; - } - } - - /** - * Interprets the current aqi value within the ranges; - * Returns AQI in a human readable format - * - * @return - */ - public State getAqiDescription(int index) { - if (index >= 300) { - return HAZARDOUS; - } else if (index >= 201) { - return VERY_UNHEALTHY; - } else if (index >= 151) { - return UNHEALTHY; - } else if (index >= 101) { - return UNHEALTHY_FOR_SENSITIVE; - } else if (index >= 51) { - return MODERATE; - } else if (index > 0) { - return GOOD; - } - return UnDefType.UNDEF; - } - - private State getAsHSB(int index) { - State state = getAqiDescription(index); - if (state == HAZARDOUS) { - return HSBType.fromRGB(343, 100, 49); - } else if (state == VERY_UNHEALTHY) { - return HSBType.fromRGB(280, 100, 60); - } else if (state == UNHEALTHY) { - return HSBType.fromRGB(345, 100, 80); - } else if (state == UNHEALTHY_FOR_SENSITIVE) { - return HSBType.fromRGB(30, 80, 100); - } else if (state == MODERATE) { - return HSBType.fromRGB(50, 80, 100); - } else if (state == GOOD) { - return HSBType.fromRGB(160, 100, 60); - } - return UnDefType.UNDEF; - } -} diff --git a/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityStationHandler.java b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityStationHandler.java new file mode 100644 index 0000000000000..90a83321dd35d --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/java/org/openhab/binding/airquality/internal/handler/AirQualityStationHandler.java @@ -0,0 +1,298 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.airquality.internal.handler; + +import static org.openhab.binding.airquality.internal.AirQualityBindingConstants.*; +import static org.openhab.core.library.unit.MetricPrefix.*; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airquality.internal.AirQualityException; +import org.openhab.binding.airquality.internal.api.ApiBridge; +import org.openhab.binding.airquality.internal.api.Appreciation; +import org.openhab.binding.airquality.internal.api.Index; +import org.openhab.binding.airquality.internal.api.Pollutant; +import org.openhab.binding.airquality.internal.api.Pollutant.SensitiveGroup; +import org.openhab.binding.airquality.internal.api.dto.AirQualityData; +import org.openhab.binding.airquality.internal.config.AirQualityConfiguration; +import org.openhab.binding.airquality.internal.config.SensitiveGroupConfiguration; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.i18n.TimeZoneProvider; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PointType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.RawType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.BridgeHandler; +import org.openhab.core.thing.binding.builder.ThingBuilder; +import org.openhab.core.thing.type.ChannelTypeUID; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link AirQualityStationHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Kuba Wolanin - Initial contribution + * @author Łukasz Dywicki - Initial contribution + */ +@NonNullByDefault +public class AirQualityStationHandler extends BaseThingHandler { + private final @NonNullByDefault({}) ClassLoader classLoader = AirQualityStationHandler.class.getClassLoader(); + private final Logger logger = LoggerFactory.getLogger(AirQualityStationHandler.class); + private final TimeZoneProvider timeZoneProvider; + private final LocationProvider locationProvider; + + private @Nullable ScheduledFuture refreshJob; + + public AirQualityStationHandler(Thing thing, TimeZoneProvider timeZoneProvider, LocationProvider locationProvider) { + super(thing); + this.timeZoneProvider = timeZoneProvider; + this.locationProvider = locationProvider; + } + + @Override + public void initialize() { + logger.debug("Initializing Air Quality handler."); + + if (thing.getProperties().isEmpty()) { + discoverAttributes(); + } + + AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class); + try { + config.checkValid(); + freeRefreshJob(); + refreshJob = scheduler.scheduleWithFixedDelay(this::updateAndPublishData, 0, config.refresh, + TimeUnit.MINUTES); + } catch (AirQualityException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + } + } + + private void discoverAttributes() { + getAirQualityData().ifPresent(data -> { + // Update thing properties + Map properties = new HashMap<>(); + properties.put(ATTRIBUTIONS, data.getAttributions()); + PointType serverLocation = locationProvider.getLocation(); + if (serverLocation != null) { + PointType stationLocation = new PointType(data.getCity().getGeo()); + double distance = serverLocation.distanceFrom(stationLocation).doubleValue(); + properties.put(DISTANCE, new QuantityType<>(distance / 1000, KILO(SIUnits.METRE)).toString()); + } + + // Search and remove missing pollutant channels + List channels = new ArrayList<>(getThing().getChannels()); + Stream.of(Pollutant.values()).forEach(pollutant -> { + String groupName = pollutant.name().toLowerCase(); + double value = data.getIaqiValue(pollutant); + channels.removeIf(channel -> value == -1 && groupName.equals(channel.getUID().getGroupId())); + }); + + // Update thing configuration + Configuration config = editConfiguration(); + config.put(AirQualityConfiguration.STATION_ID, data.getStationId()); + + ThingBuilder thingBuilder = editThing(); + thingBuilder.withChannels(channels).withConfiguration(config).withProperties(properties) + .withLocation(data.getCity().getName()); + updateThing(thingBuilder.build()); + }); + } + + private void updateAndPublishData() { + getAirQualityData().ifPresent(data -> { + getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID().getId())).forEach(channel -> { + State state; + ChannelUID channelUID = channel.getUID(); + ChannelTypeUID channelTypeUID = channel.getChannelTypeUID(); + if (channelTypeUID != null && SENSITIVE.equals(channelTypeUID.getId().toString())) { + SensitiveGroupConfiguration configuration = channel.getConfiguration() + .as(SensitiveGroupConfiguration.class); + state = getSensitive(configuration.asSensitiveGroup(), data); + } else { + state = getValue(channelUID.getIdWithoutGroup(), channelUID.getGroupId(), data); + } + updateState(channelUID, state); + }); + }); + } + + @Override + public void dispose() { + logger.debug("Disposing the Air Quality handler."); + freeRefreshJob(); + } + + private void freeRefreshJob() { + ScheduledFuture job = this.refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); + refreshJob = null; + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + updateAndPublishData(); + return; + } + logger.debug("The Air Quality binding is read-only and can not handle command {}", command); + } + + /** + * Request new air quality data to the aqicn.org service + * + * @return an optional air quality data object mapping the JSON response + */ + private Optional getAirQualityData() { + AirQualityData result = null; + ApiBridge apiBridge = getApiBridge(); + if (apiBridge != null) { + AirQualityConfiguration config = getConfigAs(AirQualityConfiguration.class); + try { + result = apiBridge.getData(config.stationId, config.location, 0); + updateStatus(ThingStatus.ONLINE); + } catch (AirQualityException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage()); + } + } + return Optional.ofNullable(result); + } + + private @Nullable ApiBridge getApiBridge() { + Bridge bridge = this.getBridge(); + if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) { + BridgeHandler handler = bridge.getHandler(); + if (handler instanceof AirQualityBridgeHandler) { + return ((AirQualityBridgeHandler) handler).getApiBridge(); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/incorrect-bridge"); + } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + } + return null; + } + + private State indexedValue(String channelId, double idx, @Nullable Pollutant pollutant) { + Index index = Index.find(idx); + if (index != null) { + switch (channelId) { + case INDEX: + return new DecimalType(idx); + case VALUE: + return pollutant != null ? pollutant.toQuantity(idx) : UnDefType.UNDEF; + case ICON: + byte[] bytes = getResource(String.format("picto/%s.svg", index.getCategory().name().toLowerCase())); + return bytes != null ? new RawType(bytes, "image/svg+xml") : UnDefType.UNDEF; + case COLOR: + return index.getCategory().getColor(); + case ALERT_LEVEL: + return new DecimalType(index.getCategory().ordinal()); + } + } + return UnDefType.UNDEF; + } + + private State getSensitive(@Nullable SensitiveGroup sensitiveGroup, AirQualityData data) { + if (sensitiveGroup != null) { + int threshHold = Appreciation.UNHEALTHY_FSG.ordinal(); + for (Pollutant pollutant : Pollutant.values()) { + Index index = Index.find(data.getIaqiValue(pollutant)); + if (index != null && pollutant.sensitiveGroups.contains(sensitiveGroup) + && index.getCategory().ordinal() >= threshHold) { + return OnOffType.ON; + } + } + return OnOffType.OFF; + } + return UnDefType.NULL; + } + + private State getValue(String channelId, @Nullable String groupId, AirQualityData data) { + switch (channelId) { + case TEMPERATURE: + double temp = data.getIaqiValue("t"); + return temp != -1 ? new QuantityType<>(temp, SIUnits.CELSIUS) : UnDefType.UNDEF; + case PRESSURE: + double press = data.getIaqiValue("p"); + return press != -1 ? new QuantityType<>(press, HECTO(SIUnits.PASCAL)) : UnDefType.UNDEF; + case HUMIDITY: + double hum = data.getIaqiValue("h"); + return hum != -1 ? new QuantityType<>(hum, Units.PERCENT) : UnDefType.UNDEF; + case TIMESTAMP: + return new DateTimeType( + data.getTime().getObservationTime().withZoneSameLocal(timeZoneProvider.getTimeZone())); + case DOMINENT: + return new StringType(data.getDominentPol()); + case DEW_POINT: + double dp = data.getIaqiValue("dew"); + return dp != -1 ? new QuantityType<>(dp, SIUnits.CELSIUS) : UnDefType.UNDEF; + case WIND_SPEED: + double w = data.getIaqiValue("w"); + return w != -1 ? new QuantityType<>(w, Units.METRE_PER_SECOND) : UnDefType.UNDEF; + default: + if (groupId != null) { + double idx = -1; + Pollutant pollutant = null; + if (AQI.equals(groupId)) { + idx = data.getAqi(); + } else { + pollutant = Pollutant.valueOf(groupId.toUpperCase()); + idx = data.getIaqiValue(pollutant); + } + return indexedValue(channelId, idx, pollutant); + } + return UnDefType.UNDEF; + } + } + + private byte @Nullable [] getResource(String iconPath) { + try (InputStream stream = classLoader.getResourceAsStream(iconPath)) { + return stream != null ? stream.readAllBytes() : null; + } catch (IOException e) { + logger.warn("Unable to load ressource '{}' : {}", iconPath, e.getMessage()); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/binding/binding.xml index d0cdc8c3812b8..09d63db67533c 100644 --- a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/binding/binding.xml +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/binding/binding.xml @@ -4,6 +4,5 @@ xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd"> Air Quality Binding - Measure Air Quality Index and details about pollution particles for a given location diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality.properties b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality.properties new file mode 100644 index 0000000000000..776d424613a09 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality.properties @@ -0,0 +1,62 @@ +# binding +binding.airquality.name = Air Quality Binding +binding.airquality.description = Measure Air Quality Index and details about pollution particles for a given location. + +# thing types +thing-type.airquality.api.label = Air Quality API +thing-type.airquality.api.description = Bridge to the Air Quality API service. +thing-type.airquality.station.label = Air Quality Station +thing-type.airquality.station.description = Provides various air quality data from the World Air Quality Project. In order to receive the data, you must register an account on http://aqicn.org/data-platform/token/ and get your API token. + +# thing types config +thing-type.config.airquality.api.apiKey.label = API Key +thing-type.config.airquality.api.apiKey.description = Data-platform token to access the AQIcn.org service. +thing-type.config.airquality.station.location.label = Location +thing-type.config.airquality.station.location.description = Your geo coordinates separated with comma (e.g. "37.8,-122.4"). +thing-type.config.airquality.station.stationId.label = Station ID +thing-type.config.airquality.station.stationId.description = Fill in case you want to receive data from the specific station. +thing-type.config.airquality.station.refresh.label = Refresh Interval +thing-type.config.airquality.station.refresh.description = Specifies the refresh interval in minutes. + +# Channel groups labels +pm25ChannelGroupLabel = PM 2.5 - Particles less than 2.5 m in diameter. +pm10ChannelGroupLabel = PM 10 - Coarse Dust Particles. +no2ChannelGroupLabel = NO2 - Nitrogen Dioxide. +so2ChannelGroupLabel = SO2 - Sulfur Dioxide. +coChannelGroupLabel = CO - Carbon Monoxide. +o3ChannelGroupLabel = O3 - Ozone. +aqiChannelGroupLabel = AQI - Synthetic Air Quality Index. +weatherChannelGroupLabel = Weather Data + +# Channel types labels +timestampChannelLabel = Observation Time +timestampChannelDescription = Observation date and time. +dominentChannelLabel = Dominent Pollutant +dewPointLabel = Dew-Point Temperature +dewPointDescription = Forecasted dew-point temperature. +windSpeedLabel = Wind Speed +pictoChannelLabel = Pictogram +pictoChannelDescription = Pictogram associated to alert level. +colorChannelLabel = AQI Color +colorChannelDescription = Color associated to given AQI Index. + +# Channel options values +alertLevelChannelLabel = Alert Level +alertLevelChannelDescription = Alert level associated to Air Quality Index scale. +alertLevelOption0 = Good +alertLevelOption1 = Moderate +alertLevelOption2 = Unhealthy for Sensitive Groups +alertLevelOption3 = Unhealthy +alertLevelOption4 = Very Unhealthy +alertLevelOption5 = Hazardous + +pollutantPm25 = Fine particles +pollutantPm10 = Coarse dust particles +pollutantO3 = Ozone +pollutantNO2 = Nitrogen Dioxide +pollutantCO = Carbon Monoxide +pollutantSO2 = Sulfur Dioxide + +# Error messages +null-or-empty-api-key = Null or empty API key +incorrect-bridge = Wrong bridge type diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties index aa947a41d1cc1..7cfe92f15b2f2 100644 --- a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties @@ -1,30 +1,62 @@ # binding binding.airquality.name = Extension Air Quality -binding.airquality.description = Indice de qualité de l'air et informations sur la pollution aux particules pour un emplacement donné. +binding.airquality.description = Indice de qualit de l'air et informations sur la pollution aux particules pour un emplacement donn. # thing types -thing-type.airquality.aqi.label = Qualité de l'air -thing-type.airquality.aqi.description = Fournit diverses données sur la qualité de l'air du World Air Quality Project. Pour recevoir les données, vous devez créer un compte sur http://aqicn.org/data-platform/token/ pour obtenir votre token API. +thing-type.airquality.api.label = API Air Quality +thing-type.airquality.api.description = Passerelle vers le service de donnes Air Quality. +thing-type.airquality.station.label = Qualit de l'air +thing-type.airquality.station.description = Fournit diverses donnes sur la qualit de l'air du World Air Quality Project. Pour recevoir les donnes, vous devez crer un compte sur http://aqicn.org/data-platform/token/ pour obtenir votre token API. -channel-type.airquality.aqiLevel.label = Indice -channel-type.airquality.aqiDescription.label = Appréciation -channel-type.airquality.observationTime.label = Heure d'observation -channel-type.airquality.temperature.label = Température -channel-type.airquality.pressure.label = Pression -channel-type.airquality.humidity.label = Humidité -channel-type.airquality.dominentpol.label = Polluant principal +# thing types config +thing-type.config.airquality.api.apiKey.label = Cl API +thing-type.config.airquality.api.apiKey.description = Jeton d'accs aux donnes du service AQIcn.org. +thing-type.config.airquality.station.location.label = Localisation +thing-type.config.airquality.station.location.description = Coordonnes gographiques (spares par une virgule : "37.8,-122.4"). +thing-type.config.airquality.station.stationId.label = ID Station +thing-type.config.airquality.station.stationId.description = Renseignez cette valeur si vous souhaitez les donnes d'une station spcifique. +thing-type.config.airquality.station.refresh.label = Priode de mise jour +thing-type.config.airquality.station.refresh.description = Dfinisser l'intervalle de mise jour en minutes. +# Channel groups labels +pm25ChannelGroupLabel = PM 2.5 - Particules de diametre infrieur 2.5 m. +pm10ChannelGroupLabel = PM 10 - Particules fines de poussire. +no2ChannelGroupLabel = NO2 - Dioxyde d'azote. +so2ChannelGroupLabel = SO2 - Dioxyde de soufre. +coChannelGroupLabel = CO - Monoxyde de carbone. +o3ChannelGroupLabel = O3 - Ozone. +aqiChannelGroupLabel = AQI - Indice Global de Qualit de l'Air. +weatherChannelGroupLabel = Donnes Mteo. -channel-type.airquality.aqiDescription.state.option.GOOD = Bonne -channel-type.airquality.aqiDescription.state.option.MODERATE = Modérée -channel-type.airquality.aqiDescription.state.option.UNHEALTHY_FOR_SENSITIVE = Mauvaise pour les groupes sensibles -channel-type.airquality.aqiDescription.state.option.UNHEALTHY = Mauvaise -channel-type.airquality.aqiDescription.state.option.VERY_UNHEALTHY = Très mauvaise -channel-type.airquality.aqiDescription.state.option.HAZARDOUS = Dangereuse +# Channel types labels +timestampChannelLabel = Horodatage +timestampChannelDescription = Date et heure des oObservations. +dominentChannelLabel = Polluant Principal +dewPointLabel = Temprature de Rose +dewPointDescription = Temprature du point de Rose. +windSpeedLabel = Vitesse du Vent +pictoChannelLabel = Pictogramme +pictoChannelDescription = Pictogramme associ au niveau d'alerte. +colorChannelLabel = Couleur AQI +colorChannelDescription = Couleur associe l'Indice de Qualit d'Air. -channel-type.airquality.dominentPol.state.option.pm25 = Particules fines -channel-type.airquality.dominentPol.state.option.pm10 = Particules de poussière -channel-type.airquality.dominentPol.state.option.o3 = Ozone -channel-type.airquality.dominentPol.state.option.no2 = Dioxyde d'azote -channel-type.airquality.dominentPol.state.option.co = Monoxyde de carbone -channel-type.airquality.dominentPol.state.option.so2 = Dioxyde de soufre +# Channel options values +alertLevelChannelLabel = Niveau d'Alerte +alertLevelChannelDescription = Niveau d'alerte associ l'Indice de Qualit d'Air. +alertLevelOption0 = Bonne +alertLevelOption1 = Modre +alertLevelOption2 = Mauvaise pour les groupes sensibles +alertLevelOption3 = Mauvaise +alertLevelOption4 = Trs mauvaise +alertLevelOption5 = Dangereuse + +pollutantPm25 = Particules de diametre infrieur 2.5 m. +pollutantPm10 = Particules fines de poussire. +pollutantO3 = Ozone +pollutantNO2 = Dioxyde d'azote. +pollutantCO = Monoxyde de carbone. +pollutantSO2 = Dioxyde de soufre. + +# Error messages +null-or-empty-api-key = Clef API nulle ou vide +incorrect-bridge = Le type de bridge est incorrect diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/thing/thing-types.xml index e37e14388cc19..08a63ca52a699 100644 --- a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/thing/thing-types.xml @@ -4,55 +4,58 @@ xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd"> - - - - - Provides various air quality data from the World Air Quality Project. - In order to receive the data, you - must register an account on http://aqicn.org/data-platform/token/ and get your API - token. - - - - - - - - - - - - - - - - - - - - - + + - + password - Data-platform token to access the AQIcn.org service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Your geo coordinates separated with comma (e.g. "37.8,-122.4"). - Fill only in case you want to receive data from the specific station - true - Specifies the refresh interval in minutes. true 60 Minutes @@ -60,155 +63,172 @@ - - Number - - - Air Quality Index - - + + + + + + + + + + + - - String - - - AQI Description - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + Number - - Fine particles pollution level - PM2.5 + + + Measurement + - + Number - - Coarse dust particles pollution level - PM10 + + + Measurement + - - Number - - Ozone level - O3 - + + Number:Density + + - - Number - - Nitrogen dioxide level - NO2 - + + Number:Dimensionless + + - + Number - - Carbon monoxide level - CO - + + @text/alertLevelChannelDescription + error + + Alarm + + + + + + + + + + + - - Number - - Sulfur dioxide level - SO2 - + + DateTime + + @text/timestampChannelDescription + time + + Status + Timestamp + + - + String - - Nearest measuring station location - Location - - - - - Location - - Location of the measuring station - Station Location - - - - - Number - - Unique measuring station ID - Station ID - - - - - DateTime - - Observation date and time - Observation time - + + + Status + + + + + + + + + + + - + Number:Temperature - - Temperature + + @text/dewPointDescription Temperature + + Point + Temperature + - - Number:Pressure - - Current Pressure - Pressure - - - - - Number:Dimensionless - - Current humidity - Humidity - + + Color + + @text/colorChannelDescription + - - String - - - - - - - - - - - + + Image + + @text/pictoChannelDescription + - - Color - - Color associated to given AQI Index. + + Switch + + Checked if sensitive group is exposed to pollutant. + + + + Defines the kind of sensitivity + + + + + + + + RESPIRATORY + + diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/good.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/good.svg new file mode 100644 index 0000000000000..aecde2e179158 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/good.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/hazardous.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/hazardous.svg new file mode 100644 index 0000000000000..143e55e5fd176 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/hazardous.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/moderate.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/moderate.svg new file mode 100644 index 0000000000000..0926e7be2cb83 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/moderate.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy.svg new file mode 100644 index 0000000000000..f654683ea76d2 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy_fsg.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy_fsg.svg new file mode 100644 index 0000000000000..1aca57635833d --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/unhealthy_fsg.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/picto/very_unhealthy.svg b/bundles/org.openhab.binding.airquality/src/main/resources/picto/very_unhealthy.svg new file mode 100644 index 0000000000000..b04e3520a8138 --- /dev/null +++ b/bundles/org.openhab.binding.airquality/src/main/resources/picto/very_unhealthy.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file From 6e6c826ea04e1185c56fbd1c8160363b024326db Mon Sep 17 00:00:00 2001 From: lolodomo Date: Tue, 9 Nov 2021 17:56:40 +0100 Subject: [PATCH 076/361] [hue] Factorize thing configurations (#11535) * Reduce the number of strings to translate * Remove wrong key for channel pattern Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/config/config.xml | 111 ++++++++++++++++-- .../main/resources/OH-INF/i18n/hue.properties | 85 +++----------- .../resources/OH-INF/i18n/hue_de.properties | 87 +++----------- .../resources/OH-INF/i18n/hue_fr.properties | 43 +++---- .../OH-INF/thing/CLIPGenericFlagSensor.xml | 11 +- .../OH-INF/thing/CLIPGenericStatusSensor.xml | 11 +- .../resources/OH-INF/thing/ColorLight.xml | 12 +- .../OH-INF/thing/ColorTemperatureLight.xml | 12 +- .../resources/OH-INF/thing/DimmableLight.xml | 12 +- .../resources/OH-INF/thing/DimmablePlug.xml | 12 +- .../resources/OH-INF/thing/DimmerSwitch.xml | 11 +- .../OH-INF/thing/ExtendedColorLight.xml | 12 +- .../resources/OH-INF/thing/GeofenceSensor.xml | 2 +- .../src/main/resources/OH-INF/thing/Group.xml | 12 +- .../OH-INF/thing/LightLevelSensor.xml | 28 +---- .../resources/OH-INF/thing/OnOffLight.xml | 7 +- .../main/resources/OH-INF/thing/OnOffPlug.xml | 7 +- .../main/resources/OH-INF/thing/TapSwitch.xml | 11 +- .../OH-INF/thing/TemperatureSensor.xml | 16 +-- 19 files changed, 172 insertions(+), 330 deletions(-) diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/config/config.xml index 71e34113f650c..bddda1e9b05e2 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/config/config.xml @@ -4,15 +4,56 @@ xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd"> + + + + @text/config.sensorId.description + + + + @text/config.on.description + + + + @text/config.ledindication.description + + + + Threshold the user configured to be used in rules to determine insufficient light level (ie below + threshold). Default value 16000. + 16000 + + + + Threshold the user configured to be used in rules to determine sufficient light level (ie above + threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. + 7000 + + + + + + + @text/config.sensorId.description + + + + @text/config.on.description + + + + @text/config.ledindication.description + + + - - The identifier that is used within the hue bridge. + + @text/config.sensorId.description - - Turns device LED during normal operation on or off. Devices might still indicate exceptional operation - (Reset, SW Update, Battery Low). + + @text/config.ledindication.description @@ -24,14 +65,64 @@ - + - - The identifier that is used within the hue bridge. + + @text/config.sensorId.description - - Enables or disables the sensor. + + @text/config.on.description + + + + + + + @text/config.lightId.description + + + + @text/config.fadetime.description + 400 + + + + + + + @text/config.lightId.description + + + + + + + @text/config.plugId.description + + + + @text/config.fadetime.description + 400 + + + + + + + @text/config.plugId.description + + + + + + + The group identifier identifies one certain hue group or room. + + + + @text/config.fadetime.description + 400 diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties index fa842293b4317..49e40b3008853 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue.properties @@ -47,62 +47,6 @@ thing-type.hue.group.description = A group of lights or a room that could be swi # thing types config -thing-type.config.hue.0000.lightId.label = Light ID -thing-type.config.hue.0000.lightId.description = The light identifier identifies one certain hue light. -thing-type.config.hue.0010.lightId.label = Light ID -thing-type.config.hue.0010.lightId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0100.fadetime.label = Fade Time -thing-type.config.hue.0100.fadetime.description = Fade time in milliseconds for changing values -thing-type.config.hue.0100.lightId.label = Light ID -thing-type.config.hue.0100.lightId.description = The light identifier identifies one certain hue light. -thing-type.config.hue.0106.ledindication.label = LED Indication -thing-type.config.hue.0106.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low). -thing-type.config.hue.0106.on.label = Sensor Status -thing-type.config.hue.0106.on.description = Enables or disables the sensor. -thing-type.config.hue.0106.sensorId.label = Sensor ID -thing-type.config.hue.0106.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0106.tholddark.label = Threshold Dark -thing-type.config.hue.0106.tholddark.description = Threshold the user configured to be used in rules to determine insufficient light level (ie below threshold). Default value 16000. -thing-type.config.hue.0106.tholdoffset.label = Threshold Offset -thing-type.config.hue.0106.tholdoffset.description = Threshold the user configured to be used in rules to determine sufficient light level (ie above threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. -thing-type.config.hue.0110.fadetime.label = Fade Time -thing-type.config.hue.0110.fadetime.description = Fade time in milliseconds for changing values -thing-type.config.hue.0110.lightId.label = Light ID -thing-type.config.hue.0110.lightId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0200.fadetime.label = Fade Time -thing-type.config.hue.0200.fadetime.description = Fade time in milliseconds for changing values -thing-type.config.hue.0200.lightId.label = Light ID -thing-type.config.hue.0200.lightId.description = The light identifier identifies one certain hue light. -thing-type.config.hue.0210.fadetime.label = Fade Time -thing-type.config.hue.0210.fadetime.description = Fade time in milliseconds for changing values -thing-type.config.hue.0210.lightId.label = Light ID -thing-type.config.hue.0210.lightId.description = The light identifier identifies one certain hue light. -thing-type.config.hue.0220.fadetime.label = Fade Time -thing-type.config.hue.0220.fadetime.description = Fade time in milliseconds for changing values -thing-type.config.hue.0220.lightId.label = Light ID -thing-type.config.hue.0220.lightId.description = The light identifier identifies one certain hue light. -thing-type.config.hue.0302.ledindication.label = LED Indication -thing-type.config.hue.0302.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low). -thing-type.config.hue.0302.on.label = Sensor Status -thing-type.config.hue.0302.on.description = Enables or disables the sensor. -thing-type.config.hue.0302.sensorId.label = Sensor ID -thing-type.config.hue.0302.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0820.on.label = Sensor Status -thing-type.config.hue.0820.on.description = Enables or disables the sensor. -thing-type.config.hue.0820.sensorId.label = Sensor ID -thing-type.config.hue.0820.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0830.on.label = Sensor Status -thing-type.config.hue.0830.on.description = Enables or disables the sensor. -thing-type.config.hue.0830.sensorId.label = Sensor ID -thing-type.config.hue.0830.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0840.on.label = Sensor Status -thing-type.config.hue.0840.on.description = Enables or disables the sensor. -thing-type.config.hue.0840.sensorId.label = Sensor ID -thing-type.config.hue.0840.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.0850.on.label = Sensor Status -thing-type.config.hue.0850.on.description = Enables or disables the sensor. -thing-type.config.hue.0850.sensorId.label = Sensor ID -thing-type.config.hue.0850.sensorId.description = The identifier that is used within the hue bridge. thing-type.config.hue.bridge.ipAddress.label = Network Address thing-type.config.hue.bridge.ipAddress.description = Network address of the Hue bridge. thing-type.config.hue.bridge.pollingInterval.label = Polling Interval @@ -113,22 +57,16 @@ thing-type.config.hue.bridge.sensorPollingInterval.label = Sensor Polling Interv thing-type.config.hue.bridge.sensorPollingInterval.description = Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the Hue bridge. Use 0 to disable the polling for sensors. Default is 500. thing-type.config.hue.bridge.userName.label = Username thing-type.config.hue.bridge.userName.description = Name of a registered Hue bridge user, that allows to access the API. -thing-type.config.hue.geofencesensor.on.label = Sensor Status -thing-type.config.hue.geofencesensor.on.description = Enables or disables the sensor. -thing-type.config.hue.geofencesensor.sensorId.label = Sensor ID -thing-type.config.hue.geofencesensor.sensorId.description = The identifier that is used within the hue bridge. -thing-type.config.hue.group.fadetime.label = Fade Time -thing-type.config.hue.group.fadetime.description = Fade time in milliseconds for changing values thing-type.config.hue.group.groupId.label = Group ID thing-type.config.hue.group.groupId.description = The group identifier identifies one certain hue group or room. -thing-type.config.hue.presencesensor.ledindication.label = LED Indication -thing-type.config.hue.presencesensor.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low). +thing-type.config.hue.lightlevelsensor.tholddark.label = Threshold Dark +thing-type.config.hue.lightlevelsensor.tholddark.description = Threshold the user configured to be used in rules to determine insufficient light level (ie below threshold). Default value 16000. +thing-type.config.hue.lightlevelsensor.tholdoffset.label = Threshold Offset +thing-type.config.hue.lightlevelsensor.tholdoffset.description = Threshold the user configured to be used in rules to determine sufficient light level (ie above threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. thing-type.config.hue.presencesensor.sensitivity.label = Sensitivity thing-type.config.hue.presencesensor.sensitivity.description = The current sensitivity of the presence sensor. Cannot exceed maximum sensitivity. thing-type.config.hue.presencesensor.sensitivitymax.label = Maximum Sensitivity thing-type.config.hue.presencesensor.sensitivitymax.description = The maximum sensitivity of the presence sensor. -thing-type.config.hue.presencesensor.sensorId.label = Sensor ID -thing-type.config.hue.presencesensor.sensorId.description = The identifier that is used within the hue bridge. # channel types @@ -187,9 +125,20 @@ channel-type.hue.tap_switch_event.description = Triggers when a button is presse channel-type.hue.temperature.label = Temperature channel-type.hue.temperature.description = Current temperature. -# channel types +# thing types config -channel-type.hue.last_updated.options.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +config.fadetime.label = Fade Time +config.fadetime.description = Fade time in milliseconds for changing values. +config.ledindication.label = LED Indication +config.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low). +config.lightId.label = Light ID +config.lightId.description = The light identifier that is used within the hue bridge. +config.plugId.label = Plug ID +config.plugId.description = The plug identifier that is used within the hue bridge. +config.sensorId.label = Sensor ID +config.sensorId.description = The sensor identifier that is used within the hue bridge. +config.on.label = Sensor Status +config.on.description = Enables or disables the sensor. # config status messages diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_de.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_de.properties index 7fdcfabf4abff..5506a2a46ddd9 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_de.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_de.properties @@ -47,62 +47,6 @@ thing-type.hue.group.description = Eine Gruppe von Lichtern, ein Raum oder eine # thing types config -thing-type.config.hue.0000.lightId.label = ID der Lampe -thing-type.config.hue.0000.lightId.description = ID zur Identifikation der Lampe. -thing-type.config.hue.0010.lightId.label = ID der Steckdose -thing-type.config.hue.0010.lightId.description = ID zur Identifikation der Steckdose. -thing-type.config.hue.0100.fadetime.label = Dauer des Überblendens -thing-type.config.hue.0100.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). -thing-type.config.hue.0100.lightId.label = ID der Lampe -thing-type.config.hue.0100.lightId.description = ID zur Identifikation der Lampe. -thing-type.config.hue.0106.ledindication.label = LED-Anzeige -thing-type.config.hue.0106.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors. -thing-type.config.hue.0106.on.label = Sensor Status -thing-type.config.hue.0106.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0106.sensorId.label = ID des Sensors -thing-type.config.hue.0106.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.0106.tholddark.label = Dunkel-Schwellwert -thing-type.config.hue.0106.tholddark.description = Zeigt den Dunkel-Schwellwert an. -thing-type.config.hue.0106.tholdoffset.label = Hell-Schwellwert -thing-type.config.hue.0106.tholdoffset.description = Zeigt den Hell-Schwellwert an. -thing-type.config.hue.0110.fadetime.label = Dauer des Überblendens -thing-type.config.hue.0110.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). -thing-type.config.hue.0110.lightId.label = ID der Steckdose -thing-type.config.hue.0110.lightId.description = ID zur Identifikation der Steckdose. -thing-type.config.hue.0200.fadetime.label = Dauer des Überblendens -thing-type.config.hue.0200.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). -thing-type.config.hue.0200.lightId.label = ID der Lampe -thing-type.config.hue.0200.lightId.description = ID zur Identifikation der Lampe. -thing-type.config.hue.0210.fadetime.label = Dauer des Überblendens -thing-type.config.hue.0210.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). -thing-type.config.hue.0210.lightId.label = ID der Lampe -thing-type.config.hue.0210.lightId.description = ID zur Identifikation der Lampe. -thing-type.config.hue.0220.fadetime.label = Dauer des Überblendens -thing-type.config.hue.0220.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). -thing-type.config.hue.0220.lightId.label = ID der Lampe -thing-type.config.hue.0220.lightId.description = ID zur Identifikation der Lampe. -thing-type.config.hue.0302.ledindication.label = LED-Anzeige -thing-type.config.hue.0302.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors. -thing-type.config.hue.0302.on.label = Sensor Status -thing-type.config.hue.0302.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0302.sensorId.label = ID des Sensors -thing-type.config.hue.0302.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.0820.on.label = Sensor Status -thing-type.config.hue.0820.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0820.sensorId.label = ID des Sensors -thing-type.config.hue.0820.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.0830.on.label = Sensor Status -thing-type.config.hue.0830.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0830.sensorId.label = ID des Sensors -thing-type.config.hue.0830.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.0840.on.label = Sensor Status -thing-type.config.hue.0840.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0840.sensorId.label = ID des Sensors -thing-type.config.hue.0840.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.0850.on.label = Sensor Status -thing-type.config.hue.0850.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.0850.sensorId.label = ID des Sensors -thing-type.config.hue.0850.sensorId.description = ID zur Identifikation des Sensors. thing-type.config.hue.bridge.ipAddress.label = IP-Adresse thing-type.config.hue.bridge.ipAddress.description = Lokale IP-Adresse oder Hostname der Hue Bridge. thing-type.config.hue.bridge.pollingInterval.label = Abfrageintervall @@ -113,22 +57,29 @@ thing-type.config.hue.bridge.sensorPollingInterval.label = Sensor-Abfrageinterva thing-type.config.hue.bridge.sensorPollingInterval.description = Intervall zur Abfrage der Sensoren der Hue Bridge (in Millisekunden). thing-type.config.hue.bridge.userName.label = Benutzer thing-type.config.hue.bridge.userName.description = Benutzer zur Authentifizierung an der Hue Bridge. -thing-type.config.hue.geofencesensor.on.label = Sensor Status -thing-type.config.hue.geofencesensor.on.description = Aktiviert oder deaktiviert den Sensor. -thing-type.config.hue.geofencesensor.sensorId.label = ID des Sensors -thing-type.config.hue.geofencesensor.sensorId.description = ID zur Identifikation des Sensors. -thing-type.config.hue.group.fadetime.label = Dauer des Überblendens -thing-type.config.hue.group.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). thing-type.config.hue.group.groupId.label = ID der Gruppe thing-type.config.hue.group.groupId.description = ID zur Identifikation der Gruppe. -thing-type.config.hue.presencesensor.ledindication.label = LED-Anzeige -thing-type.config.hue.presencesensor.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors. +thing-type.config.hue.lightlevelsensor.tholddark.label = Dunkel-Schwellwert +thing-type.config.hue.lightlevelsensor.tholddark.description = Zeigt den Dunkel-Schwellwert an. +thing-type.config.hue.lightlevelsensor.tholdoffset.label = Hell-Schwellwert +thing-type.config.hue.lightlevelsensor.tholdoffset.description = Zeigt den Hell-Schwellwert an. thing-type.config.hue.presencesensor.sensitivity.label = Empfindlichkeit thing-type.config.hue.presencesensor.sensitivity.description = Zeigt die Empfindlichkeit an. thing-type.config.hue.presencesensor.sensitivitymax.label = Maximale Empfindlichkeit thing-type.config.hue.presencesensor.sensitivitymax.description = Zeigt die maximale Empfindlichkeit an. -thing-type.config.hue.presencesensor.sensorId.label = ID des Sensors -thing-type.config.hue.presencesensor.sensorId.description = ID zur Identifikation des Sensors. + +config.fadetime.label = Dauer des Überblendens +config.fadetime.description = Dauer des Überblendens bei Änderung von Werten (in Millisekunden). +config.ledindication.label = ED-Anzeige +config.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors. +config.lightId.label = ID der Lampe +config.lightId.description = ID zur Identifikation der Lampe. +config.plugId.label = ID der Steckdose +config.plugId.description = ID zur Identifikation der Steckdose. +config.sensorId.label = ID des Sensors +config.sensorId.description = ID zur Identifikation des Sensors. +config.on.label = Sensor Status +config.on.description = Aktiviert oder deaktiviert den Sensor. # channel types @@ -187,10 +138,6 @@ channel-type.hue.tap_switch_event.description = Wird ausgelöst, wenn auf dem Ta channel-type.hue.temperature.label = Temperatur channel-type.hue.temperature.description = Die aktuelle Temperatur. -# channel types - -channel-type.hue.last_updated.options.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS - # config status messages config-status.error.missing-ip-address-configuration = Es wurde keine IP-Adresse für die Hue Bridge angegeben. diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties index 3b35df70aa0d1..87e642f24e8d5 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties @@ -1,10 +1,10 @@ # binding + binding.hue.name = Extension hue binding.hue.description = L'extension hue intègre le système Philips hue et permet de contrôler des ampoules hue. # thing types -thing-type.hue.bridge.label = Pont de connexion hue -thing-type.hue.bridge.description = Le pont de connexion Philips Hue. + thing-type.hue.0000.label = Ampoule sans variation thing-type.hue.0000.description = Une ampoule sans réglage de l'intensité lumineuse. thing-type.hue.0010.label = Prise commandée sans variation @@ -19,34 +19,33 @@ thing-type.hue.0210.label = Ampoule couleur thing-type.hue.0210.description = Une ampoule avec réglages de l'intensité lumineuse, de la couleur et de la température de couleur thing-type.hue.0220.label = Ampoule couleur thing-type.hue.0220.description = Une ampoule avec réglages de l'intensité lumineuse et de la température de couleur. +thing-type.hue.bridge.label = Pont de connexion hue +thing-type.hue.bridge.description = Le pont de connexion Philips Hue. thing-type.hue.group.label = Groupe hue thing-type.hue.group.description = Un groupe d'ampoules ou une pièce pouvant être allumé et éteint. # thing type configuration + thing-type.config.hue.bridge.ipAddress.label = Adresse réseau thing-type.config.hue.bridge.ipAddress.description = L'adresse réseau du pont de connexion hue. -thing-type.config.hue.bridge.userName.label = Nom d'utilisateur -thing-type.config.hue.bridge.userName.description = Le nom d'un utilisateur enregistré sur le pont de connexion hue, autorisant un accès à l'API. thing-type.config.hue.bridge.pollingInterval.label = Intervalle d'interrogation thing-type.config.hue.bridge.pollingInterval.description = Le nombre de secondes entre chaque récupération des valeurs du pont. -thing-type.config.hue.0000.lightId.label = ID ampoule -thing-type.config.hue.0000.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue. -thing-type.config.hue.0010.lightId.label = ID prise commandée -thing-type.config.hue.0010.lightId.description = L'identifiant de prise commandée identifie l'une des prises commandées. hue -thing-type.config.hue.0100.lightId.label = ID ampoule -thing-type.config.hue.0100.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue. -thing-type.config.hue.0110.lightId.label = ID prise commandée -thing-type.config.hue.0110.lightId.description = L'identifiant de prise commandée identifie l'une des prises commandées. hue. -thing-type.config.hue.0200.lightId.label = ID ampoule -thing-type.config.hue.0200.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue. -thing-type.config.hue.0210.lightId.label = ID ampoule -thing-type.config.hue.0210.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue. -thing-type.config.hue.0220.lightId.label = ID ampoule -thing-type.config.hue.0220.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue. -thing-type.config.hue.group.groupId.label = ID groupe +thing-type.config.hue.bridge.userName.label = Nom d'utilisateur +thing-type.config.hue.bridge.userName.description = Le nom d'un utilisateur enregistré sur le pont de connexion hue, autorisant un accès à l'API. +thing-type.config.hue.group.groupId.label = ID group thing-type.config.hue.group.groupId.description = L'identifiant de groupe identifie l'un des groupes d'ampoules hue ou une pièce. +config.lightId.label = ID ampoule +config.lightId.description = L'identifiant d'ampoule qui est utilis dans le pont de connexion Hue. +config.plugId.label = ID prise commande +config.plugId.description = L'identifiant de prise commande qui est utilis dans le pont de connexion Hue. +config.sensorId.label = ID du capteur +config.sensorId.description = identifiant de capteur qui est utilis dans le pont de connexion Hue. +config.on.label = tat du capteur +config.on.description = Active ou dsactive le capteur. + # channel types + channel-type.hue.alert.label = Mode alerte channel-type.hue.alert.description = Permet un changement temporaire de l'état de l'ampoule. channel-type.hue.alert.state.option.NONE = Sans alerte @@ -55,10 +54,12 @@ channel-type.hue.alert.state.option.LSELECT = Alerte longue channel-type.hue.effect.label = Mode boucle de couleur channel-type.hue.effect.description = Permet de passer l'ampoule dans un mode boucle de couleur. -# Config status messages +# config status messages + config-status.error.missing-ip-address-configuration=Aucune adresse IP fournie pour le pont de connexion hue. -# Thing status descriptions +# thing status descriptions + offline.conf-error-no-ip-address = Echec de la connexion au pont hue. Adresse IP non renseignée dans la configuration. offline.conf-error-no-username = Echec de la connexion au pont hue. Nom d''utilisateur pour l''autentification non renseigné dans la configuration. offline.conf-error-invalid-username = Echec de l''autentification. Supprimer le nom d''utilisateur de la configuration pour en générer un nouveau. diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericFlagSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericFlagSensor.xml index 262308d69c306..c3eeb75f127a7 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericFlagSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericFlagSensor.xml @@ -19,15 +19,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericStatusSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericStatusSensor.xml index f683ea0a78def..843cb416c9a89 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericStatusSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/CLIPGenericStatusSensor.xml @@ -19,15 +19,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorLight.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorLight.xml index b76386919b9ab..3102c496266ab 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorLight.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorLight.xml @@ -20,16 +20,6 @@ uniqueId - - - - The light identifier identifies one certain hue light. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorTemperatureLight.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorTemperatureLight.xml index 7bd7ea70f3eb0..6d32d7f46f907 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorTemperatureLight.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ColorTemperatureLight.xml @@ -22,16 +22,6 @@ uniqueId - - - - The light identifier identifies one certain hue light. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmableLight.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmableLight.xml index d68de9b6006db..62d6b84e74d2f 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmableLight.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmableLight.xml @@ -19,16 +19,6 @@ uniqueId - - - - The light identifier identifies one certain hue light. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmablePlug.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmablePlug.xml index 6a272f9b70c8e..0adffeace6f9d 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmablePlug.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmablePlug.xml @@ -18,16 +18,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmerSwitch.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmerSwitch.xml index 3fe4e25e301f2..15c9f6735f05f 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmerSwitch.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/DimmerSwitch.xml @@ -22,15 +22,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ExtendedColorLight.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ExtendedColorLight.xml index 6d64a96ee451e..78c7dacc3f156 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ExtendedColorLight.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/ExtendedColorLight.xml @@ -22,16 +22,6 @@ uniqueId - - - - The light identifier identifies one certain hue light. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/GeofenceSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/GeofenceSensor.xml index 02330d79559d3..b9d50f01d64ed 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/GeofenceSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/GeofenceSensor.xml @@ -19,6 +19,6 @@ uniqueId - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Group.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Group.xml index 3078bd66480f7..76f3a0f1e59c0 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Group.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/Group.xml @@ -24,16 +24,6 @@ groupId - - - - The group identifier identifies one certain hue group or room. - - - - Fade time in milliseconds for changing values - 400 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml index 661d6e9f3c6fc..278f5efbac676 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/LightLevelSensor.xml @@ -24,32 +24,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - - - Turns device LED during normal operation on or off. Devices might still indicate exceptional operation - (Reset, SW Update, Battery Low). - - - - Threshold the user configured to be used in rules to determine insufficient light level (ie below - threshold). Default value 16000. - 16000 - - - - Threshold the user configured to be used in rules to determine sufficient light level (ie above - threshold). Specified as relative offset to the "dark" threshold. Shall be >=1. Default value 7000. - 7000 - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffLight.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffLight.xml index b2fd1f6259caa..6f01f226aa357 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffLight.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffLight.xml @@ -19,11 +19,6 @@ uniqueId - - - - The light identifier identifies one certain hue light. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffPlug.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffPlug.xml index ee1771da33da5..d109b8fa92be7 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffPlug.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/OnOffPlug.xml @@ -18,11 +18,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TapSwitch.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TapSwitch.xml index 2f6cce4efa826..213f035fd4a6c 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TapSwitch.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TapSwitch.xml @@ -20,15 +20,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - + diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TemperatureSensor.xml b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TemperatureSensor.xml index 1f68f7fce7f2e..c54cd14400cb6 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TemperatureSensor.xml +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/thing/TemperatureSensor.xml @@ -21,20 +21,6 @@ uniqueId - - - - The identifier that is used within the hue bridge. - - - - Enables or disables the sensor. - - - - Turns device LED during normal operation on or off. Devices might still indicate exceptional operation - (Reset, SW Update, Battery Low). - - + From fcfe621c3f093815b2c8b569ed721dcdc8ddab12 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Wed, 10 Nov 2021 00:41:23 +0100 Subject: [PATCH 077/361] fix: NPE Signed-off-by: Michael Schmidt --- .../openhab/binding/evnotify/internal/EVNotifyHandler.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java index 9993bf6c9e70f..322603aa14d31 100644 --- a/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java +++ b/bundles/org.openhab.binding.evnotify/src/main/java/org/openhab/binding/evnotify/internal/EVNotifyHandler.java @@ -131,17 +131,17 @@ private void updateChannelsAndStatus(@Nullable ChargingData chargingData, @Nulla private State getValue(String channelId, ChargingData chargingData) { switch (channelId) { case STATE_OF_CHARGE_DISPLAY: - if (chargingData.getStateOfHealth() == null) { + if (chargingData.getStateOfChargeDisplay() == null) { return UnDefType.UNDEF; } return new QuantityType<>(chargingData.getStateOfChargeDisplay(), Units.PERCENT); case STATE_OF_CHARGE_BMS: - if (chargingData.getStateOfHealth() == null) { + if (chargingData.getStateOfChargeBms() == null) { return UnDefType.UNDEF; } return new QuantityType<>(chargingData.getStateOfChargeBms(), Units.PERCENT); case LAST_STATE_OF_CHARGE: - if (chargingData.getLastExtended() == null) { + if (chargingData.getLastStateOfCharge() == null) { return UnDefType.UNDEF; } return new StringType( @@ -233,6 +233,7 @@ private State getValue(String channelId, ChargingData chargingData) { private void refresh() { // Request new EVNotify data try { + logger.debug("Refresh data"); if (client != null) { ChargingData chargingData = client.getCarChargingData(); updateChannelsAndStatus(chargingData, null); From 753550fe8558c04e20cc94316a369ee40b3e4c1d Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Wed, 10 Nov 2021 03:31:57 -0500 Subject: [PATCH 078/361] [nuvo] fixes protocol errors when connecting via an MPS4 (#11511) Signed-off-by: Brian O'Connell Co-authored-by: Brian O'Connell Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.nuvo/README.md | 6 +- .../nuvo/internal/NuvoBindingConstants.java | 3 + .../internal/communication/NuvoConnector.java | 6 + .../nuvo/internal/handler/NuvoHandler.java | 170 ++++++++++++------ 4 files changed, 128 insertions(+), 57 deletions(-) diff --git a/bundles/org.openhab.binding.nuvo/README.md b/bundles/org.openhab.binding.nuvo/README.md index 7939f2da9529d..512b4dafba780 100644 --- a/bundles/org.openhab.binding.nuvo/README.md +++ b/bundles/org.openhab.binding.nuvo/README.md @@ -47,8 +47,8 @@ The thing has the following configuration parameters: Some notes: -* The direct connection to the MPS4 server has not been exhaustively tested, please report any issues found. -* The only issue with the MPS4 connection seen thus far is that the setting SxDISPINFO as seen in the advanced rules below does not work. +* If the port is set to 5006 the binding will adjust its protocol to connect to a NuVo via an MPS4 IP connection. +* MPS4 connections do not support SxDISPINFO commands including those outlined in the advanced rules section below. * If a zone has a maximum volume limit configured by the Nuvo configurator, the volume slider will automatically drop back to that level if set above the configured limit. * Source display_line1 thru 4 can only be updated on non NuvoNet sources. * The track_position channel does not update continuously for NuvoNet sources. It only changes when the track changes or playback is paused/unpaused. @@ -104,7 +104,7 @@ nuvo:amplifier:myamp "Nuvo WHA" [ serialPort="COM5", numZones=6, clockSync=false // serial over IP connection nuvo:amplifier:myamp "Nuvo WHA" [ host="192.168.0.10", port=4444, numZones=6, clockSync=false] -// MPS4 server IP connection (experimental) +// MPS4 server IP connection nuvo:amplifier:myamp "Nuvo WHA" [ host="192.168.0.10", port=5006, numZones=6, clockSync=false] ``` diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java index 5a365ae803ac7..3c04af93c000d 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/NuvoBindingConstants.java @@ -83,4 +83,7 @@ public class NuvoBindingConstants { public static final String NAME_QUOTE = "NAME\""; public static final String MUTE = "MUTE"; public static final String VOL = "VOL"; + + // MPS4 + public static final String TYPE_PING = "PING"; } diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java index 35fe19ca55501..fd07ece33b853 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/communication/NuvoConnector.java @@ -45,6 +45,7 @@ public abstract class NuvoConnector { private static final String ALL_OFF = "#ALLOFF"; private static final String MUTE = "#MUTE"; private static final String PAGE = "#PAGE"; + private static final String PING = "#PING"; private static final byte[] WAKE_STR = "\r".getBytes(StandardCharsets.US_ASCII); @@ -304,6 +305,11 @@ public void handleIncomingMessage(byte[] incomingMessage) { return; } + if (message.contains(PING)) { + dispatchKeyValue(TYPE_PING, BLANK, BLANK); + return; + } + if (message.contains(VER_STR)) { // example: #VER"NV-E6G FWv2.66 HWv0" // split on " and return the version number diff --git a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java index 6494814be4006..2a0100deddce8 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java +++ b/bundles/org.openhab.binding.nuvo/src/main/java/org/openhab/binding/nuvo/internal/handler/NuvoHandler.java @@ -87,6 +87,7 @@ public class NuvoHandler extends BaseThingHandler implements NuvoMessageEventLis private static final long CLOCK_SYNC_INTERVAL_SEC = 3600; private static final long INITIAL_POLLING_DELAY_SEC = 30; private static final long INITIAL_CLOCK_SYNC_DELAY_SEC = 10; + private static final long PING_TIMEOUT_SEC = 60; // spec says wait 50ms, min is 100 private static final long SLEEP_BETWEEN_CMD_MS = 100; private static final Unitlumi.gateway.mgl03) Channels @@ -1772,6 +1774,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Philips ZhiRui Downlight (philips.light.downlight) Channels @@ -1875,6 +1878,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Nordic 40W (philips.light.mceilm) Channels @@ -1890,6 +1894,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Nordic 28W (philips.light.mceils) Channels @@ -1905,6 +1910,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Philips Smart Lamp (philips.light.mono1) Channels @@ -1941,6 +1947,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Black 40W (philips.light.obceim) Channels @@ -1956,6 +1963,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Black 28W (philips.light.obceis) Channels @@ -1971,6 +1979,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Mijia Philips Study Desk Lamp (philips.light.rwread) Channels @@ -1996,6 +2005,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Starry 40W (philips.light.sceilm) Channels @@ -2011,6 +2021,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Starry 28W (philips.light.sceils) Channels @@ -2026,6 +2037,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Philips EyeCare Connected Desk Lamp gen2. (philips.light.sread1) Channels @@ -2077,6 +2089,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Gorgeous 40W (philips.light.xzceim) Channels @@ -2092,6 +2105,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Zhirui Ceiling Lamp Gorgeous 28W (philips.light.xzceis) Channels @@ -2107,6 +2121,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | autoCct | String | Auto CCT | | | dimmingPeriod | Number | Dimming Period | | | MibandStatus | String | Mi Band Status | | +| actions | String | Actions | Value mapping `["light-brightness-down"="Light Brightness Down","light-brightness-up"="Light Brightness Up","light-toggle"="Light Toggle"]` | ### Philips ZhiYi Ceiling lamp (philips.light.zyceiling) Channels @@ -2209,7 +2224,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | | state | Number | State | | | mode | Number | Mode | | | err_state | Number | Error | | @@ -2229,7 +2244,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | | state | Number | State | | | mode | Number | Mode | | | err_state | Number | Error | | @@ -2249,7 +2264,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | | state | Number | State | | | mode | Number | Mode | | | err_state | Number | Error | | @@ -4976,7 +4991,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | speedLevel | Number | Speed Level | | | speed | Number | Speed | | | naturalLevel | Number | Natural Level | | -| move | String | Move Direction | | +| move | String | Move Direction | Value mapping `[""="None","left"="Left","right"="Right"]` | ### Smartmi Standing Fan 2S (zhimi.fan.za4) Channels @@ -4993,7 +5008,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | speedLevel | Number | Speed Level | | | speed | Number | Speed | | | naturalLevel | Number | Natural Level | | -| move | String | Move Direction | | +| move | String | Move Direction | Value mapping `[""="None","left"="Left","right"="Right"]` | ### Smartmi Standing Fan 3 (zhimi.fan.za5) Channels @@ -6320,14 +6335,16 @@ note: Autogenerated example. Replace the id (curtain) in the channel with your o ``` Group G_curtain "Xiaomiyoupin Curtain Controller (Wi-Fi)" Number fault "Curtain - Device Fault" (G_curtain) {channel="miio:basic:curtain:fault"} -Number current_position "Curtain - Current Position" (G_curtain) {channel="miio:basic:curtain:current-position"} +Number motor_control "Curtain - Motor Control" (G_curtain) {channel="miio:basic:curtain:motor_control"} +Number:Dimensionless current_position "Curtain - Current Position" (G_curtain) {channel="miio:basic:curtain:current-position"} Number status "Curtain - Status" (G_curtain) {channel="miio:basic:curtain:status"} -Number target_position "Curtain - Target Position" (G_curtain) {channel="miio:basic:curtain:target-position"} +Number:Dimensionless target_position "Curtain - Target Position" (G_curtain) {channel="miio:basic:curtain:target-position"} Number manual_enabled "curtain_cfg - Manual Enabled" (G_curtain) {channel="miio:basic:curtain:manual-enabled"} -Number polarity "curtain_cfg - Polarity" (G_curtain) {channel="miio:basic:curtain:polarity"} +Number polarity "Curtain_cfg - Polarity" (G_curtain) {channel="miio:basic:curtain:polarity"} Number pos_limit "curtain_cfg - Position Limit" (G_curtain) {channel="miio:basic:curtain:pos-limit"} -Switch en_night_tip_light "Set Night Tip Light" (G_curtain) {channel="miio:basic:curtain:en-night-tip-light"} -Number run_time "curtain_cfg - Run-time" (G_curtain) {channel="miio:basic:curtain:run-time"} +Number en_night_tip_light "Curtain_cfg - En_night_tip_light" (G_curtain) {channel="miio:basic:curtain:en_night_tip_light"} +Number run_time "Curtain_cfg - Run-time" (G_curtain) {channel="miio:basic:curtain:run-time"} +Number adjust_value "Motor_controller - Adjust_value" (G_curtain) {channel="miio:basic:curtain:adjust_value"} ``` ### Mi Air Purifier virtual (lumi.gateway.mgl03) item file lines @@ -6737,6 +6754,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Philips ZhiRui Downlight (philips.light.downlight) item file lines @@ -6861,6 +6879,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Nordic 40W (philips.light.mceilm) item file lines @@ -6879,6 +6898,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Nordic 28W (philips.light.mceils) item file lines @@ -6897,6 +6917,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Philips Smart Lamp (philips.light.mono1) item file lines @@ -6942,6 +6963,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Black 40W (philips.light.obceim) item file lines @@ -6960,6 +6982,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Black 28W (philips.light.obceis) item file lines @@ -6978,6 +7001,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Mijia Philips Study Desk Lamp (philips.light.rwread) item file lines @@ -7009,6 +7033,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Starry 40W (philips.light.sceilm) item file lines @@ -7027,6 +7052,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Starry 28W (philips.light.sceils) item file lines @@ -7045,6 +7071,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Philips EyeCare Connected Desk Lamp gen2. (philips.light.sread1) item file lines @@ -7108,6 +7135,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Gorgeous 40W (philips.light.xzceim) item file lines @@ -7126,6 +7154,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Zhirui Ceiling Lamp Gorgeous 28W (philips.light.xzceis) item file lines @@ -7144,6 +7173,7 @@ String WallScene "Wall Scene" (G_light) {channel="miio:basic:light:WallScene"} String autoCct "Auto CCT" (G_light) {channel="miio:basic:light:autoCct"} Number dimmingPeriod "Dimming Period" (G_light) {channel="miio:basic:light:dimmingPeriod"} String MibandStatus "Mi Band Status" (G_light) {channel="miio:basic:light:MibandStatus"} +String actions "Actions" (G_light) {channel="miio:basic:light:actions"} ``` ### Philips ZhiYi Ceiling lamp (philips.light.zyceiling) item file lines diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java index 9391acd15bdad..33dc575743288 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java @@ -48,6 +48,9 @@ public class MiIoBasicChannel { @SerializedName("channel") @Expose private @Nullable String channel; + @SerializedName("description") + @Expose + private @Nullable String description; @SerializedName("channelType") @Expose private @Nullable String channelType; @@ -142,6 +145,15 @@ public void setChannel(@Nullable String channel) { this.channel = channel; } + public String getDescription() { + final String description = this.description; + return description != null ? description : ""; + } + + public void setDescription(@Nullable String description) { + this.description = description; + } + public String getChannelType() { final @Nullable String ct = channelType; if (ct == null || ct.isEmpty()) { diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml index d6ff826d8f2ff..f0a6b876330ce 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml @@ -82,18 +82,6 @@ - - - Number:Temperature - - - - - Number:Time - - - - String @@ -107,716 +95,5 @@ Switch - - Switch - - - - Switch - - - - Switch - - - - String - - - - String - - - - - - - - - - Number - - - - Number - - - - Number - - - - Number - - - - Switch - - - - Number - - - - Number - - - - Number - - - - Number - - - - Number - - - - Number - - - - String - - - - Number - - - - Number - - - - Switch - - - - Switch - - - - Switch - - - - Color - - - - Color - - - - Number - - - - - - Number - - - - - Number:Temperature - - - - - Number - - - - - Number - - Particulate Matter 2.5 - - - - Number - - Carbon Dioxide - - - - Number - - Total Volatile Organic Compounds - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Number:Time - - - - - Number:Time - - - - - Number:Time - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - Number - - - - - Switch - - - - Number - - - - Switch - - - - Number - - - - - String - - - - - - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Switch - - - - - String - - - - - Switch - - - - - Switch - - - - - String - - - - - - - - - - - - String - - - - - - - - - - - Number - - - - - Switch - - - - Switch - - - - Switch - - - - String - - - - - - - - - - - Switch - - - - Switch - - - - - String - - - - - - - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - String - - - - - - - - - - String - - - - - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - - Number - - - - Number - - - - Number - - - - String - - - - Switch - - - - Number - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - Number - - - - - - - - - - Switch - - - - - - - - - - Number - - - - - - - - - - - String - - - - - - - - - - - - - - Number - - - - - - - - - - - - - - Number - - - - - - - - - - - - - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - - - - - - - Number - - - - - - - - - - String - - - - - - - - - - - Number:Temperature - - - - - - Number - - - - - - - - - - - - - - - - - - Number - - - - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - Number - - - - - - - - - - - - - - - - diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.b1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.b1.json index a91b75b79ec9c..9c0ed5462a217 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.b1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.b1.json @@ -20,8 +20,11 @@ "property": "pm25", "friendlyName": "PM2.5", "channel": "pm25", - "channelType": "pm25", "type": "Number", + "stateDescription": { + "pattern": "%.1f", + "readOnly": true + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -30,7 +33,7 @@ "property": "co2e", "friendlyName": "CO2e", "channel": "co2", - "channelType": "co2", + "description": "Carbon Dioxide", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -43,7 +46,7 @@ "property": "tvoc", "friendlyName": "tVOC", "channel": "tvoc", - "channelType": "tvoc", + "description": "Total Volatile Organic Compounds", "type": "Number", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.s1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.s1.json index 75202f8aaa163..95f00dbd8aa7c 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.s1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airmonitor.s1.json @@ -20,8 +20,11 @@ "property": "pm25", "friendlyName": "PM2.5", "channel": "pm25", - "channelType": "pm25", "type": "Number", + "stateDescription": { + "pattern": "%.1f", + "readOnly": true + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -30,7 +33,7 @@ "property": "co2", "friendlyName": "CO2", "channel": "co2", - "channelType": "co2", + "description": "Carbon Dioxide", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -45,7 +48,7 @@ "property": "tvoc", "friendlyName": "tVOC", "channel": "tvoc", - "channelType": "tvoc", + "description": "Total Volatile Organic Compounds", "type": "Number", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.m1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.m1.json index 3e2d57876aa59..8c5e79c704fe7 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.m1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.m1.json @@ -10,7 +10,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -46,7 +45,6 @@ "property": "wifi_led", "friendlyName": "Indicator light", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v1.json index 4d110f8e0dc53..854e43023f59b 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v1.json @@ -8,7 +8,6 @@ "property": "on", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,7 +25,6 @@ "property": "usb_on", "friendlyName": "USB", "channel": "usb", - "channelType": "usb", "type": "Switch", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v2.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v2.json index 243a5060b9969..f4197d977dc3b 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v2.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v2.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,7 +25,6 @@ "property": "usb_on", "friendlyName": "USB", "channel": "usb", - "channelType": "usb", "type": "Switch", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3.json index 4670777563b83..28f0aaa2ee77c 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3.json @@ -10,7 +10,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -29,7 +28,6 @@ "property": "usb_on", "friendlyName": "USB", "channel": "usb", - "channelType": "usb", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -62,7 +60,6 @@ "property": "wifi_led", "friendlyName": "Wifi LED", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/cuco.plug.cp1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/cuco.plug.cp1-miot.json index 970e625a68512..c74bc4d3b92c9 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/cuco.plug.cp1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/cuco.plug.cp1-miot.json @@ -12,7 +12,6 @@ "piid": 4, "friendlyName": "Device Information-CurrentFirmware Version", "channel": "FirmwareRevision", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [] @@ -23,7 +22,6 @@ "piid": 1, "friendlyName": "Device Information-Device Manufacturer", "channel": "Manufacturer", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [] @@ -34,7 +32,6 @@ "piid": 2, "friendlyName": "Device Information-Device Model", "channel": "Model", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [] @@ -45,7 +42,6 @@ "piid": 3, "friendlyName": "Device Information-Device Serial Number", "channel": "SerialNumber", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [] @@ -56,7 +52,6 @@ "piid": 1, "friendlyName": "Switch-Switch Status", "channel": "On", - "channelType": "miot_bool", "type": "Switch", "refresh": true, "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.a1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.a1.json index d0c1da4454bfb..35eb0c3abe90b 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.a1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.a1.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,8 +25,23 @@ "property": "mode", "friendlyName": "Mode", "channel": "airFreshMode", - "channelType": "airFreshMode", "type": "String", + "stateDescription": { + "options": [ + { + "value": "auto", + "label": "Auto" + }, + { + "value": "sleep", + "label": "Sleep" + }, + { + "value": "favourite", + "label": "Favorite" + } + ] + }, "refresh": true, "actions": [ { @@ -37,13 +51,13 @@ ], "tags": [ "Control" - ] + ], + "readmeComment": "Value mapping `[\"auto\"\u003d\"Auto\",\"sleep\"\u003d\"Sleep\",\"favourite\"\u003d\"Favorite\"]`" }, { "property": "ptc_on", "friendlyName": "PTC", "channel": "airFreshPTCPower", - "channelType": "airFreshPTCPower", "type": "Switch", "refresh": true, "actions": [ @@ -57,7 +71,6 @@ "property": "ptc_status", "friendlyName": "PTC Status", "channel": "airFreshPTCStatus", - "channelType": "airFreshPTCStatus", "type": "Switch", "refresh": true, "ChannelGroup": "Status", @@ -67,7 +80,6 @@ "property": "display", "friendlyName": "Display", "channel": "airFreshDisplay", - "channelType": "airFreshDisplay", "type": "Switch", "refresh": true, "actions": [ @@ -81,7 +93,6 @@ "property": "child_lock", "friendlyName": "Child Lock", "channel": "airFreshChildLock", - "channelType": "airFreshChildLock", "type": "Switch", "refresh": true, "actions": [ @@ -95,7 +106,6 @@ "property": "sound", "friendlyName": "Sound", "channel": "airFreshSound", - "channelType": "airFreshSound", "type": "Switch", "refresh": true, "actions": [ @@ -109,8 +119,10 @@ "property": "pm25", "friendlyName": "PM2.5", "channel": "airFreshPM25", - "channelType": "airFreshPM25", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -119,8 +131,10 @@ "property": "co2", "friendlyName": "CO2", "channel": "airFreshCO2", - "channelType": "airFreshCO2", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [], @@ -134,8 +148,10 @@ "property": "control_speed", "friendlyName": "Current Speed", "channel": "airFreshCurrentSpeed", - "channelType": "airFreshCurrentSpeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f m³/h" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -144,8 +160,12 @@ "property": "favourite_speed", "friendlyName": "Favorite Speed", "channel": "airFreshFavoriteSpeed", - "channelType": "airFreshFavoriteSpeed", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 300, + "pattern": "%.0f" + }, "refresh": true, "actions": [ { @@ -158,8 +178,10 @@ "property": "temperature_outside", "friendlyName": "Temperature Outside", "channel": "airFreshTemperature", - "channelType": "airFreshTemperature", "type": "Number", + "stateDescription": { + "pattern": "%.0f°C" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -168,8 +190,10 @@ "property": "filter_rate", "friendlyName": "Filter Percents Remaining", "channel": "airFreshFilterPercents", - "channelType": "airFreshFilterPercents", "type": "Number", + "stateDescription": { + "pattern": "%.0f%%" + }, "refresh": true, "actions": [] }, @@ -177,8 +201,10 @@ "property": "filter_day", "friendlyName": "Filter Days Remaining", "channel": "airFreshFilterDays", - "channelType": "airFreshFilterDays", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -187,7 +213,6 @@ "property": "", "friendlyName": "Reset Filter", "channel": "airFreshResetFilterA1", - "channelType": "airFreshResetFilterA1", "type": "String", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.t2017.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.t2017.json index 8485af890692a..f1929aa424919 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.t2017.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.airfresh.t2017.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,8 +25,23 @@ "property": "mode", "friendlyName": "Mode", "channel": "airFreshMode", - "channelType": "airFreshMode", "type": "String", + "stateDescription": { + "options": [ + { + "value": "auto", + "label": "Auto" + }, + { + "value": "sleep", + "label": "Sleep" + }, + { + "value": "favourite", + "label": "Favorite" + } + ] + }, "refresh": true, "actions": [ { @@ -37,13 +51,13 @@ ], "tags": [ "Control" - ] + ], + "readmeComment": "Value mapping `[\"auto\"\u003d\"Auto\",\"sleep\"\u003d\"Sleep\",\"favourite\"\u003d\"Favorite\"]`" }, { "property": "ptc_on", "friendlyName": "PTC", "channel": "airFreshPTCPower", - "channelType": "airFreshPTCPower", "type": "Switch", "refresh": true, "actions": [ @@ -57,21 +71,36 @@ "property": "ptc_level", "friendlyName": "PTC Level", "channel": "airFreshPtcLevel", - "channelType": "airFreshPtcLevel", "type": "String", + "stateDescription": { + "options": [ + { + "value": "low", + "label": "Low" + }, + { + "value": "medium", + "label": "Medium" + }, + { + "value": "high", + "label": "High" + } + ] + }, "refresh": true, "actions": [ { "command": "set_ptc_level", "parameterType": "STRING" } - ] + ], + "readmeComment": "Value mapping `[\"low\"\u003d\"Low\",\"medium\"\u003d\"Medium\",\"high\"\u003d\"High\"]`" }, { "property": "ptc_status", "friendlyName": "PTC Status", "channel": "airFreshPTCStatus", - "channelType": "airFreshPTCStatus", "type": "Switch", "refresh": true, "ChannelGroup": "Status", @@ -81,21 +110,36 @@ "property": "screen_direction", "friendlyName": "Screen direction", "channel": "airFreshDisplayDirection", - "channelType": "airFreshDisplayDirection", "type": "String", + "stateDescription": { + "options": [ + { + "value": "forward", + "label": "Normal" + }, + { + "value": "left", + "label": "Left" + }, + { + "value": "right", + "label": "Right" + } + ] + }, "refresh": true, "actions": [ { "command": "set_screen_direction", "parameterType": "STRING" } - ] + ], + "readmeComment": "Value mapping `[\"forward\"\u003d\"Normal\",\"left\"\u003d\"Left\",\"right\"\u003d\"Right\"]`" }, { "property": "display", "friendlyName": "Display", "channel": "airFreshDisplay", - "channelType": "airFreshDisplay", "type": "Switch", "refresh": true, "actions": [ @@ -109,7 +153,6 @@ "property": "child_lock", "friendlyName": "Child Lock", "channel": "airFreshChildLock", - "channelType": "airFreshChildLock", "type": "Switch", "refresh": true, "actions": [ @@ -123,7 +166,6 @@ "property": "sound", "friendlyName": "Sound", "channel": "airFreshSound", - "channelType": "airFreshSound", "type": "Switch", "refresh": true, "actions": [ @@ -137,8 +179,10 @@ "property": "pm25", "friendlyName": "PM2.5", "channel": "airFreshPM25", - "channelType": "airFreshPM25", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -147,8 +191,10 @@ "property": "co2", "friendlyName": "CO2", "channel": "airFreshCO2", - "channelType": "airFreshCO2", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [], @@ -162,8 +208,10 @@ "property": "control_speed", "friendlyName": "Current Speed", "channel": "airFreshCurrentSpeed", - "channelType": "airFreshCurrentSpeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f m³/h" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -172,8 +220,12 @@ "property": "favourite_speed", "friendlyName": "Favorite Speed", "channel": "airFreshFavoriteSpeed", - "channelType": "airFreshFavoriteSpeed", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 300, + "pattern": "%.0f" + }, "refresh": true, "actions": [ { @@ -186,8 +238,10 @@ "property": "temperature_outside", "friendlyName": "Temperature Outside", "channel": "airFreshTemperature", - "channelType": "airFreshTemperature", "type": "Number", + "stateDescription": { + "pattern": "%.0f°C" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -196,8 +250,10 @@ "property": "filter_intermediate", "friendlyName": "Filter Percents Remaining", "channel": "airFreshFilterPercents", - "channelType": "airFreshFilterPercents", "type": "Number", + "stateDescription": { + "pattern": "%.0f%%" + }, "refresh": true, "actions": [] }, @@ -205,8 +261,10 @@ "property": "filter_inter_day", "friendlyName": "Filter Days Remaining", "channel": "airFreshFilterDays", - "channelType": "airFreshFilterDays", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -215,8 +273,10 @@ "property": "filter_efficient", "friendlyName": "Filter Pro Percents Remaining", "channel": "airFreshFilterProPercents", - "channelType": "airFreshFilterProPercents", "type": "Number", + "stateDescription": { + "pattern": "%.0f%%" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -225,8 +285,10 @@ "property": "filter_effi_day", "friendlyName": "Filter Pro Days Remaining", "channel": "airFreshFilterProDays", - "channelType": "airFreshFilterProDays", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -235,7 +297,6 @@ "property": "", "friendlyName": "Reset Filter", "channel": "airFreshResetFilter", - "channelType": "airFreshResetFilter", "type": "String", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p5.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p5.json index f032281ea9af0..743a6a08caa53 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p5.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p5.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -39,7 +38,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -57,8 +55,13 @@ "property": "roll_angle", "friendlyName": "Angle", "channel": "angle", - "channelType": "angle", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 360, + "step": 1, + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -128,8 +131,10 @@ "property": "speed", "friendlyName": "Speed", "channel": "speed", - "channelType": "speed", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/lumi.curtain.hagl05-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/lumi.curtain.hagl05-miot.json index e1c562d576045..ce6fda7cb3bef 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/lumi.curtain.hagl05-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/lumi.curtain.hagl05-miot.json @@ -12,7 +12,6 @@ "piid": 1, "friendlyName": "Curtain - Device Fault", "channel": "fault", - "channelType": "LumiCurtainHagl05_fault", "type": "Number", "stateDescription": { "readOnly": true, @@ -27,14 +26,57 @@ "actions": [], "readmeComment": "Value mapping `[\"0\"\u003d\"No faults\"]`" }, + { + "property": "motor-control", + "siid": 2, + "piid": 2, + "friendlyName": "Curtain - Motor Control", + "channel": "motor_control", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Pause" + }, + { + "value": "1", + "label": "Open" + }, + { + "value": "2", + "label": "Close" + }, + { + "value": "3", + "label": "auto" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Pause\",\"1\"\u003d\"Open\",\"2\"\u003d\"Close\",\"3\"\u003d\"auto\"]`" + }, { "property": "current-position", "siid": 2, "piid": 3, "friendlyName": "Curtain - Current Position", "channel": "current-position", - "channelType": "miot_uint8", - "type": "Number", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, "refresh": true, "actions": [] }, @@ -44,7 +86,6 @@ "piid": 6, "friendlyName": "Curtain - Status", "channel": "status", - "channelType": "LumiCurtainHagl05_status", "type": "Number", "stateDescription": { "readOnly": true, @@ -77,8 +118,14 @@ "piid": 7, "friendlyName": "Curtain - Target Position", "channel": "target-position", - "channelType": "miot_uint8", - "type": "Number", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%" + }, "refresh": true, "actions": [ { @@ -93,7 +140,6 @@ "piid": 1, "friendlyName": "curtain_cfg - Manual Enabled", "channel": "manual-enabled", - "channelType": "LumiCurtainHagl05_manual-enabled", "type": "Number", "stateDescription": { "options": [ @@ -120,9 +166,8 @@ "property": "polarity", "siid": 4, "piid": 2, - "friendlyName": "curtain_cfg - Polarity", + "friendlyName": "Curtain_cfg - Polarity", "channel": "polarity", - "channelType": "LumiCurtainHagl05_polarity", "type": "Number", "stateDescription": { "options": [ @@ -151,7 +196,6 @@ "piid": 3, "friendlyName": "curtain_cfg - Position Limit", "channel": "pos-limit", - "channelType": "LumiCurtainHagl05_pos-limit", "type": "Number", "stateDescription": { "options": [ @@ -178,10 +222,9 @@ "property": "en-night-tip-light", "siid": 4, "piid": 4, - "friendlyName": "Set Night Tip Light", - "channel": "en-night-tip-light", - "channelType": "LumiCurtainHagl05_en-night-tip-light", - "type": "Switch", + "friendlyName": "Curtain_cfg - En_night_tip_light", + "channel": "en_night_tip_light", + "type": "Number", "stateDescription": { "options": [ { @@ -207,12 +250,39 @@ "property": "run-time", "siid": 4, "piid": 5, - "friendlyName": "curtain_cfg - Run-time", + "friendlyName": "Curtain_cfg - Run-time", "channel": "run-time", - "channelType": "miot_int32", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 255, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, "refresh": true, "actions": [] + }, + { + "property": "adjust-value", + "siid": 5, + "piid": 1, + "friendlyName": "Motor_controller - Adjust_value", + "channel": "adjust_value", + "type": "Number", + "stateDescription": { + "minimum": -100, + "maximum": 100, + "step": 1, + "pattern": "%.0f" + }, + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] } ], "experimental": true diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bceiling1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bceiling1.json index 69b4aad9962b0..8998b0e8e2937 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bceiling1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bceiling1.json @@ -13,7 +13,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -59,7 +58,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "actions": [ @@ -73,7 +71,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "actions": [ @@ -87,7 +84,6 @@ "property": "dv", "friendlyName": "DV", "channel": "dv", - "channelType": "dv", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -149,7 +145,6 @@ "property": "", "friendlyName": "Delay Off", "channel": "delayoff", - "channelType": "delayoff", "type": "Switch", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bulb.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bulb.json index 6285f85096d38..8cfdb128422b7 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bulb.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.bulb.json @@ -13,7 +13,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -60,7 +59,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "ChannelGroup": "actions", @@ -75,7 +73,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -90,7 +87,6 @@ "property": "dv", "friendlyName": "DV", "channel": "dv", - "channelType": "dv", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -118,7 +114,6 @@ "property": "", "friendlyName": "Delay Off", "channel": "delayoff", - "channelType": "delayoff", "type": "Switch", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.candle.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.candle.json index 05e14e54371f3..517502b1554ce 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.candle.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.candle.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -56,7 +55,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "ChannelGroup": "actions", @@ -71,7 +69,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -86,7 +83,6 @@ "property": "", "friendlyName": "Delay Off", "channel": "delayoff", - "channelType": "delayoff", "type": "Switch", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.cbulb.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.cbulb.json index 99d6fde03a180..a7b8c4eaf9282 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.cbulb.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.cbulb.json @@ -10,7 +10,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -57,7 +56,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "ChannelGroup": "actions", @@ -72,7 +70,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -129,7 +126,6 @@ "property": "", "friendlyName": "Delay Off", "channel": "delayoff", - "channelType": "delayoff", "type": "Switch", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceil-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceil-miot.json index 5a45e63c8cb54..2304d9a062d83 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceil-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceil-miot.json @@ -24,7 +24,6 @@ "piid": 1, "friendlyName": "Power", "channel": "on", - "channelType": "miot_bool", "type": "Switch", "refresh": true, "actions": [ @@ -44,7 +43,6 @@ "piid": 2, "friendlyName": "Mode", "channel": "mode", - "channelType": "miot_uint8", "type": "Number", "refresh": true, "actions": [ @@ -83,7 +81,6 @@ "piid": 4, "friendlyName": "Color Temperature", "channel": "cct", - "channelType": "miot_uint32", "type": "Number", "refresh": true, "actions": [ @@ -99,8 +96,13 @@ "piid": 1, "friendlyName": "Delayed Turn-off", "channel": "dv", - "channelType": "miot_uint16", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 21600, + "step": 1, + "pattern": "%.0f %unit%" + }, "refresh": true, "actions": [ { @@ -115,7 +117,6 @@ "piid": 2, "friendlyName": "Wall Scene Enable", "channel": "WallSceneEn", - "channelType": "miot_bool", "type": "Switch", "refresh": true, "actions": [ @@ -131,7 +132,6 @@ "piid": 3, "friendlyName": "Wall Scene", "channel": "WallScene", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [ @@ -147,7 +147,6 @@ "piid": 4, "friendlyName": "Auto CCT", "channel": "autoCct", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [ @@ -163,8 +162,13 @@ "piid": 6, "friendlyName": "Dimming Period", "channel": "dimmingPeriod", - "channelType": "miot_uint16", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 65535, + "step": 1, + "pattern": "%.0f" + }, "refresh": true, "actions": [ { @@ -179,10 +183,77 @@ "piid": 12, "friendlyName": "Mi Band Status", "channel": "MibandStatus", - "channelType": "miot_string", "type": "String", "refresh": true, "actions": [] + }, + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "light-brightness-down", + "label": "Light Brightness Down" + }, + { + "value": "light-brightness-up", + "label": "Light Brightness Up" + }, + { + "value": "light-toggle", + "label": "Light Toggle" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "light-brightness-down" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "light-brightness-up" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 3, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "light-toggle" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"light-brightness-down\"\u003d\"Light Brightness Down\",\"light-brightness-up\"\u003d\"Light Brightness Up\",\"light-toggle\"\u003d\"Light Toggle\"]`" } ], "experimental": true diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceiling.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceiling.json index 17e1051c3a0bc..42a4972717c91 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceiling.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.ceiling.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -56,7 +55,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "ChannelGroup": "actions", @@ -71,7 +69,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.mono.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.mono.json index bebb00d60e872..ada9d8256fac5 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.mono.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.mono.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -55,7 +54,6 @@ "property": "scene_num", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.moonlight.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.moonlight.json index bb705f6ac244f..2ec405f496a85 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.moonlight.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.moonlight.json @@ -8,7 +8,6 @@ "property": "pow", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -51,7 +50,6 @@ "property": "cct", "friendlyName": "Correlated Color Temperature", "channel": "cct", - "channelType": "cct", "type": "Dimmer", "refresh": true, "ChannelGroup": "actions", @@ -66,7 +64,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -81,7 +78,6 @@ "property": "dv", "friendlyName": "DV", "channel": "dv", - "channelType": "dv", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -95,7 +91,6 @@ "property": "", "friendlyName": "Go Night", "channel": "gonight", - "channelType": "gonight", "type": "Switch", "refresh": false, "ChannelGroup": "actions", @@ -110,7 +105,6 @@ "property": "", "friendlyName": "Delay Off", "channel": "delayoff", - "channelType": "delayoff", "type": "Switch", "refresh": false, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.rwread.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.rwread.json index b3f9279f20103..5e74a45785448 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.rwread.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.rwread.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -55,7 +54,6 @@ "property": "snm", "friendlyName": "Scene", "channel": "scene", - "channelType": "scene", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -83,7 +81,6 @@ "property": "dv", "friendlyName": "DV", "channel": "dv", - "channelType": "dv", "type": "Number", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.sread1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.sread1.json index 7b4237ce981d2..42b02375d1dae 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.sread1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/philips.light.sread1.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -56,7 +55,6 @@ "property": "ambstatus", "friendlyName": "Ambient Power", "channel": "ambientPower", - "channelType": "ambientPower", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -71,7 +69,6 @@ "property": "ambvalue", "friendlyName": "Ambient Brightness", "channel": "ambientBrightness", - "channelType": "ambientBrightness", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -86,8 +83,11 @@ "property": "dvalue", "friendlyName": "Ambient Illumination", "channel": "illumination", - "channelType": "illumination", "type": "Number", + "stateDescription": { + "pattern": "%.1f", + "readOnly": true + }, "refresh": true, "actions": [] }, @@ -95,7 +95,6 @@ "property": "eyecare", "friendlyName": "Eyecare", "channel": "eyecare", - "channelType": "eyecare", "type": "Switch", "refresh": true, "ChannelGroup": "actions", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/qmi.powerstrip.v1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/qmi.powerstrip.v1.json index 369b220eaaf23..d5d68e3152e6f 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/qmi.powerstrip.v1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/qmi.powerstrip.v1.json @@ -89,7 +89,6 @@ "property": "wifi_led", "friendlyName": "wifi LED", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/scishare.coffee.s1102.json b/bundles/org.openhab.binding.miio/src/main/resources/database/scishare.coffee.s1102.json index b49a64da81afa..ca1e246b98485 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/scishare.coffee.s1102.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/scishare.coffee.s1102.json @@ -9,7 +9,6 @@ "property": "", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": false, "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json index 115f948a68d7d..efc34cbc5932e 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json @@ -12,7 +12,6 @@ "channel": "vacuumaction", "type": "String", "stateDescription": { - "readOnly": true, "options": [ { "value": "start-sweep", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json index 6aa4387dd9962..1a7de8e576dff 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json @@ -10,8 +10,23 @@ "property": "", "friendlyName": "Vacuum Action", "channel": "vacuumaction", - "channelType": "vacuumaction", "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "Start" + }, + { + "value": "0", + "label": "Stop" + }, + { + "value": "2", + "label": "Pause" + } + ] + }, "refresh": false, "actions": [ { @@ -23,13 +38,13 @@ 0 ] } - ] + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Start\",\"0\"\u003d\"Stop\",\"2\"\u003d\"Pause\"]`" }, { "property": "run_state", "friendlyName": "State", "channel": "state", - "channelType": "state", "type": "Number", "refresh": true, "actions": [] @@ -38,7 +53,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "Number", "refresh": true, "actions": [ diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/xiaomi.aircondition.mc1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/xiaomi.aircondition.mc1-miot.json index 144bcb234c098..96879ececfab4 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/xiaomi.aircondition.mc1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/xiaomi.aircondition.mc1-miot.json @@ -94,7 +94,6 @@ "stateDescription": { "minimum": 16, "maximum": 31, - "step": 0.0, "pattern": "%.1f %unit%" }, "refresh": true, @@ -351,13 +350,12 @@ "piid": 3, "friendlyName": "Electricity - Count", "channel": "elec-count", - "channelType": "miot_uint16", "type": "Number", "stateDescription": { "minimum": 0, "maximum": 65535, "step": 1, - "pattern": "%.1f", + "pattern": "%.0f", "readOnly": true }, "refresh": true, diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.bhf1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.bhf1.json index badbcecd62aa4..b14bbeca8a71a 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.bhf1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.bhf1.json @@ -107,7 +107,6 @@ "property": "nl_br", "friendlyName": "Nightlight Brightness", "channel": "nightlightBrightness", - "channelType": "nightlightBrightness", "type": "Number", "refresh": true, "actions": [], diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling.json b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling.json index 8bb665c0921ec..09851a3c2b157 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling.json @@ -230,7 +230,6 @@ "property": "", "friendlyName": "Set Scene", "channel": "customScene", - "channelType": "customScene", "type": "String", "refresh": false, "ChannelGroup": "actions", @@ -245,7 +244,6 @@ "property": "nl_br", "friendlyName": "Nightlight Brightness", "channel": "nightlightBrightness", - "channelType": "nightlightBrightness", "type": "Number", "refresh": true, "actions": [], diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling2.json b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling2.json index 66ebf9009ae49..c6cc80f464ccd 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling2.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling2.json @@ -204,7 +204,6 @@ "property": "", "friendlyName": "Set Scene", "channel": "customScene", - "channelType": "customScene", "type": "String", "refresh": false, "ChannelGroup": "actions", @@ -219,7 +218,6 @@ "property": "nl_br", "friendlyName": "Nightlight Brightness", "channel": "nightlightBrightness", - "channelType": "nightlightBrightness", "type": "Number", "refresh": true, "actions": [], diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling4.json b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling4.json index 5af25be9960c2..064f54009db18 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling4.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.ceiling4.json @@ -229,7 +229,6 @@ "property": "bg_power", "friendlyName": "Ambient Power", "channel": "ambientPower", - "channelType": "ambientPower", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -244,7 +243,6 @@ "property": "bg_rgb", "friendlyName": "Ambient Color", "channel": "ambientColor", - "channelType": "ambientColor", "type": "Color", "refresh": true, "ChannelGroup": "actions", @@ -259,7 +257,6 @@ "property": "bg_ct", "friendlyName": "Ambient Color Temperature", "channel": "ambientColorTemperature", - "channelType": "ambientColorTemperature", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -279,7 +276,6 @@ "property": "", "friendlyName": "Set Scene", "channel": "customScene", - "channelType": "customScene", "type": "String", "refresh": false, "ChannelGroup": "actions", @@ -294,7 +290,6 @@ "property": "bg_lmode", "friendlyName": "Ambient Color Mode", "channel": "ambientColorMode", - "channelType": "ambientColorMode", "type": "Number", "refresh": true, "actions": [] @@ -303,7 +298,6 @@ "property": "nl_br", "friendlyName": "Nightlight Brightness", "channel": "nightlightBrightness", - "channelType": "nightlightBrightness", "type": "Number", "refresh": true, "actions": [], diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.light15.json b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.light15.json index 0390aab285b8e..fac444533ff06 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.light15.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/yeelink.light.light15.json @@ -232,7 +232,6 @@ "property": "bg_bright", "friendlyName": "Ambient Brightness", "channel": "ambientBrightness", - "channelType": "ambientBrightness", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -247,7 +246,6 @@ "property": "bg_power", "friendlyName": "Ambient Power", "channel": "ambientPower", - "channelType": "ambientPower", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -262,7 +260,6 @@ "property": "bg_rgb", "friendlyName": "Ambient Color", "channel": "ambientColor", - "channelType": "ambientColor", "type": "Color", "refresh": true, "ChannelGroup": "actions", @@ -277,7 +274,6 @@ "property": "bg_ct", "friendlyName": "Ambient Color Temperature", "channel": "ambientColorTemperature", - "channelType": "ambientColorTemperature", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -297,7 +293,6 @@ "property": "bg_lmode", "friendlyName": "Ambient Color Mode", "channel": "ambientColorMode", - "channelType": "ambientColorMode", "type": "Number", "refresh": true, "actions": [] diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airmonitor.v1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airmonitor.v1.json index f2c2a7c92a6e6..6e2736d98d4ee 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airmonitor.v1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airmonitor.v1.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,7 +25,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.m1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.m1.json index f2f73e769545a..e90c98a859770 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.m1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.m1.json @@ -19,7 +19,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -37,7 +36,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "String", "stateDescription": { "options": [ @@ -102,7 +100,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -115,7 +112,6 @@ "property": "average_aqi", "friendlyName": "Average Air Quality Index", "channel": "averageaqi", - "channelType": "averageaqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -128,7 +124,6 @@ "property": "led", "friendlyName": "LED Status", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -143,7 +138,6 @@ "property": "buzzer", "friendlyName": "Buzzer Status", "channel": "buzzer", - "channelType": "buzzer", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -158,7 +152,6 @@ "property": "f1_hour", "friendlyName": "Filter Max Life", "channel": "filtermaxlife", - "channelType": "filtermaxlife", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -168,9 +161,11 @@ "property": "f1_hour_used", "friendlyName": "Filter Hours used", "channel": "filterhours", - "channelType": "filterhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -181,9 +176,11 @@ "property": "use_time", "friendlyName": "Run Time", "channel": "usedhours", - "channelType": "usedhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -194,8 +191,10 @@ "property": "motor1_speed", "friendlyName": "Motor Speed", "channel": "motorspeed", - "channelType": "motorspeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f rpm" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -315,9 +314,11 @@ "property": "purify_volume", "friendlyName": "Purified Volume", "channel": "purifyvolume", - "channelType": "purifyvolume", "type": "Number:Volume", "unit": "liter", + "stateDescription": { + "pattern": "%.0f m3" + }, "refresh": true, "ChannelGroup": "Status", "actions": [], diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v1.json index 47952528d3aec..81b03943a89e2 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v1.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,7 +25,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "String", "refresh": true, "ChannelGroup": "actions", @@ -59,7 +57,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -91,7 +88,6 @@ "property": "led", "friendlyName": "LED Status", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -106,7 +102,6 @@ "property": "act_det", "friendlyName": "Air AutoDetect", "channel": "act_det", - "channelType": "act_det", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -116,7 +111,6 @@ "property": "buzzer", "friendlyName": "Buzzer Status", "channel": "buzzer", - "channelType": "buzzer", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -131,7 +125,6 @@ "property": "f1_hour", "friendlyName": "Filter Max Life", "channel": "filtermaxlife", - "channelType": "filtermaxlife", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -141,8 +134,10 @@ "property": "filter1_life", "friendlyName": "Filter Life", "channel": "filterlive", - "channelType": "filterlive", "type": "Number", + "stateDescription": { + "pattern": "%.0f%%" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v6.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v6.json index 92299edb63f50..7642d5b7b3b62 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v6.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v6.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -27,7 +26,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "String", "refresh": true, "ChannelGroup": "actions", @@ -60,7 +58,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -73,7 +70,6 @@ "property": "average_aqi", "friendlyName": "Average Air Quality Index", "channel": "averageaqi", - "channelType": "averageaqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -86,7 +82,6 @@ "property": "led", "friendlyName": "LED Status", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -120,7 +115,6 @@ "property": "f1_hour", "friendlyName": "Filter Max Life", "channel": "filtermaxlife", - "channelType": "filtermaxlife", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -130,9 +124,11 @@ "property": "f1_hour_used", "friendlyName": "Filter Hours used", "channel": "filterhours", - "channelType": "filterhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -143,9 +139,11 @@ "property": "use_time", "friendlyName": "Run Time", "channel": "usedhours", - "channelType": "usedhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -156,8 +154,10 @@ "property": "motor1_speed", "friendlyName": "Motor Speed", "channel": "motorspeed", - "channelType": "motorspeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f rpm" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -175,8 +175,10 @@ "property": "favorite_level", "friendlyName": "Favorite Level", "channel": "favoritelevel", - "channelType": "favoritelevel", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [ @@ -210,8 +212,10 @@ "property": "purify_volume", "friendlyName": "Purivied Volume", "channel": "purifyvolume", - "channelType": "purifyvolume", "type": "Number", + "stateDescription": { + "pattern": "%.0f m3" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -220,7 +224,6 @@ "property": "child_lock", "friendlyName": "Child Lock", "channel": "childlock", - "channelType": "childlock", "type": "Switch", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v7.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v7.json index 68e75135cb974..42fb5c90ccc43 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v7.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.v7.json @@ -8,7 +8,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -26,7 +25,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "String", "refresh": true, "ChannelGroup": "actions", @@ -59,7 +57,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -72,7 +69,6 @@ "property": "average_aqi", "friendlyName": "Average Air Quality Index", "channel": "averageaqi", - "channelType": "averageaqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -94,7 +90,6 @@ "property": "led", "friendlyName": "LED Status", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -123,7 +118,6 @@ "property": "f1_hour", "friendlyName": "Filter Max Life", "channel": "filtermaxlife", - "channelType": "filtermaxlife", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -133,9 +127,11 @@ "property": "f1_hour_used", "friendlyName": "Filter Hours used", "channel": "filterhours", - "channelType": "filterhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -146,8 +142,10 @@ "property": "motor1_speed", "friendlyName": "Motor Speed", "channel": "motorspeed", - "channelType": "motorspeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f rpm" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -174,8 +172,10 @@ "property": "favorite_level", "friendlyName": "Favorite Level", "channel": "favoritelevel", - "channelType": "favoritelevel", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "Status", "actions": [ @@ -209,7 +209,6 @@ "property": "child_lock", "friendlyName": "Child Lock", "channel": "childlock", - "channelType": "childlock", "type": "Switch", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.fan.za4.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.fan.za4.json index 90c95b04499db..9c7cf22894dcd 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.fan.za4.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.fan.za4.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -27,7 +26,6 @@ "property": "angle_enable", "friendlyName": "Rotation", "channel": "angleEnable", - "channelType": "angleEnable", "type": "Switch", "refresh": true, "actions": [ @@ -41,9 +39,11 @@ "property": "use_time", "friendlyName": "Run Time", "channel": "usedhours", - "channelType": "usedhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -54,8 +54,13 @@ "property": "angle", "friendlyName": "Angle", "channel": "angle", - "channelType": "angle", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 360, + "step": 1, + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -69,8 +74,13 @@ "property": "poweroff_time", "friendlyName": "Timer", "channel": "poweroffTime", - "channelType": "poweroffTime", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 28800, + "step": 1, + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -84,7 +94,6 @@ "property": "buzzer", "friendlyName": "Buzzer", "channel": "buzzer", - "channelType": "buzzer", "type": "Number", "refresh": true, "ChannelGroup": "actions", @@ -127,8 +136,13 @@ "property": "speed_level", "friendlyName": "Speed Level", "channel": "speedLevel", - "channelType": "speedLevel", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 99, + "step": 1, + "pattern": "%.0f%%" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -142,8 +156,10 @@ "property": "speed", "friendlyName": "Speed", "channel": "speed", - "channelType": "speed", "type": "Number", + "stateDescription": { + "pattern": "%.0f" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -157,8 +173,13 @@ "property": "natural_level", "friendlyName": "Natural Level", "channel": "naturalLevel", - "channelType": "naturalLevel", "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 99, + "step": 1, + "pattern": "%.0f%%" + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -172,8 +193,23 @@ "property": "", "friendlyName": "Move Direction", "channel": "move", - "channelType": "move", "type": "String", + "stateDescription": { + "options": [ + { + "value": "", + "label": "None" + }, + { + "value": "left", + "label": "Left" + }, + { + "value": "right", + "label": "Right" + } + ] + }, "refresh": true, "ChannelGroup": "actions", "actions": [ @@ -181,7 +217,8 @@ "command": "set_move", "parameterType": "STRING" } - ] + ], + "readmeComment": "Value mapping `[\"\"\u003d\"None\",\"left\"\u003d\"Left\",\"right\"\u003d\"Right\"]`" } ] } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.humidifier.v1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.humidifier.v1.json index a21ff474e2c31..f64237fa045c7 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.humidifier.v1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.humidifier.v1.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -27,7 +26,6 @@ "property": "mode", "friendlyName": "Mode", "channel": "mode", - "channelType": "mode", "type": "String", "refresh": true, "ChannelGroup": "actions", @@ -60,7 +58,6 @@ "property": "limit_hum", "friendlyName": "Humidity Set", "channel": "setHumidity", - "channelType": "setHumidity", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -75,7 +72,6 @@ "property": "aqi", "friendlyName": "Air Quality Index", "channel": "aqi", - "channelType": "aqi", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -88,7 +84,6 @@ "property": "trans_level", "friendlyName": "Trans_level", "channel": "translevel", - "channelType": "translevel", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -112,7 +107,6 @@ "property": "buzzer", "friendlyName": "Buzzer Status", "channel": "buzzer", - "channelType": "buzzer", "type": "Switch", "refresh": true, "ChannelGroup": "actions", @@ -127,7 +121,6 @@ "property": "depth", "friendlyName": "Depth", "channel": "depth", - "channelType": "depth", "type": "Number", "refresh": true, "ChannelGroup": "Status", @@ -137,7 +130,6 @@ "property": "dry", "friendlyName": "Dry", "channel": "dry", - "channelType": "dry", "type": "Switch", "refresh": true, "ChannelGroup": "Status", @@ -152,9 +144,11 @@ "property": "use_time", "friendlyName": "Run Time", "channel": "usedhours", - "channelType": "usedhours", "type": "Number:Time", "unit": "hours", + "stateDescription": { + "pattern": "%.0f %unit%" + }, "refresh": true, "transformation": "SecondsToHours", "ChannelGroup": "Status", @@ -165,8 +159,10 @@ "property": "speed", "friendlyName": "Motor Speed", "channel": "motorspeed", - "channelType": "motorspeed", "type": "Number", + "stateDescription": { + "pattern": "%.0f rpm" + }, "refresh": true, "ChannelGroup": "Status", "actions": [] @@ -195,7 +191,6 @@ "property": "child_lock", "friendlyName": "Child Lock", "channel": "childlock", - "channelType": "childlock", "type": "Switch", "refresh": true, "ChannelGroup": "Status", diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zimi.powerstrip.v2.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zimi.powerstrip.v2.json index 411e576130163..ca8547bf895a6 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zimi.powerstrip.v2.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zimi.powerstrip.v2.json @@ -9,7 +9,6 @@ "property": "power", "friendlyName": "Power", "channel": "power", - "channelType": "power", "type": "Switch", "refresh": true, "actions": [ @@ -27,8 +26,10 @@ "property": "power_consume_rate", "friendlyName": "Power Consumption", "channel": "powerUsage", - "channelType": "powerUsage", "type": "Number", + "stateDescription": { + "pattern": "%.0fW" + }, "refresh": true, "actions": [ { @@ -40,7 +41,6 @@ "property": "wifi_led", "friendlyName": "wifi LED", "channel": "led", - "channelType": "led", "type": "Switch", "refresh": true, "actions": [ @@ -67,8 +67,10 @@ "property": "current", "friendlyName": "Current", "channel": "current", - "channelType": "current", "type": "Number", + "stateDescription": { + "pattern": "%.2fA" + }, "refresh": true, "actions": [] }, From 70f72defea245baafbc0a5cdd3a225fedbc9ceb9 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 20 Nov 2021 12:34:00 +0100 Subject: [PATCH 117/361] [miio] add support Mi Smart Humidifier deerma.humidifier.jsq5 (#11577) https://community.openhab.org/t/mi-smart-antibacterial-humidifier-not-recognized/127562 Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 34 +++ .../binding/miio/internal/MiIoDevices.java | 1 + .../database/deerma.humidifier.jsq5.json | 214 ++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 1a3a95208019f..c8251f60c5829 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -205,6 +205,7 @@ Currently the miio binding supports more than 300 different models. | Gosund Smart Plug | miio:basic | [cuco.plug.cp1](#cuco-plug-cp1) | Yes | | | Mi Smart Antibacterial Humidifier | miio:basic | [deerma.humidifier.jsq](#deerma-humidifier-jsq) | Yes | | | Mi S Smart Humidifer | miio:basic | [deerma.humidifier.jsq1](#deerma-humidifier-jsq1) | Yes | | +| Mi Smart Antibacterial Humidifier | miio:basic | [deerma.humidifier.jsq5](#deerma-humidifier-jsq5) | Yes | | | Mi Smart Humidifier | miio:basic | [deerma.humidifier.mjjsq](#deerma-humidifier-mjjsq) | Yes | | | Mi Fresh Air Ventilator A1-150 | miio:basic | [dmaker.airfresh.a1](#dmaker-airfresh-a1) | Yes | | | Mi Fresh Air Ventilator | miio:basic | [dmaker.airfresh.t2017](#dmaker-airfresh-t2017) | Yes | | @@ -794,6 +795,21 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | watertankstatus | Number | Watertank Status | | | wet_and_protect | Switch | Wet and Protect | | +### Mi Smart Antibacterial Humidifier (deerma.humidifier.jsq5) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| on | Switch | Humidifier - Switch Status | | +| fault | Number | Humidifier - Device Fault | Value mapping `["0"="No Faults","1"="Insufficient Water","2"="Water Separation"]` | +| fan_level | Number | Humidifier - Fan Level | Value mapping `["1"="Level1","2"="Level2","3"="Level3","4"="Humidity"]` | +| target_humidity | Number:Dimensionless | Humidifier - Target Humidity | | +| relative_humidity | Number:Dimensionless | Environment - Relative Humidity | | +| temperature | Number:Temperature | Environment - Temperature | | +| alarm | Switch | Alarm - Alarm | | +| on1 | Switch | Indicator Light - Switch Status | | +| water_shortage_fault | Switch | Custom - Water Shortage Fault | | +| the_tank_filed | Switch | Custom - The Tank Filed | | + ### Mi Smart Humidifier (deerma.humidifier.mjjsq) Channels | Channel | Type | Description | Comment | @@ -5589,6 +5605,24 @@ Number watertankstatus "Watertank Status" (G_humidifier) {channel="miio:basic:hu Switch wet_and_protect "Wet and Protect" (G_humidifier) {channel="miio:basic:humidifier:wet_and_protect"} ``` +### Mi Smart Antibacterial Humidifier (deerma.humidifier.jsq5) item file lines + +note: Autogenerated example. Replace the id (humidifier) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_humidifier "Mi Smart Antibacterial Humidifier" +Switch on "Humidifier - Switch Status" (G_humidifier) {channel="miio:basic:humidifier:on"} +Number fault "Humidifier - Device Fault" (G_humidifier) {channel="miio:basic:humidifier:fault"} +Number fan_level "Humidifier - Fan Level" (G_humidifier) {channel="miio:basic:humidifier:fan_level"} +Number:Dimensionless target_humidity "Humidifier - Target Humidity" (G_humidifier) {channel="miio:basic:humidifier:target_humidity"} +Number:Dimensionless relative_humidity "Environment - Relative Humidity" (G_humidifier) {channel="miio:basic:humidifier:relative_humidity"} +Number:Temperature temperature "Environment - Temperature" (G_humidifier) {channel="miio:basic:humidifier:temperature"} +Switch alarm "Alarm - Alarm" (G_humidifier) {channel="miio:basic:humidifier:alarm"} +Switch on1 "Indicator Light - Switch Status" (G_humidifier) {channel="miio:basic:humidifier:on1"} +Switch water_shortage_fault "Custom - Water Shortage Fault" (G_humidifier) {channel="miio:basic:humidifier:water_shortage_fault"} +Switch the_tank_filed "Custom - The Tank Filed" (G_humidifier) {channel="miio:basic:humidifier:the_tank_filed"} +``` + ### Mi Smart Humidifier (deerma.humidifier.mjjsq) item file lines note: Autogenerated example. Replace the id (humidifier) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java index dbc8a17a59d9e..e8e89b15ba7f4 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java @@ -51,6 +51,7 @@ public enum MiIoDevices { CUCO_PLUG_CP1("cuco.plug.cp1", "Gosund Smart Plug", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_JSQ("deerma.humidifier.jsq", "Mi Smart Antibacterial Humidifier", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_JSQ1("deerma.humidifier.jsq1", "Mi S Smart Humidifer ", THING_TYPE_BASIC), + DEERMA_HUMIDIFIER_JSQ5("deerma.humidifier.jsq5", "Mi Smart Antibacterial Humidifier", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_MJJSQ("deerma.humidifier.mjjsq", "Mi Smart Humidifier", THING_TYPE_BASIC), DMAKER_AIRFRESH_A1("dmaker.airfresh.a1", "Mi Fresh Air Ventilator A1-150", THING_TYPE_BASIC), DMAKER_AIRFRESH_T2017("dmaker.airfresh.t2017", "Mi Fresh Air Ventilator", THING_TYPE_BASIC), diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json b/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json new file mode 100644 index 0000000000000..9a8cfbc9a93f0 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json @@ -0,0 +1,214 @@ +{ + "deviceMapping": { + "id": [ + "deerma.humidifier.jsq5" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "on", + "siid": 2, + "piid": 1, + "friendlyName": "Humidifier - Switch Status", + "channel": "on", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ], + "category": "switch", + "tags": [ + "Switch" + ] + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Humidifier - Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Faults" + }, + { + "value": "1", + "label": "Insufficient Water" + }, + { + "value": "2", + "label": "Water Separation" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Faults\",\"1\"\u003d\"Insufficient Water\",\"2\"\u003d\"Water Separation\"]`" + }, + { + "property": "fan-level", + "siid": 2, + "piid": 5, + "friendlyName": "Humidifier - Fan Level", + "channel": "fan_level", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "Level1" + }, + { + "value": "2", + "label": "Level2" + }, + { + "value": "3", + "label": "Level3" + }, + { + "value": "4", + "label": "Humidity" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Level1\",\"2\"\u003d\"Level2\",\"3\"\u003d\"Level3\",\"4\"\u003d\"Humidity\"]`" + }, + { + "property": "target-humidity", + "siid": 2, + "piid": 6, + "friendlyName": "Humidifier - Target Humidity", + "channel": "target_humidity", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 40, + "maximum": 80, + "step": 1, + "pattern": "%.0f %%" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "relative-humidity", + "siid": 3, + "piid": 1, + "friendlyName": "Environment - Relative Humidity", + "channel": "relative_humidity", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "humidity", + "tags": [ + "Measurement", + "Humidity" + ] + }, + { + "property": "temperature", + "siid": 3, + "piid": 7, + "friendlyName": "Environment - Temperature", + "channel": "temperature", + "type": "Number:Temperature", + "unit": "celsius", + "stateDescription": { + "minimum": -30, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "alarm", + "siid": 5, + "piid": 1, + "friendlyName": "Alarm - Alarm", + "channel": "alarm", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "on1", + "siid": 6, + "piid": 1, + "friendlyName": "Indicator Light - Switch Status", + "channel": "on1", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "water-shortage-fault", + "siid": 7, + "piid": 1, + "friendlyName": "Custom - Water Shortage Fault", + "channel": "water_shortage_fault", + "type": "Switch", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "the-tank-filed", + "siid": 7, + "piid": 2, + "friendlyName": "Custom - The Tank Filed", + "channel": "the_tank_filed", + "type": "Switch", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + } + ], + "experimental": false + } +} From 011aca950ae2caad54497f386e5ba7d112492277 Mon Sep 17 00:00:00 2001 From: Matthew Skinner Date: Sat, 20 Nov 2021 22:41:46 +1100 Subject: [PATCH 118/361] [wled] Abstract json api for better segment support (#11509) * Change to json for states Signed-off-by: Matthew Skinner * Add 3rd colours. Signed-off-by: Matthew Skinner * Segments now mostly work Signed-off-by: Matthew Skinner * changes to json api fully made Signed-off-by: Matthew Skinner * Mirror and Reverse channels added. Signed-off-by: Matthew Skinner * Remove old channels when needed. Signed-off-by: Matthew Skinner * Simplify return Signed-off-by: Matthew Skinner * Add support for named presets Signed-off-by: Matthew Skinner * Dont add empty preset 0 to list Signed-off-by: Matthew Skinner * Add preset saving with custom names Signed-off-by: Matthew Skinner * Tidy up Signed-off-by: Matthew Skinner * Rename function for clarity Signed-off-by: Matthew Skinner * Add more channels Signed-off-by: Matthew Skinner * Clean up Signed-off-by: Matthew Skinner * Fix bugs and update readme for new channels Signed-off-by: Matthew Skinner Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.wled/README.md | 34 +- .../binding/wled/internal/WLedActions.java | 23 +- .../wled/internal/WLedBindingConstants.java | 9 + .../wled/internal/WLedDiscoveryService.java | 2 +- .../binding/wled/internal/WLedHandler.java | 550 +++++++----------- .../wled/internal/WLedHandlerFactory.java | 16 +- .../binding/wled/internal/WLedHelper.java | 49 +- .../binding/wled/internal/WledState.java | 118 ++++ .../wled/internal/api/ApiException.java | 42 ++ .../binding/wled/internal/api/WledApi.java | 105 ++++ .../wled/internal/api/WledApiFactory.java | 56 ++ .../wled/internal/api/WledApiV0110.java | 92 +++ .../wled/internal/api/WledApiV0130.java | 59 ++ .../wled/internal/api/WledApiV084.java | 508 ++++++++++++++++ .../resources/OH-INF/thing/thing-types.xml | 101 +++- 15 files changed, 1359 insertions(+), 405 deletions(-) create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledState.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/ApiException.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApi.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiFactory.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0110.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0130.java create mode 100644 bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java diff --git a/bundles/org.openhab.binding.wled/README.md b/bundles/org.openhab.binding.wled/README.md index 0f8f159f7bb28..46e5451e98c34 100644 --- a/bundles/org.openhab.binding.wled/README.md +++ b/bundles/org.openhab.binding.wled/README.md @@ -24,39 +24,47 @@ For additional segments, you can add them manually and set the `segmentIndex` co |-|-|-|-| | `address`| The full URL to your WLED device. Example is `http://192.168.0.2:80` | Y | | | `pollTime`| How often in seconds you want the states of the LED fetched in case you make changes with a non openHAB app, web browser, or the light is auto changing FX or presets. | Y | 10 | -| `segmentIndex` | The index number to the LED segment you wish these channels to control. Leave on -1 if you do not know what a segment is. | Y | -1 | +| `segmentIndex` | The index number to the LED segment you wish these channels to control. Leave on 0 if you do not know what a segment is. | Y | 0 | | `saturationThreshold` | Allows you to use a colorpicker control linked to the `masterControls` channel to trigger only using the pure white LEDs instead of creating fake white light from the RGB channels. Try setting the value to 12 or leave this on 0 for RGB strings. | Y | 0 | ## Channels | Channel | Type | Description | |-|-|-| -| `masterControls` | Color | Gives you control over the WLED like it is any normal light. Tag this control for Alexa or Google/Nest to change the lights instantly to any colour, brightness or on/off state that you ask for regardless of what mode the light is in. | +| `masterControls` | Color | Gives you control over the WLED segment like it is any normal light. Tag this control for Alexa or Google/Nest to change the lights instantly to any colour, brightness or on/off state that you ask for regardless of what mode the light is in. | +| `segmentBrightness` | Dimmer | Allows you to Dim and turn the entire segment ON and OFF. | | `primaryColor` | Color | The primary colour used in FX. | -| `primaryWhite` | Dimmer | The amount of white light used in the primary colour if you have RGBW LEDs. | +| `primaryWhite` | Dimmer | The amount of white light used in the primary colour. Only available if you have RGBW LEDs. | | `secondaryColor` | Color | The secondary colour used in FX. | -| `secondaryWhite` | Dimmer | The amount of white light used in the secondary colour if you have RGBW LEDs. | +| `secondaryWhite` | Dimmer | The amount of white light used in the second colour. Only available if you have RGBW LEDs. | +| `tertiaryColor` | Color | The third colour used in FX. | +| `tertiaryWhite` | Dimmer | The amount of white light used in the third colour. Only available if you have RGBW LEDs. | | `palettes` | String | A list of colour palettes you can select from that are used in the FX. | | `fx` | String | A list of Effects you can select from. | | `speed` | Dimmer | Changes the speed of the loaded effect. | | `intensity` | Dimmer | Changes the intensity of the loaded effect. | -| `presets` | String | A list of presets that you can select from. | -| `presetCycle` | Switch | Turns ON/OFF the automatic changing from one preset to the next. | -| `presetDuration` | Number:Time | How long in seconds it will display a preset for, before it begins to change from one preset to the next with `presetCycle` turned ON. | +| `presets` | String | A list of presets that you can select from and will display -1 when no presets are running. | +| `playlists` | String | A list of playlists that you can select from and will display -1 when none are running. | +| `presetCycle` | Switch | Turns ON/OFF the automatic changing from one preset to the next. Only in V0.12.0 and older firmwares. | +| `presetDuration` | Number:Time | How long in seconds it will display a preset for, before it begins to change from one preset to the next with `presetCycle` turned ON. Only in V0.12.0 and older firmwares. | | `transformTime` | Number:Time | How long in seconds it takes to transform/morph from one look to the next. | | `sleep` | Switch | Turns on the sleep or 'night light' timer which can be configured to work in many different ways. Refer to WLED documentation for how this can be setup. The default action is the light will fade to OFF over the next 60 minutes. | | `syncSend` | Switch | Sends UDP packets that tell other WLED lights to follow this one. | | `syncReceive` | Switch | Allows UDP packets from other WLED lights to control this one. | +| `mirror` | Switch | Mirror the effect for this segment. | +| `reverse` | Switch | Reverse the effect for this segment. | +| `liveOverride` | String | A value of "0" turns off, "1" will override live data to display what you want, and "2" overrides until you reboot the ESP device. | +| `grouping` | Number | The number of LEDs that are grouped together to display as one pixel in FX. Use metadata to display a list widget slider. | +| `spacing` | Number | The number of LEDs that will not light up in between FX pixels. Use metadata to display a list widget slider. | ## Rule Actions -This binding has a rule Action `savePreset(int presetNumber)` which can save the current state of the WLED string into a preset slot that you can specify. -Currently 1 to 16 are valid preset slots. +This binding has two rule Actions `savePreset(int presetNumber)` and `savePreset(int presetNumber, String presetName)` which can save the current state of the WLED string into a preset slot that you can specify. In Xtend rules, you can use the Actions like this. ``` -getActions("wled", "wled:wled:XmasTree").savePreset(5) +getActions("wled", "wled:wled:XmasTree").savePreset(5,"Flashy Preset") ``` ## Sitemap Example @@ -68,7 +76,7 @@ If you use the ADMIN>MODEL>`Create equipment from thing` feature you can use the ``` Text label="XmasLights" icon="rgb"{ Switch item=XmasTree_MasterControls - Slider item=XmasTree_MasterControls + Slider item=XmasTree_SegmentBrightness Colorpicker item=XmasTree_MasterControls Switch item=XmasTree_SleepTimer Colorpicker item=XmasTree_PrimaryColor @@ -77,9 +85,7 @@ If you use the ADMIN>MODEL>`Create equipment from thing` feature you can use the Selection item=XmasTree_Palettes Selection item=XmasTree_Presets Default item=XmasTree_FXSpeed - Default item=XmasTree_FXIntensity - Default item=XmasTree_PresetCycle - Selection item=XmasTree_PresetDuration mappings=[2 ='2 seconds', 10='10 seconds', 30='30 seconds', 60='60 seconds'] + Default item=XmasTree_FXIntensity Selection item=XmasTree_TransformTime mappings=[0='0 seconds', 2 ='2 seconds', 10='10 seconds', 30='30 seconds', 60='60 seconds'] } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java index f1e302ca1e574..8c2c53712d1f1 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedActions.java @@ -47,15 +47,30 @@ public void setThingHandler(@Nullable ThingHandler handler) { @RuleAction(label = "save state to preset", description = "Save a WLED state to a preset slot") public void savePreset( @ActionInput(name = "presetNumber", label = "Preset Slot", description = "Number for the preset slot you wish to use") int presetNumber) { + savePreset(presetNumber, ""); + } + + public static void savePreset(@Nullable ThingActions actions, int presetNumber) { + if (actions instanceof WLedActions) { + ((WLedActions) actions).savePreset(presetNumber, ""); + } else { + throw new IllegalArgumentException("Instance is not a WLED class."); + } + } + + @RuleAction(label = "save state to preset", description = "Save a WLED state to a preset slot") + public void savePreset( + @ActionInput(name = "presetNumber", label = "Preset Slot", description = "Number for the preset slot you wish to use") int presetNumber, + @ActionInput(name = "presetName", label = "Preset Name", description = "Name for the preset that you wish to use") String presetName) { WLedHandler localHandler = handler; - if (presetNumber > 0 && localHandler != null) { - localHandler.savePreset(presetNumber); + if (localHandler != null) { + localHandler.savePreset(presetNumber, presetName); } } - public static void savePreset(@Nullable ThingActions actions, int presetNumber) { + public static void savePreset(@Nullable ThingActions actions, int presetNumber, String presetName) { if (actions instanceof WLedActions) { - ((WLedActions) actions).savePreset(presetNumber); + ((WLedActions) actions).savePreset(presetNumber, presetName); } else { throw new IllegalArgumentException("Instance is not a WLED class."); } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java index 72106cea56164..62883bcb5098d 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedBindingConstants.java @@ -43,18 +43,27 @@ public class WLedBindingConstants { // Channels public static final String CHANNEL_MASTER_CONTROLS = "masterControls"; + public static final String CHANNEL_SEGMENT_BRIGHTNESS = "segmentBrightness"; public static final String CHANNEL_PRIMARY_COLOR = "primaryColor"; public static final String CHANNEL_SECONDARY_COLOR = "secondaryColor"; + public static final String CHANNEL_THIRD_COLOR = "tertiaryColor"; public static final String CHANNEL_PRIMARY_WHITE = "primaryWhite"; public static final String CHANNEL_SECONDARY_WHITE = "secondaryWhite"; + public static final String CHANNEL_THIRD_WHITE = "tertiaryWhite"; public static final String CHANNEL_PALETTES = "palettes"; public static final String CHANNEL_PRESETS = "presets"; + public static final String CHANNEL_PLAYLISTS = "playlists"; public static final String CHANNEL_PRESET_DURATION = "presetDuration"; public static final String CHANNEL_TRANS_TIME = "transformTime"; public static final String CHANNEL_PRESET_CYCLE = "presetCycle"; public static final String CHANNEL_FX = "fx"; public static final String CHANNEL_SPEED = "speed"; public static final String CHANNEL_INTENSITY = "intensity"; + public static final String CHANNEL_MIRROR = "mirror"; + public static final String CHANNEL_REVERSE = "reverse"; + public static final String CHANNEL_GROUPING = "grouping"; + public static final String CHANNEL_SPACING = "spacing"; + public static final String CHANNEL_LIVE_OVERRIDE = "liveOverride"; public static final String CHANNEL_SLEEP = "sleep"; public static final String CHANNEL_SYNC_SEND = "syncSend"; public static final String CHANNEL_SYNC_RECEIVE = "syncReceive"; diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java index f9a3185eb20bc..34114b1f32e3f 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedDiscoveryService.java @@ -106,7 +106,7 @@ private String sendGetRequest(String address, String url) { properties.put(Thing.PROPERTY_MAC_ADDRESS, macAddress); properties.put(Thing.PROPERTY_FIRMWARE_VERSION, firmware); return DiscoveryResultBuilder.create(thingUID).withProperty(CONFIG_ADDRESS, address[0]) - .withProperty(CONFIG_SEGMENT_INDEX, -1).withLabel(label).withProperties(properties) + .withProperty(CONFIG_SEGMENT_INDEX, 0).withLabel(label).withProperties(properties) .withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build(); } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java index d61d890f540f0..7088441bcbc1d 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java @@ -15,41 +15,36 @@ import static org.openhab.binding.wled.internal.WLedBindingConstants.*; import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; +import org.openhab.binding.wled.internal.api.ApiException; +import org.openhab.binding.wled.internal.api.WledApi; +import org.openhab.binding.wled.internal.api.WledApiFactory; +import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.HSBType; import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StringType; import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.ThingHandlerService; +import org.openhab.core.thing.binding.builder.ThingBuilder; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; -import org.openhab.core.types.StateOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,386 +58,244 @@ @NonNullByDefault public class WLedHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final HttpClient httpClient; - private final WledDynamicStateDescriptionProvider stateDescriptionProvider; + public final WledDynamicStateDescriptionProvider stateDescriptionProvider; + private WledApiFactory apiFactory; + private @Nullable WledApi api; private @Nullable ScheduledFuture pollingFuture = null; - private BigDecimal hue65535 = BigDecimal.ZERO; - private BigDecimal saturation255 = BigDecimal.ZERO; private BigDecimal masterBrightness255 = BigDecimal.ZERO; + public boolean hasWhite = false; private HSBType primaryColor = new HSBType(); - private BigDecimal primaryWhite = BigDecimal.ZERO; private HSBType secondaryColor = new HSBType(); - private BigDecimal secondaryWhite = BigDecimal.ZERO; - private boolean hasWhite = false; - private WLedConfiguration config = new WLedConfiguration(); + private HSBType thirdColor = new HSBType(); + public WLedConfiguration config = new WLedConfiguration(); - public WLedHandler(Thing thing, HttpClient httpClient, + public WLedHandler(Thing thing, WledApiFactory apiFactory, WledDynamicStateDescriptionProvider stateDescriptionProvider) { super(thing); - this.httpClient = httpClient; + this.apiFactory = apiFactory; this.stateDescriptionProvider = stateDescriptionProvider; } - private void sendGetRequest(String url) { - Request request; - if (url.contains("json") || config.segmentIndex == -1) { - request = httpClient.newRequest(config.address + url); - } else { - request = httpClient.newRequest(config.address + url + "&SM=" + config.segmentIndex); - } - request.timeout(3, TimeUnit.SECONDS); - request.method(HttpMethod.GET); - request.header(HttpHeader.ACCEPT_ENCODING, "gzip"); - logger.trace("Sending WLED GET:{}", url); - String errorReason = ""; - try { - ContentResponse contentResponse = request.send(); - if (contentResponse.getStatus() == 200) { - processState(contentResponse.getContentAsString()); - return; - } else { - errorReason = String.format("WLED request failed with %d: %s", contentResponse.getStatus(), - contentResponse.getReason()); - } - } catch (TimeoutException e) { - errorReason = "TimeoutException: WLED was not reachable on your network"; - } catch (ExecutionException e) { - errorReason = String.format("ExecutionException: %s", e.getMessage()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - errorReason = String.format("InterruptedException: %s", e.getMessage()); - } - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, errorReason); - } - - private HSBType parseToHSBType(String message, String element) { - int startIndex = message.indexOf(element); - if (startIndex == -1) { - return new HSBType(); - } - int endIndex = message.indexOf("<", startIndex + element.length()); - int r = 0, g = 0, b = 0; - try { - r = Integer.parseInt(message.substring(startIndex + element.length(), endIndex)); - // look for second element - startIndex = message.indexOf(element, endIndex); - if (startIndex == -1) { - return new HSBType(); - } - endIndex = message.indexOf("<", startIndex + element.length()); - g = Integer.parseInt(message.substring(startIndex + element.length(), endIndex)); - // look for third element called - startIndex = message.indexOf(element, endIndex); - if (startIndex == -1) { - return new HSBType(); - } - endIndex = message.indexOf("<", startIndex + element.length()); - b = Integer.parseInt(message.substring(startIndex + element.length(), endIndex)); - } catch (NumberFormatException e) { - logger.warn("NumberFormatException when parsing the WLED color fields:{}", e.getMessage()); - } - return HSBType.fromRGB(r, g, b); - } - - private void parseColours(String message) { - primaryColor = parseToHSBType(message, ""); - updateState(CHANNEL_PRIMARY_COLOR, primaryColor); - secondaryColor = parseToHSBType(message, ""); - updateState(CHANNEL_SECONDARY_COLOR, secondaryColor); - try { - primaryWhite = new BigDecimal(WLedHelper.getValue(message, "", "<")); - if (primaryWhite.intValue() > -1) { - hasWhite = true; - updateState(CHANNEL_PRIMARY_WHITE, - new PercentType(primaryWhite.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); - secondaryWhite = new BigDecimal(WLedHelper.getValue(message, "", "<")); - updateState(CHANNEL_SECONDARY_WHITE, - new PercentType(secondaryWhite.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); - } - } catch (IllegalArgumentException e) { - logger.warn("IllegalArgumentException when parsing the WLED colour and white fields:{}", e.getMessage()); - } - } - - /** - * - * This function should prevent the need to keep updating the binding as more FX and Palettes are added to the - * firmware. - */ - private void scrapeChannelOptions(String message) { - List fxOptions = new ArrayList<>(); - List palleteOptions = new ArrayList<>(); - int counter = 0; - for (String value : WLedHelper.getValue(message, "\"effects\":[", "]").replace("\"", "").split(",")) { - fxOptions.add(new StateOption(Integer.toString(counter++), value)); - } - stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FX), fxOptions); - counter = 0; - for (String value : (WLedHelper.getValue(message, "\"palettes\":[", "]").replace("\"", "")).split(",")) { - palleteOptions.add(new StateOption(Integer.toString(counter++), value)); - } - stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_PALETTES), palleteOptions); - } - - private void processState(String message) { - logger.trace("WLED states are:{}", message); - if (thing.getStatus() != ThingStatus.ONLINE) { - updateStatus(ThingStatus.ONLINE); - sendGetRequest("/json"); // fetch FX and Pallete names - } - if (message.contains("\"effects\":[")) {// JSON API reply - scrapeChannelOptions(message); - return; - } - if (message.contains("0")) { - updateState(CHANNEL_MASTER_CONTROLS, OnOffType.OFF); - } else { - masterBrightness255 = new BigDecimal(WLedHelper.getValue(message, "", "<")); - updateState(CHANNEL_MASTER_CONTROLS, - new PercentType(masterBrightness255.divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); - } - if (message.contains("0")) { - updateState(CHANNEL_INTENSITY, OnOffType.OFF); - } else { - BigDecimal bigTemp = new BigDecimal(WLedHelper.getValue(message, "", "<")).divide(BIG_DECIMAL_2_55, - RoundingMode.HALF_UP); - updateState(CHANNEL_INTENSITY, new PercentType(bigTemp)); - } - if (message.contains("1")) { - updateState(CHANNEL_PRESET_CYCLE, OnOffType.ON); - } else { - updateState(CHANNEL_PRESET_CYCLE, OnOffType.OFF); - } - if (message.contains("1")) { - updateState(CHANNEL_SLEEP, OnOffType.ON); - } else { - updateState(CHANNEL_SLEEP, OnOffType.OFF); - } - if (message.contains("1")) { - updateState(CHANNEL_SYNC_SEND, OnOffType.ON); - } else { - updateState(CHANNEL_SYNC_SEND, OnOffType.OFF); - } - if (message.contains("1")) { - updateState(CHANNEL_SYNC_RECEIVE, OnOffType.ON); - } else { - updateState(CHANNEL_SYNC_RECEIVE, OnOffType.OFF); - } - if (message.contains("")) { - updateState(CHANNEL_FX, new StringType(WLedHelper.getValue(message, "", "<"))); - } - if (message.contains("")) { - BigDecimal bigTemp = new BigDecimal(WLedHelper.getValue(message, "", "<")).divide(BIG_DECIMAL_2_55, - RoundingMode.HALF_UP); - updateState(CHANNEL_SPEED, new PercentType(bigTemp)); - } - if (message.contains("")) { - updateState(CHANNEL_PALETTES, new StringType(WLedHelper.getValue(message, "", "<"))); - } - parseColours(message); - } - - private void sendWhite() { - if (hasWhite) { - sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=hFF000000" + "&A=" + masterBrightness255); - } else { - sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=hFFFFFF" + "&A=" + masterBrightness255); - } - } - - /** - * - * @param hsb - * @return WLED needs the letter h followed by 2 digit HEX code for RRGGBB - */ - private String createColorHex(HSBType hsb) { - return String.format("h%06X", hsb.getRGB() & 0x00FFFFFF); - } - @Override public void handleCommand(ChannelUID channelUID, Command command) { + WledApi localApi = api; + if (localApi == null) { + return; + } BigDecimal bigTemp; - PercentType localPercentType; if (command instanceof RefreshType) { - switch (channelUID.getId()) { - case CHANNEL_MASTER_CONTROLS: - sendGetRequest("/win"); - } return;// no need to check for refresh below } logger.debug("command {} sent to {}", command, channelUID.getId()); - switch (channelUID.getId()) { - case CHANNEL_SYNC_SEND: - if (OnOffType.OFF.equals(command)) { - sendGetRequest("/win&NS=0"); - } else { - sendGetRequest("/win&NS=1"); - } - break; - case CHANNEL_SYNC_RECEIVE: - if (OnOffType.OFF.equals(command)) { - sendGetRequest("/win&NR=0"); - } else { - sendGetRequest("/win&NR=1"); - } - break; - case CHANNEL_PRIMARY_WHITE: - if (command instanceof PercentType) { - sendGetRequest("/win&W=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55)); - } - break; - case CHANNEL_SECONDARY_WHITE: - if (command instanceof PercentType) { - sendGetRequest("/win&W2=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55)); - } - break; - case CHANNEL_MASTER_CONTROLS: - if (command instanceof OnOffType) { - if (OnOffType.OFF.equals(command)) { - sendGetRequest("/win&TT=250&T=0"); - } else { - sendGetRequest("/win&TT=1000&T=1"); + try { + switch (channelUID.getId()) { + case CHANNEL_SEGMENT_BRIGHTNESS: + if (command instanceof OnOffType) { + localApi.setMasterOn(OnOffType.ON.equals(command), config.segmentIndex); + } else if (command instanceof PercentType) { + if (PercentType.ZERO.equals(command)) { + localApi.setMasterOn(false, config.segmentIndex); + return; + } + localApi.setMasterBrightness((PercentType) command, config.segmentIndex); + } + break; + case CHANNEL_MIRROR: + localApi.setMirror(OnOffType.ON.equals(command), config.segmentIndex); + break; + case CHANNEL_LIVE_OVERRIDE: + localApi.setLiveOverride(command.toString()); + break; + case CHANNEL_SPACING: + if (command instanceof DecimalType) { + localApi.setSpacing(((DecimalType) command).intValue(), config.segmentIndex); + } + break; + case CHANNEL_GROUPING: + if (command instanceof DecimalType) { + localApi.setGrouping(((DecimalType) command).intValue(), config.segmentIndex); + } + break; + case CHANNEL_REVERSE: + localApi.setReverse(OnOffType.ON.equals(command), config.segmentIndex); + break; + case CHANNEL_SYNC_SEND: + localApi.setUdpSend(OnOffType.ON.equals(command)); + break; + case CHANNEL_SYNC_RECEIVE: + localApi.setUdpRecieve(OnOffType.ON.equals(command)); + break; + case CHANNEL_PRIMARY_WHITE: + if (command instanceof PercentType) { + localApi.sendGetRequest( + "/win&W=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55)); + } + break; + case CHANNEL_SECONDARY_WHITE: + if (command instanceof PercentType) { + localApi.sendGetRequest( + "/win&W2=" + ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55)); } - } else if (command instanceof IncreaseDecreaseType) { - if (IncreaseDecreaseType.INCREASE.equals(command)) { - if (masterBrightness255.intValue() < 240) { - sendGetRequest("/win&TT=1000&A=~15"); // 255 divided by 15 = 17 different levels + break; + case CHANNEL_MASTER_CONTROLS: + if (command instanceof OnOffType) { + localApi.setMasterOn(OnOffType.ON.equals(command), config.segmentIndex); + } else if (command instanceof IncreaseDecreaseType) { + if (IncreaseDecreaseType.INCREASE.equals(command)) { + if (masterBrightness255.intValue() < 240) { + localApi.sendGetRequest("/win&TT=1000&A=~15"); // 255 divided by 15 = 17 levels + } else { + localApi.sendGetRequest("/win&TT=1000&A=255"); + } } else { - sendGetRequest("/win&TT=1000&A=255"); + if (masterBrightness255.intValue() > 15) { + localApi.sendGetRequest("/win&TT=1000&A=~-15"); + } else { + localApi.sendGetRequest("/win&TT=1000&A=0"); + } + } + } else if (command instanceof HSBType) { + if ((((HSBType) command).getBrightness()).equals(PercentType.ZERO)) { + localApi.setMasterOn(false, config.segmentIndex); + return; } - } else { - if (masterBrightness255.intValue() > 15) { - sendGetRequest("/win&TT=1000&A=~-15"); + primaryColor = (HSBType) command; + if (primaryColor.getSaturation().intValue() < config.saturationThreshold && hasWhite) { + localApi.setWhiteOnly((PercentType) command, config.segmentIndex); + } else if (primaryColor.getSaturation().intValue() == 32 + && primaryColor.getHue().intValue() == 36 && hasWhite) { + localApi.setWhiteOnly((PercentType) command, config.segmentIndex); } else { - sendGetRequest("/win&TT=1000&A=0"); + localApi.setMasterHSB((HSBType) command, config.segmentIndex); } + } else if (command instanceof PercentType) { + localApi.setMasterBrightness((PercentType) command, config.segmentIndex); } - } else if (command instanceof HSBType) { - if (PercentType.ZERO.equals(((HSBType) command).getBrightness())) { - sendGetRequest("/win&TT=500&T=0"); + return; + case CHANNEL_PRIMARY_COLOR: + if (command instanceof HSBType) { + primaryColor = (HSBType) command; + } else if (command instanceof PercentType) { + primaryColor = new HSBType(primaryColor.getHue(), primaryColor.getSaturation(), + ((PercentType) command)); } - primaryColor = (HSBType) command; - hue65535 = primaryColor.getHue().toBigDecimal().multiply(BIG_DECIMAL_182_04); - saturation255 = primaryColor.getSaturation().toBigDecimal().multiply(BIG_DECIMAL_2_55); - masterBrightness255 = primaryColor.getBrightness().toBigDecimal().multiply(BIG_DECIMAL_2_55); - if (primaryColor.getSaturation().intValue() < config.saturationThreshold) { - sendWhite(); - } else if (primaryColor.getSaturation().intValue() == 32 && primaryColor.getHue().intValue() == 36 - && hasWhite) { - // Google sends this when it wants white - sendWhite(); - } else { - if (config.segmentIndex == -1) { - sendGetRequest("/win&TT=1000&FX=0&CY=0&HU=" + hue65535 + "&SA=" + saturation255 + "&A=" - + masterBrightness255); - } else { - sendGetRequest("/win&TT=1000&FX=0&CY=0&CL=" + createColorHex(primaryColor) + "&A=" - + masterBrightness255); + localApi.setPrimaryColor(primaryColor, config.segmentIndex); + return; + case CHANNEL_SECONDARY_COLOR: + if (command instanceof HSBType) { + secondaryColor = (HSBType) command; + } else if (command instanceof PercentType) { + secondaryColor = new HSBType(secondaryColor.getHue(), secondaryColor.getSaturation(), + ((PercentType) command)); + } + localApi.setSecondaryColor(secondaryColor, config.segmentIndex); + return; + case CHANNEL_THIRD_COLOR: + if (command instanceof HSBType) { + thirdColor = (HSBType) command; + } else if (command instanceof PercentType) { + thirdColor = new HSBType(thirdColor.getHue(), thirdColor.getSaturation(), + ((PercentType) command)); + } + localApi.setTertiaryColor(thirdColor, config.segmentIndex); + return; + case CHANNEL_PALETTES: + localApi.setPalette(command.toString(), config.segmentIndex); + break; + case CHANNEL_FX: + localApi.setEffect(command.toString(), config.segmentIndex); + break; + case CHANNEL_SPEED: + localApi.setFxSpeed((PercentType) command, config.segmentIndex); + break; + case CHANNEL_INTENSITY: + localApi.setFxIntencity((PercentType) command, config.segmentIndex); + break; + case CHANNEL_SLEEP: + localApi.setSleep(OnOffType.ON.equals(command)); + break; + case CHANNEL_PLAYLISTS: + case CHANNEL_PRESETS: + localApi.setPreset(command.toString()); + break; + case CHANNEL_PRESET_DURATION:// ch removed in firmware 0.13.0 and newer + if (command instanceof QuantityType) { + QuantityType seconds = ((QuantityType) command).toUnit(Units.SECOND); + if (seconds != null) { + bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000)); + localApi.sendGetRequest("/win&PT=" + bigTemp.intValue()); } } - } else if (command instanceof PercentType) { - masterBrightness255 = ((PercentType) command).toBigDecimal().multiply(BIG_DECIMAL_2_55); - sendGetRequest("/win&TT=1000&A=" + masterBrightness255); - } - return; - case CHANNEL_PRIMARY_COLOR: - if (command instanceof HSBType) { - primaryColor = (HSBType) command; - sendGetRequest("/win&CL=" + createColorHex(primaryColor)); - } else if (command instanceof PercentType) { - primaryColor = new HSBType(primaryColor.getHue(), primaryColor.getSaturation(), - ((PercentType) command)); - sendGetRequest("/win&CL=" + createColorHex(primaryColor)); - } - return; - case CHANNEL_SECONDARY_COLOR: - if (command instanceof HSBType) { - secondaryColor = (HSBType) command; - sendGetRequest("/win&C2=" + createColorHex(secondaryColor)); - } else if (command instanceof PercentType) { - secondaryColor = new HSBType(secondaryColor.getHue(), secondaryColor.getSaturation(), - ((PercentType) command)); - sendGetRequest("/win&C2=" + createColorHex(secondaryColor)); - } - return; - case CHANNEL_PALETTES: - sendGetRequest("/win&FP=" + command); - break; - case CHANNEL_FX: - sendGetRequest("/win&FX=" + command); - break; - case CHANNEL_SPEED: - localPercentType = ((State) command).as(PercentType.class); - if (localPercentType != null) { - bigTemp = localPercentType.toBigDecimal().multiply(BIG_DECIMAL_2_55); - sendGetRequest("/win&SX=" + bigTemp); - } - break; - case CHANNEL_INTENSITY: - localPercentType = ((State) command).as(PercentType.class); - if (localPercentType != null) { - bigTemp = localPercentType.toBigDecimal().multiply(BIG_DECIMAL_2_55); - sendGetRequest("/win&IX=" + bigTemp); - } - break; - case CHANNEL_SLEEP: - if (OnOffType.ON.equals(command)) { - sendGetRequest("/win&ND"); - } else { - sendGetRequest("/win&NL=0"); - } - break; - case CHANNEL_PRESETS: - sendGetRequest("/win&PL=" + command); - break; - case CHANNEL_PRESET_DURATION: - if (command instanceof QuantityType) { - QuantityType seconds = ((QuantityType) command).toUnit(Units.SECOND); - if (seconds != null) { - bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000)); - sendGetRequest("/win&PT=" + bigTemp.intValue()); + break; + case CHANNEL_TRANS_TIME: + if (command instanceof QuantityType) { + QuantityType seconds = ((QuantityType) command).toUnit(Units.SECOND); + if (seconds != null) { + localApi.setTransitionTime(new BigDecimal(seconds.multiply(BigDecimal.TEN).intValue())); + } } - } - break; - case CHANNEL_TRANS_TIME: - if (command instanceof QuantityType) { - QuantityType seconds = ((QuantityType) command).toUnit(Units.SECOND); - if (seconds != null) { - bigTemp = new BigDecimal(seconds.intValue()).multiply(new BigDecimal(1000)); - sendGetRequest("/win&TT=" + bigTemp.intValue()); + break; + case CHANNEL_PRESET_CYCLE: // ch removed in firmware 0.13.0 and newer + if (command instanceof OnOffType) { + localApi.setPresetCycle(OnOffType.ON.equals(command)); } - } - break; - case CHANNEL_PRESET_CYCLE: - if (OnOffType.ON.equals(command)) { - sendGetRequest("/win&CY=1"); - } else { - sendGetRequest("/win&CY=0"); - } - break; + break; + } + } catch (ApiException e) { + logger.debug("Exception occured:{}", e.getMessage()); } } - public void savePreset(int presetIndex) { - if (presetIndex > 16) { - logger.warn("Presets above 16 do not exist, and the action sent {}", presetIndex); - return; + public void savePreset(int position, String presetName) { + try { + if (api != null) { + api.savePreset(position, presetName); + } + } catch (ApiException e) { + } + } + + public void removeChannels(ArrayList removeChannels) { + if (!removeChannels.isEmpty()) { + ThingBuilder thingBuilder = editThing(); + thingBuilder.withoutChannels(removeChannels); + updateThing(thingBuilder.build()); } - sendGetRequest("/win&PS=" + presetIndex); } - private void pollLED() { - sendGetRequest("/win"); + public void update(String channelID, State state) { + updateState(channelID, state); + } + + private void pollState() { + WledApi localApi = api; + try { + if (localApi == null) { + api = apiFactory.getApi(this); + api.initialize(); + } + if (localApi == null) { + return; + } + localApi.update(); + updateStatus(ThingStatus.ONLINE); + } catch (ApiException e) { + api = null;// Firmware may be updated so need to check next connect + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + } } @Override public void initialize() { config = getConfigAs(WLedConfiguration.class); + if (config.segmentIndex < 0) { + config.segmentIndex = 0; + } if (!config.address.contains("://")) { logger.debug("Address was not entered in correct format, it may be the raw IP so adding http:// to start"); config.address = "http://" + config.address; } - pollingFuture = scheduler.scheduleWithFixedDelay(this::pollLED, 1, config.pollTime, TimeUnit.SECONDS); + pollingFuture = scheduler.scheduleWithFixedDelay(this::pollState, 0, config.pollTime, TimeUnit.SECONDS); } @Override @@ -450,6 +303,7 @@ public void dispose() { Future future = pollingFuture; if (future != null) { future.cancel(true); + pollingFuture = null; } } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java index 52d60c68e6771..9c41546fd01fd 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandlerFactory.java @@ -16,8 +16,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.jetty.client.HttpClient; -import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.binding.wled.internal.api.WledApiFactory; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; @@ -36,29 +35,26 @@ @NonNullByDefault @Component(configurationPid = "binding.wled", service = ThingHandlerFactory.class) public class WLedHandlerFactory extends BaseThingHandlerFactory { - private final HttpClient httpClient; private final WledDynamicStateDescriptionProvider stateDescriptionProvider; + private final WledApiFactory apiFactory; @Activate - public WLedHandlerFactory(@Reference HttpClientFactory httpClientFactory, + public WLedHandlerFactory(@Reference WledApiFactory apiFactory, final @Reference WledDynamicStateDescriptionProvider stateDescriptionProvider) { - this.httpClient = httpClientFactory.getCommonHttpClient(); + this.apiFactory = apiFactory; this.stateDescriptionProvider = stateDescriptionProvider; } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { - if (SUPPORTED_THING_TYPES.contains(thingTypeUID)) { - return true; - } - return false; + return SUPPORTED_THING_TYPES.contains(thingTypeUID); } @Override protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (SUPPORTED_THING_TYPES.contains(thingTypeUID)) { - return new WLedHandler(thing, httpClient, stateDescriptionProvider); + return new WLedHandler(thing, apiFactory, stateDescriptionProvider); } return null; } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java index a50a08e32fac1..cf36cb6a757ea 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHelper.java @@ -12,10 +12,13 @@ */ package org.openhab.binding.wled.internal; -import java.util.LinkedList; +import java.math.BigDecimal; +import java.util.Arrays; import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.PercentType; /** * The {@link WLedHelper} Provides helper classes that are used from multiple classes in the binding. @@ -24,6 +27,28 @@ */ @NonNullByDefault public class WLedHelper { + public static HSBType parseToHSBType(String message) { + // example message rgb in array brackets [255.0, 255.0, 255.0] + List colors = Arrays.asList(message.replaceAll("\\[|\\]", "").split("\\s*,\\s*")); + try { + int r = new BigDecimal(colors.get(0)).intValue(); + int g = new BigDecimal(colors.get(1)).intValue(); + int b = new BigDecimal(colors.get(2)).intValue(); + return HSBType.fromRGB(r, g, b); + } catch (NumberFormatException e) { + return new HSBType(); + } + } + + public static PercentType parseWhitePercent(String message) { + // example message rgb in array brackets [255.0, 255.0, 255.0, 255.0] + List colors = Arrays.asList(message.replaceAll("\\[|\\]", "").split("\\s*,\\s*")); + try { + return new PercentType(new BigDecimal(colors.get(2))); + } catch (IllegalArgumentException e) { + return new PercentType(); + } + } /** * @return A string that starts after finding the element and terminates when it finds the first occurrence of the @@ -40,26 +65,4 @@ static String getValue(String message, String element, String end) { } return ""; } - - /** - * @return A List that holds the values from a heading/element that re-occurs in a message multiple times. - * - */ - static List listOfResults(String message, String element, String end) { - List results = new LinkedList<>(); - String temp = ""; - for (int startLookingFromIndex = 0; startLookingFromIndex != -1;) { - startLookingFromIndex = message.indexOf(element, startLookingFromIndex); - if (startLookingFromIndex >= 0) { - temp = getValue(message.substring(startLookingFromIndex), element, end); - if (!temp.isEmpty()) { - results.add(temp); - } else { - return results;// end string must not exist so stop looking. - } - startLookingFromIndex += temp.length(); - } - } - return results; - } } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledState.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledState.java new file mode 100644 index 0000000000000..dfec00167857a --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WledState.java @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +import com.google.gson.Gson; + +/** + * The {@link WledState} class holds the state and replies for a WLED device. + * + * @author Matthew Skinner - Initial contribution + */ +@NonNullByDefault +public class WledState { + protected final Gson gson = new Gson(); + public JsonResponse jsonResponse = new JsonResponse(); + public StateResponse stateResponse = new StateResponse(); + public InfoResponse infoResponse = new InfoResponse(); + public LedInfo ledInfo = new LedInfo(); + public NightLightState nightLightState = new NightLightState(); + public UdpnState udpnState = new UdpnState(); + public SegmentState segmentState = new SegmentState(); + public PresetState[] presetState = new PresetState[1]; + + public class JsonResponse { + public List effects = new ArrayList<>(); + public List palettes = new ArrayList<>(); + } + + public void unpackJsonObjects() { + @Nullable + NightLightState localNightLightState = gson.fromJson(stateResponse.nl.toString(), NightLightState.class); + if (localNightLightState != null) { + nightLightState = localNightLightState; + } + + @Nullable + UdpnState localUdpnState = gson.fromJson(stateResponse.udpn.toString(), UdpnState.class); + if (localUdpnState != null) { + udpnState = localUdpnState; + } + } + + public class StateResponse { + public boolean on = true; + public Object nl = "{}"; + public Object udpn = "{}"; + public SegmentState[] seg = new SegmentState[1]; + public int bri = 0; + public int transition = 7; + public int ps = -1; + public int pss = 0; + public int pl = -1; + public int lor = 0; + } + + public class UdpnState { + public boolean send = false; + public boolean recv = false; + } + + public class SegmentState { + public int id = 0; + public int start = 0; + public int stop = 0; + public int len = 0; + public int grp = 0; + public int spc = 0; + public boolean on = true; + public int bri = 0; + public Object[] col = new Object[1]; + public int fx = 0; + public int sx = 0; + public int ix = 0; + public int pal = 0; + public boolean sel = true; + public boolean rev = false; + public boolean mi = false; + } + + public class NightLightState { + public boolean on = true; + public int dur = 0; + public int mode = 0; + public int tbri = 0; + public int rem = 0; + } + + public class InfoResponse { + public String ver = "00000"; + public String mac = ""; + public Object leds = "{}"; + } + + public class LedInfo { + public boolean rgbw = false; + } + + public class PresetState { + public String n = "";// Name of preset + public int bri = 0;// brightness in 255, 0 means it is a playlist as bri was not defined + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/ApiException.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/ApiException.java new file mode 100644 index 0000000000000..602afb8596d81 --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/ApiException.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link ApiException} will be thrown whenever the wled API can not successfully communicate with the device. + * + * @author Matthew Skinner - Initial contribution + */ + +@NonNullByDefault +public class ApiException extends Exception { + /** + * Serial ID of this error class. + */ + private static final long serialVersionUID = 1238256795216449L; + + /** + * Basic constructor allowing the storing of a single message. + * + * @param message Descriptive message about the error. + */ + public ApiException(String message) { + super(message); + } + + public ApiException(String message, Throwable e) { + super(message, e); + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApi.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApi.java new file mode 100644 index 0000000000000..658b6f8a74ae5 --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApi.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import java.math.BigDecimal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.PercentType; + +/** + * The {@link WledApi} is the JSON API methods that can be extended for different firmware versions. + * + * @author Matthew Skinner - Initial contribution + */ +@NonNullByDefault +public interface WledApi { + public abstract void update() throws ApiException; + + public abstract void initialize() throws ApiException; + + public abstract int getFirmwareVersion() throws ApiException; + + public abstract String sendGetRequest(String string) throws ApiException; + + /** + * Turns on/off ALL segments + */ + public abstract void setGlobalOn(boolean bool) throws ApiException; + + /** + * Turns on/off just THIS segment + */ + public abstract void setMasterOn(boolean bool, int segmentIndex) throws ApiException; + + /** + * Sets the brightness of ALL segments + */ + public abstract void setGlobalBrightness(PercentType percent) throws ApiException; + + /** + * Sets the brightness of just THIS segment + */ + public abstract void setMasterBrightness(PercentType percent, int segmentIndex) throws ApiException; + + /** + * Stops any running FX and instantly changes the segment to the desired colour + */ + public abstract void setMasterHSB(HSBType hsbType, int segmentIndex) throws ApiException; + + public abstract void setEffect(String string, int segmentIndex) throws ApiException; + + public abstract void setPreset(String string) throws ApiException; + + public abstract void setPalette(String string, int segmentIndex) throws ApiException; + + public abstract void setFxIntencity(PercentType percentType, int segmentIndex) throws ApiException; + + public abstract void setFxSpeed(PercentType percentType, int segmentIndex) throws ApiException; + + public abstract void setSleep(boolean bool) throws ApiException; + + public abstract void setUdpSend(boolean bool) throws ApiException; + + public abstract void setUdpRecieve(boolean bool) throws ApiException; + + public abstract void setTransitionTime(BigDecimal time) throws ApiException; + + public abstract void setPresetCycle(boolean bool) throws ApiException; + + public abstract void setPrimaryColor(HSBType hsbType, int segmentIndex) throws ApiException; + + public abstract void setSecondaryColor(HSBType hsbType, int segmentIndex) throws ApiException; + + public abstract void setTertiaryColor(HSBType hsbType, int segmentIndex) throws ApiException; + + public abstract void setWhiteOnly(PercentType percentType, int segmentIndex) throws ApiException; + + public abstract void setMirror(boolean bool, int segmentIndex) throws ApiException; + + public abstract void setReverse(boolean bool, int segmentIndex) throws ApiException; + + public abstract void setLiveOverride(String value) throws ApiException; + + public abstract void setGrouping(int value, int segmentIndex) throws ApiException; + + public abstract void setSpacing(int value, int segmentIndex) throws ApiException; + + /** + * Saves a preset to the position number with the supplied name. If the supplied name is an empty String then the + * name 'Preset x' will be used by default using the position number given. + * + */ + public abstract void savePreset(int position, String presetName) throws ApiException; +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiFactory.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiFactory.java new file mode 100644 index 0000000000000..f71cac034443e --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiFactory.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.wled.internal.WLedHandler; +import org.openhab.core.io.net.http.HttpClientFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link WledApiFactory} is responsible for creating an instance of the API that is optimized for different + * firmware versions. + * + * @author Matthew Skinner - Initial contribution + */ +@Component(service = WledApiFactory.class) +@NonNullByDefault +public class WledApiFactory { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final HttpClient httpClient; + + @Activate + public WledApiFactory(@Reference HttpClientFactory httpClientFactory) { + this.httpClient = httpClientFactory.getCommonHttpClient(); + } + + public WledApi getApi(WLedHandler handler) throws ApiException { + WledApi lowestSupportedApi = new WledApiV084(handler, httpClient); + int version = lowestSupportedApi.getFirmwareVersion(); + logger.debug("Treating firmware as int:{}", version); + if (version >= 130) { + return new WledApiV0130(handler, httpClient); + } else if (version >= 110) { + return new WledApiV0110(handler, httpClient); + } else if (version >= 100) { + return new WledApiV084(handler, httpClient); + } + logger.warn("Your WLED firmware is very old, upgrade to at least 0.10.0"); + return lowestSupportedApi; + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0110.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0110.java new file mode 100644 index 0000000000000..8c6444305c577 --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0110.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import static org.openhab.binding.wled.internal.WLedBindingConstants.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.wled.internal.WLedHandler; +import org.openhab.binding.wled.internal.WledState.PresetState; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.StateOption; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link WledApiV0130} is the json Api methods for firmware version 0.11.0 and newer + * as newer firmwares come out with breaking changes, extend this class into a newer firmware version class. + * + * @author Matthew Skinner - Initial contribution + */ +@NonNullByDefault +public class WledApiV0110 extends WledApiV084 { + + public WledApiV0110(WLedHandler handler, HttpClient httpClient) { + super(handler, httpClient); + } + + @Override + public void initialize() throws ApiException { + super.initialize(); + getPresets(); + } + + protected void getPresets() throws JsonSyntaxException, ApiException { + List presetsOptions = new ArrayList<>(); + List playlistsOptions = new ArrayList<>(); + JsonObject obj = gson.fromJson(sendGetRequest("/presets.json"), JsonObject.class); + if (obj == null) { + return; + } + Set> set = obj.entrySet(); + int counter = 0; + for (Entry presetEntry : set) { + logger.trace("Preset:{} json:{}", presetEntry.getKey(), presetEntry.getValue()); + PresetState preset = gson.fromJson(presetEntry.getValue(), PresetState.class); + if (preset != null && counter > 0) { + if (preset.bri == 0) { + playlistsOptions.add(new StateOption(Integer.toString(counter), preset.n)); + } else { + presetsOptions.add(new StateOption(Integer.toString(counter), preset.n)); + } + } + counter++; + } + handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_PRESETS), + presetsOptions); + handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_PLAYLISTS), + playlistsOptions); + } + + @Override + public void savePreset(int position, String presetName) throws ApiException { + if (position < 1) { + logger.warn("Preset position {} is not supported in this firmware version", position); + return; + } + + String name = presetName; + if (name.isEmpty()) { + name = "Preset " + position; + } + postState("{\"psave\":" + position + ",\"n\":\"" + name + "\",\"ib\":true,\"sb\":true}"); + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0130.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0130.java new file mode 100644 index 0000000000000..e69bbc823365f --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV0130.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import static org.openhab.binding.wled.internal.WLedBindingConstants.*; + +import java.util.ArrayList; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.wled.internal.WLedHandler; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.Channel; + +/** + * The {@link WledApiV0130} is the json Api methods for firmware version 0.13.0 and newer + * as newer firmwares come out with breaking changes, extend this class into a newer firmware version class. + * + * @author Matthew Skinner - Initial contribution + */ +@NonNullByDefault +public class WledApiV0130 extends WledApiV0110 { + + public WledApiV0130(WLedHandler handler, HttpClient httpClient) { + super(handler, httpClient); + } + + @Override + public void initialize() throws ApiException { + super.initialize(); + ArrayList removeChannels = new ArrayList<>(); + // This version of firmware removed these channels + Channel channel = handler.getThing().getChannel(CHANNEL_PRESET_DURATION); + if (channel != null) { + removeChannels.add(channel); + } + channel = handler.getThing().getChannel(CHANNEL_PRESET_CYCLE); + if (channel != null) { + removeChannels.add(channel); + } + handler.removeChannels(removeChannels); + } + + @Override + protected void processState() throws ApiException { + super.processState(); + handler.update(CHANNEL_PLAYLISTS, new StringType(Integer.toString(state.stateResponse.pl))); + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java new file mode 100644 index 0000000000000..bd6d00ddef79c --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java @@ -0,0 +1,508 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.wled.internal.api; + +import static org.openhab.binding.wled.internal.WLedBindingConstants.*; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpMethod; +import org.openhab.binding.wled.internal.WLedHandler; +import org.openhab.binding.wled.internal.WLedHelper; +import org.openhab.binding.wled.internal.WledState; +import org.openhab.binding.wled.internal.WledState.InfoResponse; +import org.openhab.binding.wled.internal.WledState.JsonResponse; +import org.openhab.binding.wled.internal.WledState.LedInfo; +import org.openhab.binding.wled.internal.WledState.StateResponse; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.types.StateOption; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link WledApiV084} is the json Api methods for firmware version 0.8.4 and newer + * as newer firmwares come out with breaking changes, extend this class into a newer firmware version class. + * + * @author Matthew Skinner - Initial contribution + */ +@NonNullByDefault +public class WledApiV084 implements WledApi { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected final Gson gson = new Gson(); + protected final HttpClient httpClient; + protected final WLedHandler handler; + protected final String address; + protected WledState state = new WledState(); + private int version = 0; + + public WledApiV084(WLedHandler handler, HttpClient httpClient) { + this.handler = handler; + this.address = handler.config.address; + this.httpClient = httpClient; + } + + @Override + public void initialize() throws ApiException { + state.jsonResponse = getJson(); + getUpdatedFxList(); + getUpdatedPaletteList(); + + @Nullable + LedInfo localLedInfo = gson.fromJson(state.infoResponse.leds.toString(), LedInfo.class); + if (localLedInfo != null) { + state.ledInfo = localLedInfo; + } + + handler.hasWhite = state.ledInfo.rgbw; + ArrayList removeChannels = new ArrayList<>(); + if (!state.ledInfo.rgbw) { + logger.debug("WLED is not setup to use RGBW, so removing un-needed white channels"); + Channel channel = handler.getThing().getChannel(CHANNEL_PRIMARY_WHITE); + if (channel != null) { + removeChannels.add(channel); + } + channel = handler.getThing().getChannel(CHANNEL_SECONDARY_WHITE); + if (channel != null) { + removeChannels.add(channel); + } + channel = handler.getThing().getChannel(CHANNEL_THIRD_WHITE); + if (channel != null) { + removeChannels.add(channel); + } + } + handler.removeChannels(removeChannels); + } + + @Override + public String sendGetRequest(String url) throws ApiException { + Request request = httpClient.newRequest(address + url); + request.timeout(3, TimeUnit.SECONDS); + request.method(HttpMethod.GET); + request.header(HttpHeader.ACCEPT_ENCODING, "gzip"); + logger.trace("Sending WLED GET:{}", url); + String errorReason = ""; + try { + ContentResponse contentResponse = request.send(); + if (contentResponse.getStatus() == 200) { + return contentResponse.getContentAsString(); + } else { + errorReason = String.format("WLED request failed with %d: %s", contentResponse.getStatus(), + contentResponse.getReason()); + } + } catch (TimeoutException e) { + errorReason = "TimeoutException: WLED was not reachable on your network"; + } catch (ExecutionException e) { + errorReason = String.format("ExecutionException: %s", e.getMessage()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + errorReason = String.format("InterruptedException: %s", e.getMessage()); + } + throw new ApiException(errorReason); + } + + protected String postState(String json) throws ApiException { + return sendPostRequest("/json/state", json); + } + + protected String sendPostRequest(String url, String json) throws ApiException { + logger.debug("Sending WLED POST:{} Message:{}", url, json); + Request request = httpClient.POST(address + url); + request.timeout(3, TimeUnit.SECONDS); + request.header(HttpHeader.CONTENT_TYPE, "application/json"); + request.content(new StringContentProvider(json), "application/json"); + String errorReason = ""; + try { + ContentResponse contentResponse = request.send(); + if (contentResponse.getStatus() == 200) { + return contentResponse.getContentAsString(); + } else { + errorReason = String.format("WLED request failed with %d: %s", contentResponse.getStatus(), + contentResponse.getReason()); + } + } catch (InterruptedException e) { + errorReason = String.format("InterruptedException: %s", e.getMessage()); + } catch (TimeoutException e) { + errorReason = "TimeoutException: WLED was not reachable on your network"; + } catch (ExecutionException e) { + errorReason = String.format("ExecutionException: %s", e.getMessage()); + } + throw new ApiException(errorReason); + } + + protected void updateStateFromReply(String jsonState) { + try { + StateResponse response = gson.fromJson(jsonState, StateResponse.class); + if (response == null) { + throw new ApiException("Reply back from WLED when command was made is not valid JSON"); + } + state.stateResponse = response; + state.unpackJsonObjects(); + processState(); + } catch (JsonSyntaxException | ApiException e) { + logger.debug("Reply back when a command was sent triggered an exception:{}", jsonState); + } + } + + protected StateResponse getState() throws ApiException { + try { + String returnContent = sendGetRequest("/json/state"); + StateResponse response = gson.fromJson(returnContent, StateResponse.class); + if (response == null) { + throw new ApiException("Could not GET:/json/state"); + } + logger.trace("json/state:{}", returnContent); + return response; + } catch (JsonSyntaxException e) { + throw new ApiException("JsonSyntaxException:{}", e); + } + } + + protected InfoResponse getInfo() throws ApiException { + try { + String returnContent = sendGetRequest("/json/info"); + InfoResponse response = gson.fromJson(returnContent, InfoResponse.class); + if (response == null) { + throw new ApiException("Could not GET:/json/info"); + } + return response; + } catch (JsonSyntaxException e) { + throw new ApiException("JsonSyntaxException:{}", e); + } + } + + protected JsonResponse getJson() throws ApiException { + try { + String returnContent = sendGetRequest("/json"); + JsonResponse response = gson.fromJson(returnContent, JsonResponse.class); + if (response == null) { + throw new ApiException("Could not GET:/json"); + } + return response; + } catch (JsonSyntaxException e) { + throw new ApiException("JsonSyntaxException:{}", e); + } + } + + @Override + public void update() throws ApiException { + state.stateResponse = getState(); + state.unpackJsonObjects(); + processState(); + } + + protected void getUpdatedFxList() { + List fxOptions = new ArrayList<>(); + int counter = 0; + for (String value : state.jsonResponse.effects) { + fxOptions.add(new StateOption(Integer.toString(counter++), value)); + } + handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_FX), + fxOptions); + } + + protected void getUpdatedPaletteList() { + List palleteOptions = new ArrayList<>(); + int counter = 0; + for (String value : state.jsonResponse.palettes) { + palleteOptions.add(new StateOption(Integer.toString(counter++), value)); + } + handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_PALETTES), + palleteOptions); + } + + @Override + public int getFirmwareVersion() throws ApiException { + state.infoResponse = getInfo(); + String temp = state.infoResponse.ver; + logger.debug("Firmware for WLED is ver:{}", temp); + temp = temp.replaceAll("\\.", ""); + if (temp.length() > 4) { + temp = temp.substring(0, 4); + } + version = Integer.parseInt(temp); + return version; + } + + protected void processState() throws ApiException { + if (state.stateResponse.seg.length <= handler.config.segmentIndex) { + throw new ApiException("Segment " + handler.config.segmentIndex + + " is not currently setup correctly in the WLED firmware"); + } + HSBType tempHSB = WLedHelper + .parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[0].toString()); + handler.update(CHANNEL_MASTER_CONTROLS, tempHSB); + handler.update(CHANNEL_PRIMARY_COLOR, tempHSB); + handler.update(CHANNEL_SECONDARY_COLOR, + WLedHelper.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[1].toString())); + handler.update(CHANNEL_THIRD_COLOR, + WLedHelper.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[2].toString())); + if (state.ledInfo.rgbw) { + handler.update(CHANNEL_PRIMARY_WHITE, WLedHelper + .parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[0].toString())); + handler.update(CHANNEL_SECONDARY_WHITE, WLedHelper + .parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[1].toString())); + handler.update(CHANNEL_THIRD_WHITE, WLedHelper + .parseWhitePercent(state.stateResponse.seg[handler.config.segmentIndex].col[2].toString())); + } + + if (!state.stateResponse.seg[handler.config.segmentIndex].on) { + handler.update(CHANNEL_MASTER_CONTROLS, OnOffType.OFF); + handler.update(CHANNEL_SEGMENT_BRIGHTNESS, OnOffType.OFF); + } else { + handler.update(CHANNEL_SEGMENT_BRIGHTNESS, + new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].bri) + .divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); + } + if (state.nightLightState.on) { + handler.update(CHANNEL_SLEEP, OnOffType.ON); + } else { + handler.update(CHANNEL_SLEEP, OnOffType.OFF); + } + if (state.stateResponse.pl == 0) { + handler.update(CHANNEL_PRESET_CYCLE, OnOffType.ON); + } else { + handler.update(CHANNEL_PRESET_CYCLE, OnOffType.OFF); + } + if (state.udpnState.recv) { + handler.update(CHANNEL_SYNC_RECEIVE, OnOffType.ON); + } else { + handler.update(CHANNEL_SYNC_RECEIVE, OnOffType.OFF); + } + if (state.udpnState.send) { + handler.update(CHANNEL_SYNC_SEND, OnOffType.ON); + } else { + handler.update(CHANNEL_SYNC_SEND, OnOffType.OFF); + } + if (state.stateResponse.seg[handler.config.segmentIndex].mi) { + handler.update(CHANNEL_MIRROR, OnOffType.ON); + } else { + handler.update(CHANNEL_MIRROR, OnOffType.OFF); + } + if (state.stateResponse.seg[handler.config.segmentIndex].rev) { + handler.update(CHANNEL_REVERSE, OnOffType.ON); + } else { + handler.update(CHANNEL_REVERSE, OnOffType.OFF); + } + handler.update(CHANNEL_TRANS_TIME, new QuantityType<>( + new BigDecimal(state.stateResponse.transition).divide(BigDecimal.TEN), Units.SECOND)); + handler.update(CHANNEL_PRESETS, new StringType(Integer.toString(state.stateResponse.ps))); + handler.update(CHANNEL_FX, + new StringType(Integer.toString(state.stateResponse.seg[handler.config.segmentIndex].fx))); + handler.update(CHANNEL_PALETTES, + new StringType(Integer.toString(state.stateResponse.seg[handler.config.segmentIndex].pal))); + handler.update(CHANNEL_SPEED, + new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].sx) + .divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); + handler.update(CHANNEL_INTENSITY, + new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].ix) + .divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); + handler.update(CHANNEL_LIVE_OVERRIDE, new StringType(Integer.toString(state.stateResponse.lor))); + handler.update(CHANNEL_GROUPING, new DecimalType(state.stateResponse.seg[handler.config.segmentIndex].grp)); + handler.update(CHANNEL_SPACING, new DecimalType(state.stateResponse.seg[handler.config.segmentIndex].spc)); + } + + @Override + public void setGlobalOn(boolean bool) throws ApiException { + updateStateFromReply(postState("{\"on\":" + bool + ",\"v\":true,\"tt\":2}")); + } + + @Override + public void setMasterOn(boolean bool, int segmentIndex) throws ApiException { + updateStateFromReply( + postState("{\"v\":true,\"tt\":2,\"seg\":[{\"id\":" + segmentIndex + ",\"on\":" + bool + "}]}")); + } + + @Override + public void setGlobalBrightness(PercentType percent) throws ApiException { + if (percent.equals(PercentType.ZERO)) { + updateStateFromReply(postState("{\"on\":false,\"v\":true}")); + return; + } + updateStateFromReply(postState("{\"on\":true,\"v\":true,\"tt\":2,\"bri\":" + + percent.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "}")); + } + + @Override + public void setMasterBrightness(PercentType percent, int segmentIndex) throws ApiException { + if (percent.equals(PercentType.ZERO)) { + updateStateFromReply(postState("{\"v\":true,\"seg\":[{\"id\":" + segmentIndex + ",\"on\":false}]}")); + return; + } + updateStateFromReply(postState("{\"tt\":2,\"v\":true,\"seg\":[{\"id\":" + segmentIndex + ",\"on\":true,\"bri\":" + + percent.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "}]}")); + } + + @Override + public void setMasterHSB(HSBType hsbType, int segmentIndex) throws ApiException { + if (hsbType.getBrightness().toBigDecimal().equals(BigDecimal.ZERO)) { + updateStateFromReply(postState("{\"tt\":2,\"v\":true,\"seg\":[{\"on\":false,\"id\":" + segmentIndex + + ",\"fx\":0,\"col\":[[" + hsbType.getRed().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + + "," + hsbType.getGreen().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getBlue().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "]]}]}")); + return; + } + updateStateFromReply(postState("{\"tt\":2,\"v\":true,\"seg\":[{\"on\":true,\"id\":" + segmentIndex + + ",\"fx\":0,\"col\":[[" + hsbType.getRed().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getGreen().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getBlue().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "]]}]}")); + } + + @Override + public void setEffect(String string, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"fx\":" + string + "}]}"); + } + + @Override + public void setPreset(String string) throws ApiException { + updateStateFromReply(postState("{\"ps\":" + string + ",\"v\":true}")); + } + + @Override + public void setPalette(String string, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"pal\":" + string + "}]}"); + } + + @Override + public void setFxIntencity(PercentType percentType, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"ix\":" + + percentType.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "}]}"); + } + + @Override + public void setFxSpeed(PercentType percentType, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"sx\":" + + percentType.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "}]}"); + } + + @Override + public void setSleep(boolean bool) throws ApiException { + postState("{\"nl\":{\"on\":" + bool + "}}"); + } + + @Override + public void setUdpSend(boolean bool) throws ApiException { + postState("{\"udpn\":{\"send\":" + bool + "}}"); + } + + @Override + public void setUdpRecieve(boolean bool) throws ApiException { + postState("{\"udpn\":{\"recv\":" + bool + "}}"); + } + + @Override + public void setTransitionTime(BigDecimal time) throws ApiException { + postState("{\"transition\":" + time + "}"); + } + + @Override + public void setPresetCycle(boolean bool) throws ApiException { + if (bool) { + postState("{\"pl\":0}"); + } else { + postState("{\"pl\":-1}"); + } + } + + @Override + public void setPrimaryColor(HSBType hsbType, int segmentIndex) throws ApiException { + postState("{\"on\":true,\"seg\":[{\"id\":" + segmentIndex + ",\"col\":[[" + + hsbType.getRed().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getGreen().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getBlue().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "],[],[]]}]}"); + } + + @Override + public void setSecondaryColor(HSBType hsbType, int segmentIndex) throws ApiException { + postState("{\"on\":true,\"seg\":[{\"id\":" + segmentIndex + ",\"col\":[[],[" + + hsbType.getRed().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getGreen().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getBlue().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "],[]]}]}"); + } + + @Override + public void setTertiaryColor(HSBType hsbType, int segmentIndex) throws ApiException { + postState("{\"on\":true,\"seg\":[{\"id\":" + segmentIndex + ",\"col\":[[],[],[" + + hsbType.getRed().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getGreen().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "," + + hsbType.getBlue().toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "]]}]}"); + } + + @Override + public void setWhiteOnly(PercentType percentType, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"on\":true,\"id\":" + segmentIndex + ",\"fx\":0,\"col\":[[0,0,0," + + percentType.toBigDecimal().multiply(BIG_DECIMAL_2_55).intValue() + "]]}]}"); + } + + @Override + public void setMirror(boolean bool, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"mi\":" + bool + "}]}"); + } + + @Override + public void setReverse(boolean bool, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"rev\":" + bool + "}]}"); + } + + @Override + public void savePreset(int position, String presetName) throws ApiException { + // named presets not supported in older firmwares, and max of 16. + if (position > 16 || position < 1) { + logger.warn("Preset position {} is not supported in this firmware version", position); + return; + } + try { + sendGetRequest("/win&PS=" + position); + } catch (ApiException e) { + logger.warn("Preset failed to save:{}", e.getMessage()); + } + } + + @Override + public void setLiveOverride(String value) throws ApiException { + postState("{\"lor\":" + value + "}"); + } + + @Override + public void setGrouping(int value, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"grp\":" + value + "}]}"); + } + + @Override + public void setSpacing(int value, int segmentIndex) throws ApiException { + postState("{\"seg\":[{\"id\":" + segmentIndex + ",\"spc\":" + value + "}]}"); + } +} diff --git a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml index 4ae88dbcf4f12..1d565066ff4d4 100644 --- a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml @@ -10,11 +10,15 @@ ColorLight + + + + @@ -22,6 +26,11 @@ + + + + + @@ -36,11 +45,11 @@ Time in seconds of how often to fetch the state of the LEDs. 10 - + - Leave this as -1 if you are not using segments, otherwise set this to the segment index number that you + Leave this as 0 if you are not using segments, otherwise set this to the segment index number that you wish to control. - -1 + 0 @@ -62,6 +71,13 @@ + + Dimmer + + Changes the brightness of the whole segment + DimmableLight + + Color @@ -90,6 +106,20 @@ DimmableLight + + Color + + Allows you to change the third color used in FX + ColorLight + + + + Dimmer + + Changes the brightness of the third white LED + DimmableLight + + String @@ -128,6 +158,12 @@ + + String + + The currently playing play list + + Number:Time @@ -136,12 +172,55 @@ + + Number + + How many consecutive LEDs of the same segment will be grouped to the same color + + + + + Number + + How many LEDs are turned off and skipped between each group + + + + + String + + Live data override. 0 is off, 1 is override until live data ends, 2 is override until ESP reboot + + + + + + + + + Number:Time Time it takes to change/fade from one look to the next. Time - + + + + @@ -156,6 +235,18 @@ Change the intensity of the FX + + Switch + + Mirror the effect for this segment + + + + Switch + + Reverse the direction of the current segment + + Switch @@ -163,7 +254,7 @@ Time - + Switch Cycle through the saved presets From 1dc734159979429057d98e6f4be47e3887900acc Mon Sep 17 00:00:00 2001 From: antroids <36043354+antroids@users.noreply.github.com> Date: Sat, 20 Nov 2021 12:44:09 +0100 Subject: [PATCH 119/361] [MQTT.Homeassistant] make the mqtt.vacuum implementation compilant with the specification (#11562) Signed-off-by: Anton Kharuzhy Signed-off-by: Michael Schmidt --- .../internal/component/Vacuum.java | 451 ++++++++++-------- .../internal/component/VacuumTests.java | 254 ++++++++++ 2 files changed, 503 insertions(+), 202 deletions(-) create mode 100644 bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java index b999380fa5721..29381a560c7a4 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/Vacuum.java @@ -15,14 +15,21 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.mqtt.generic.values.DateTimeValue; -import org.openhab.binding.mqtt.generic.values.NumberValue; +import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener; +import org.openhab.binding.mqtt.generic.values.OnOffValue; +import org.openhab.binding.mqtt.generic.values.PercentageValue; import org.openhab.binding.mqtt.generic.values.TextValue; +import org.openhab.binding.mqtt.generic.values.Value; +import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel; import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.gson.annotations.SerializedName; @@ -30,38 +37,62 @@ * A MQTT vacuum, following the https://www.home-assistant.io/components/vacuum.mqtt/ specification. * * @author Stefan Triller - Initial contribution + * @author Anton Kharuzhyi - Make it compilant with the Specification */ @NonNullByDefault public class Vacuum extends AbstractComponent { - public static final String VACUUM_STATE_CHANNEL_ID = "state"; - public static final String VACUUM_COMMAND_CHANNEL_ID = "command"; - public static final String VACUUM_BATTERY_CHANNEL_ID = "batteryLevel"; - public static final String VACUUM_FAN_SPEED_CHANNEL_ID = "fanSpeed"; - - // sensor stats - public static final String VACUUM_MAIN_BRUSH_CHANNEL_ID = "mainBrushUsage"; - public static final String VACUUM_SIDE_BRUSH_CHANNEL_ID = "sideBrushUsage"; - public static final String VACUUM_FILTER_CHANNEL_ID = "filter"; - public static final String VACUUM_SENSOR_CHANNEL_ID = "sensor"; - public static final String VACUUM_CURRENT_CLEAN_TIME_CHANNEL_ID = "currentCleanTime"; - public static final String VACUUM_CURRENT_CLEAN_AREA_CHANNEL_ID = "currentCleanArea"; - public static final String VACUUM_CLEAN_TIME_CHANNEL_ID = "cleanTime"; - public static final String VACUUM_CLEAN_AREA_CHANNEL_ID = "cleanArea"; - public static final String VACUUM_CLEAN_COUNT_CHANNEL_ID = "cleanCount"; - - public static final String VACUUM_LAST_RUN_START_CHANNEL_ID = "lastRunStart"; - public static final String VACUUM_LAST_RUN_END_CHANNEL_ID = "lastRunEnd"; - public static final String VACUUM_LAST_RUN_DURATION_CHANNEL_ID = "lastRunDuration"; - public static final String VACUUM_LAST_RUN_AREA_CHANNEL_ID = "lastRunArea"; - public static final String VACUUM_LAST_RUN_ERROR_CODE_CHANNEL_ID = "lastRunErrorCode"; - public static final String VACUUM_LAST_RUN_ERROR_DESCRIPTION_CHANNEL_ID = "lastRunErrorDescription"; - public static final String VACUUM_LAST_RUN_FINISHED_FLAG_CHANNEL_ID = "lastRunFinishedFlag"; - - public static final String VACUUM_BIN_IN_TIME_CHANNEL_ID = "binInTime"; - public static final String VACUUM_LAST_BIN_OUT_TIME_CHANNEL_ID = "lastBinOutTime"; - public static final String VACUUM_LAST_BIN_FULL_TIME_CHANNEL_ID = "lastBinFullTime"; - - public static final String VACUUM_CUSMTOM_COMMAND_CHANNEL_ID = "customCommand"; + public static final String SCHEMA_LEGACY = "legacy"; + public static final String SCHEMA_STATE = "state"; + + public static final String TRUE = "true"; + public static final String FALSE = "false"; + public static final String OFF = "off"; + + public static final String FEATURE_TURN_ON = "turn_on"; // Begin cleaning + public static final String FEATURE_TURN_OFF = "turn_off"; // Turn the Vacuum off + public static final String FEATURE_RETURN_HOME = "return_home"; // Return to base/dock + public static final String FEATURE_START = "start"; + public static final String FEATURE_STOP = "stop"; // Stop the Vacuum + public static final String FEATURE_CLEAN_SPOT = "clean_spot"; // Initialize a spot cleaning cycle + public static final String FEATURE_LOCATE = "locate"; // Locate the vacuum (typically by playing a song) + public static final String FEATURE_PAUSE = "pause"; // Pause the vacuum + public static final String FEATURE_BATTERY = "battery"; + public static final String FEATURE_STATUS = "status"; + public static final String FEATURE_FAN_SPEED = "fan_speed"; + public static final String FEATURE_SEND_COMMAND = "send_command"; + + // State Schema only + public static final String STATE_CLEANING = "cleaning"; + public static final String STATE_DOCKED = "docked"; + public static final String STATE_PAUSED = "paused"; + public static final String STATE_IDLE = "idle"; + public static final String STATE_RETURNING = "returning"; + public static final String STATE_ERROR = "error"; + + public static final String COMMAND_CH_ID = "command"; + public static final String FAN_SPEED_CH_ID = "fanSpeed"; + public static final String CUSTOM_COMMAND_CH_ID = "customCommand"; + public static final String BATTERY_LEVEL_CH_ID = "batteryLevel"; + public static final String CHARGING_CH_ID = "charging"; + public static final String CLEANING_CH_ID = "cleaning"; + public static final String DOCKED_CH_ID = "docked"; + public static final String ERROR_CH_ID = "error"; + public static final String JSON_ATTRIBUTES_CH_ID = "jsonAttributes"; + public static final String STATE_CH_ID = "state"; + + public static final List LEGACY_DEFAULT_FEATURES = List.of(FEATURE_TURN_ON, FEATURE_TURN_OFF, FEATURE_STOP, + FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_CLEAN_SPOT); + public static final List LEGACY_SUPPORTED_FEATURES = List.of(FEATURE_TURN_ON, FEATURE_TURN_OFF, + FEATURE_PAUSE, FEATURE_STOP, FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_LOCATE, + FEATURE_CLEAN_SPOT, FEATURE_FAN_SPEED, FEATURE_SEND_COMMAND); + + public static final List STATE_DEFAULT_FEATURES = List.of(FEATURE_START, FEATURE_STOP, FEATURE_RETURN_HOME, + FEATURE_STATUS, FEATURE_BATTERY, FEATURE_CLEAN_SPOT); + public static final List STATE_SUPPORTED_FEATURES = List.of(FEATURE_START, FEATURE_STOP, FEATURE_PAUSE, + FEATURE_RETURN_HOME, FEATURE_BATTERY, FEATURE_STATUS, FEATURE_LOCATE, FEATURE_CLEAN_SPOT, FEATURE_FAN_SPEED, + FEATURE_SEND_COMMAND); + + private static final Logger LOGGER = LoggerFactory.getLogger(Vacuum.class); /** * Configuration class for MQTT component @@ -71,204 +102,220 @@ static class ChannelConfiguration extends AbstractChannelConfiguration { super("MQTT Vacuum"); } + // Legacy and Common MQTT vacuum configuration section. + + @SerializedName("battery_level_template") + protected @Nullable String batteryLevelTemplate; + @SerializedName("battery_level_topic") + protected @Nullable String batteryLevelTopic; + + @SerializedName("charging_template") + protected @Nullable String chargingTemplate; + @SerializedName("charging_topic") + protected @Nullable String chargingTopic; + + @SerializedName("cleaning_template") + protected @Nullable String cleaningTemplate; + @SerializedName("cleaning_topic") + protected @Nullable String cleaningTopic; + @SerializedName("command_topic") protected @Nullable String commandTopic; - @SerializedName("state_topic") - protected String stateTopic = ""; + + @SerializedName("docked_template") + protected @Nullable String dockedTemplate; + @SerializedName("docked_topic") + protected @Nullable String dockedTopic; + + @SerializedName("enabled_by_default") + protected @Nullable Boolean enabledByDefault = true; + + @SerializedName("error_template") + protected @Nullable String errorTemplate; + @SerializedName("error_topic") + protected @Nullable String errorTopic; + + @SerializedName("fan_speed_list") + protected @Nullable List fanSpeedList; + @SerializedName("fan_speed_template") + protected @Nullable String fanSpeedTemplate; + @SerializedName("fan_speed_topic") + protected @Nullable String fanSpeedTopic; + + @SerializedName("payload_clean_spot") + protected @Nullable String payloadCleanSpot = "clean_spot"; + @SerializedName("payload_locate") + protected @Nullable String payloadLocate = "locate"; + @SerializedName("payload_return_to_base") + protected @Nullable String payloadReturnToBase = "return_to_base"; + @SerializedName("payload_start_pause") + protected @Nullable String payloadStartPause = "start_pause"; // Legacy only + @SerializedName("payload_stop") + protected @Nullable String payloadStop = "stop"; + @SerializedName("payload_turn_off") + protected @Nullable String payloadTurnOff = "turn_off"; + @SerializedName("payload_turn_on") + protected @Nullable String payloadTurnOn = "turn_on"; + + @SerializedName("schema") + protected Schema schema = Schema.LEGACY; + @SerializedName("send_command_topic") - protected @Nullable String sendCommandTopic; // for custom_command + protected @Nullable String sendCommandTopic; - // [start, pause, stop, return_home, battery, status, locate, clean_spot, fan_speed, send_command] - @SerializedName("supported_features") - protected String[] supportedFeatures = new String[] {}; @SerializedName("set_fan_speed_topic") protected @Nullable String setFanSpeedTopic; - @SerializedName("fan_speed_list") - protected String[] fanSpeedList = new String[] {}; - @SerializedName("json_attributes_topic") - protected @Nullable String jsonAttributesTopic; + @SerializedName("supported_features") + protected @Nullable List supportedFeatures; + + // State MQTT vacuum configuration section. + + // Start/Pause replaced by 2 payloads + @SerializedName("payload_pause") + protected @Nullable String payloadPause = "pause"; + @SerializedName("payload_start") + protected @Nullable String payloadStart = "start"; + + @SerializedName("state_topic") + protected @Nullable String stateTopic; + @SerializedName("json_attributes_template") protected @Nullable String jsonAttributesTemplate; + @SerializedName("json_attributes_topic") + protected @Nullable String jsonAttributesTopic; } + /** + * Creates component based on generic configuration and component configuration type. + * + * @param componentConfiguration generic componentConfiguration with not parsed JSON config + */ public Vacuum(ComponentFactory.ComponentConfiguration componentConfiguration) { super(componentConfiguration, ChannelConfiguration.class); - - List features = Arrays.asList(channelConfiguration.supportedFeatures); - - // features = [start, pause, stop, return_home, status, locate, clean_spot, fan_speed, send_command] - ArrayList possibleCommands = new ArrayList(); - if (features.contains("start")) { - possibleCommands.add("start"); + final ChannelStateUpdateListener updateListener = componentConfiguration.getUpdateListener(); + + final var allowedSupportedFeatures = channelConfiguration.schema == Schema.LEGACY ? LEGACY_SUPPORTED_FEATURES + : STATE_SUPPORTED_FEATURES; + final var configSupportedFeatures = channelConfiguration.supportedFeatures == null + ? channelConfiguration.schema == Schema.LEGACY ? LEGACY_DEFAULT_FEATURES : STATE_DEFAULT_FEATURES + : channelConfiguration.supportedFeatures; + List deviceSupportedFeatures = Collections.emptyList(); + + if (!configSupportedFeatures.isEmpty()) { + deviceSupportedFeatures = allowedSupportedFeatures.stream().filter(configSupportedFeatures::contains) + .collect(Collectors.toList()); } - - if (features.contains("stop")) { - possibleCommands.add("stop"); + if (deviceSupportedFeatures.size() != configSupportedFeatures.size()) { + LOGGER.warn("Vacuum discovery config has unsupported or duplicated features. Supported: {}, provided: {}", + Arrays.toString(allowedSupportedFeatures.toArray()), + Arrays.toString(configSupportedFeatures.toArray())); } - if (features.contains("pause")) { - possibleCommands.add("pause"); + final List commands = new ArrayList<>(); + addPayloadToList(deviceSupportedFeatures, FEATURE_CLEAN_SPOT, channelConfiguration.payloadCleanSpot, commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_LOCATE, channelConfiguration.payloadLocate, commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_RETURN_HOME, channelConfiguration.payloadReturnToBase, + commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_STOP, channelConfiguration.payloadStop, commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_TURN_OFF, channelConfiguration.payloadTurnOff, commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_TURN_ON, channelConfiguration.payloadTurnOn, commands); + + if (channelConfiguration.schema == Schema.LEGACY) { + addPayloadToList(deviceSupportedFeatures, FEATURE_PAUSE, channelConfiguration.payloadStartPause, commands); + } else { + addPayloadToList(deviceSupportedFeatures, FEATURE_PAUSE, channelConfiguration.payloadPause, commands); + addPayloadToList(deviceSupportedFeatures, FEATURE_START, channelConfiguration.payloadStart, commands); } - if (features.contains("return_home")) { - possibleCommands.add("return_to_base"); + buildOptionalChannel(COMMAND_CH_ID, new TextValue(commands.toArray(new String[0])), updateListener, null, + channelConfiguration.commandTopic, null, null); + + final var fanSpeedList = channelConfiguration.fanSpeedList; + if (deviceSupportedFeatures.contains(FEATURE_FAN_SPEED) && fanSpeedList != null && !fanSpeedList.isEmpty()) { + if (!fanSpeedList.contains(OFF)) { + fanSpeedList.add(OFF); // Off value is used when cleaning if OFF + } + var fanSpeedValue = new TextValue(fanSpeedList.toArray(new String[0])); + if (channelConfiguration.schema == Schema.LEGACY) { + buildOptionalChannel(FAN_SPEED_CH_ID, fanSpeedValue, updateListener, null, + channelConfiguration.setFanSpeedTopic, channelConfiguration.fanSpeedTemplate, + channelConfiguration.fanSpeedTopic); + } else if (deviceSupportedFeatures.contains(FEATURE_STATUS)) { + buildOptionalChannel(FAN_SPEED_CH_ID, fanSpeedValue, updateListener, null, + channelConfiguration.setFanSpeedTopic, "{{ value_json.fan_speed }}", + channelConfiguration.stateTopic); + } else { + LOGGER.info("Status feature is disabled, unable to get fan speed."); + buildOptionalChannel(FAN_SPEED_CH_ID, fanSpeedValue, updateListener, null, + channelConfiguration.setFanSpeedTopic, null, null); + } } - if (features.contains("locate")) { - possibleCommands.add("locate"); + if (deviceSupportedFeatures.contains(FEATURE_SEND_COMMAND)) { + buildOptionalChannel(CUSTOM_COMMAND_CH_ID, new TextValue(), updateListener, null, + channelConfiguration.sendCommandTopic, null, null); } - TextValue value = new TextValue(possibleCommands.toArray(new String[0])); - buildChannel(VACUUM_COMMAND_CHANNEL_ID, value, "Command", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.commandTopic).commandTopic(channelConfiguration.commandTopic, false, 1) - .build(); - - List vacuumStates = List.of("docked", "cleaning", "returning", "paused", "idle", "error"); - TextValue valueState = new TextValue(vacuumStates.toArray(new String[0])); - buildChannel(VACUUM_STATE_CHANNEL_ID, valueState, "State", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.stateTopic, "{{value_json.state}}").build(); - - if (features.contains("battery")) { - // build battery level channel (0-100) - NumberValue batValue = new NumberValue(BigDecimal.ZERO, new BigDecimal(100), new BigDecimal(1), "%"); - buildChannel(VACUUM_BATTERY_CHANNEL_ID, batValue, "Battery Level", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.stateTopic, "{{value_json.battery_level}}").build(); + if (channelConfiguration.schema == Schema.LEGACY) { + // I assume, that if these topics defined in config, then we don't need to check features + buildOptionalChannel(BATTERY_LEVEL_CH_ID, + new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null), + updateListener, null, null, channelConfiguration.batteryLevelTemplate, + channelConfiguration.batteryLevelTopic); + buildOptionalChannel(CHARGING_CH_ID, new OnOffValue(TRUE, FALSE), updateListener, null, null, + channelConfiguration.chargingTemplate, channelConfiguration.chargingTopic); + buildOptionalChannel(CLEANING_CH_ID, new OnOffValue(TRUE, FALSE), updateListener, null, null, + channelConfiguration.cleaningTemplate, channelConfiguration.cleaningTopic); + buildOptionalChannel(DOCKED_CH_ID, new OnOffValue(TRUE, FALSE), updateListener, null, null, + channelConfiguration.dockedTemplate, channelConfiguration.dockedTopic); + buildOptionalChannel(ERROR_CH_ID, new TextValue(), updateListener, null, null, + channelConfiguration.errorTemplate, channelConfiguration.errorTopic); + } else { + if (deviceSupportedFeatures.contains(FEATURE_STATUS)) { + // state key is mandatory + buildOptionalChannel(STATE_CH_ID, + new TextValue(new String[] { STATE_CLEANING, STATE_DOCKED, STATE_PAUSED, STATE_IDLE, + STATE_RETURNING, STATE_ERROR }), + updateListener, null, null, "{{ value_json.state }}", channelConfiguration.stateTopic); + if (deviceSupportedFeatures.contains(FEATURE_BATTERY)) { + buildOptionalChannel(BATTERY_LEVEL_CH_ID, + new PercentageValue(BigDecimal.ZERO, BigDecimal.valueOf(100), BigDecimal.ONE, null, null), + updateListener, null, null, "{{ value_json.battery_level }}", + channelConfiguration.stateTopic); + } + } } - if (features.contains("fan_speed")) { - // build fan speed channel with values from channelConfiguration.fan_speed_list - TextValue fanValue = new TextValue(channelConfiguration.fanSpeedList); - buildChannel(VACUUM_FAN_SPEED_CHANNEL_ID, fanValue, "Fan speed", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.stateTopic, "{{value_json.fan_speed}}") - .commandTopic(channelConfiguration.setFanSpeedTopic, false, 1).build(); - } + buildOptionalChannel(JSON_ATTRIBUTES_CH_ID, new TextValue(), updateListener, null, null, + channelConfiguration.jsonAttributesTemplate, channelConfiguration.jsonAttributesTopic); + } - // {"mainBrush":"220.6","sideBrush":"120.6","filter":"70.6","sensor":"0.0","currentCleanTime":"0.0","currentCleanArea":"0.0","cleanTime":"79.3","cleanArea":"4439.9","cleanCount":183,"last_run_stats":{"startTime":1613503117000,"endTime":1613503136000,"duration":0,"area":"0.0","errorCode":0,"errorDescription":"No - // error","finishedFlag":false},"bin_in_time":1000,"last_bin_out":-1,"last_bin_full":-1,"last_loaded_map":null,"state":"docked","valetudo_state":{"id":8,"name":"Charging"}} - if (features.contains("status")) { - NumberValue currentCleanTimeValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_CURRENT_CLEAN_TIME_CHANNEL_ID, currentCleanTimeValue, "Current Cleaning Time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.currentCleanTime}}") - .build(); - - NumberValue currentCleanAreaValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_CURRENT_CLEAN_AREA_CHANNEL_ID, currentCleanAreaValue, "Current Cleaning Area", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.currentCleanArea}}") - .build(); - - NumberValue cleanTimeValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_CLEAN_TIME_CHANNEL_ID, cleanTimeValue, "Cleaning Time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanTime}}").build(); - - NumberValue cleanAreaValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_CLEAN_AREA_CHANNEL_ID, cleanAreaValue, "Cleaned Area", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanArea}}").build(); - - NumberValue cleaCountValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_CLEAN_COUNT_CHANNEL_ID, cleaCountValue, "Cleaning Counter", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.cleanCount}}").build(); - - DateTimeValue lastStartTime = new DateTimeValue(); - buildChannel(VACUUM_LAST_RUN_START_CHANNEL_ID, lastStartTime, "Last run start time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.startTime}}") - .build(); - - DateTimeValue lastEndTime = new DateTimeValue(); - buildChannel(VACUUM_LAST_RUN_END_CHANNEL_ID, lastEndTime, "Last run end time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.endTime}}") - .build(); - - NumberValue lastRunDurationValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_LAST_RUN_DURATION_CHANNEL_ID, lastRunDurationValue, "Last run duration", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.duration}}") - .build(); - - NumberValue lastRunAreaValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_LAST_RUN_AREA_CHANNEL_ID, lastRunAreaValue, "Last run area", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_run_stats.area}}") - .build(); - - NumberValue lastRunErrorCodeValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_LAST_RUN_ERROR_CODE_CHANNEL_ID, lastRunErrorCodeValue, "Last run error code", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.errorCode}}") - .build(); - - TextValue lastRunErrorDescriptionValue = new TextValue(); - buildChannel(VACUUM_LAST_RUN_ERROR_DESCRIPTION_CHANNEL_ID, lastRunErrorDescriptionValue, - "Last run error description", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.errorDescription}}") - .build(); - - // true/false doesnt map to ON/OFF => use TextValue instead of OnOffValue - TextValue lastRunFinishedFlagValue = new TextValue(); - buildChannel(VACUUM_LAST_RUN_FINISHED_FLAG_CHANNEL_ID, lastRunFinishedFlagValue, "Last run finished flag", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, - "{{value_json.last_run_stats.finishedFlag}}") - .build(); - - // only for valetudo re => advanced channels - DateTimeValue binInValue = new DateTimeValue(); - buildChannel(VACUUM_BIN_IN_TIME_CHANNEL_ID, binInValue, "Bin In Time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.bin_in_time}}") - .isAdvanced(true).build(); - - DateTimeValue lastBinOutValue = new DateTimeValue(); - buildChannel(VACUUM_LAST_BIN_OUT_TIME_CHANNEL_ID, lastBinOutValue, "Last Bin Out Time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_bin_out}}") - .isAdvanced(true).build(); - - DateTimeValue lastBinFullValue = new DateTimeValue(); - buildChannel(VACUUM_LAST_BIN_FULL_TIME_CHANNEL_ID, lastBinFullValue, "Last Bin Full Time", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.last_bin_full}}") - .isAdvanced(true).build(); + @Nullable + private ComponentChannel buildOptionalChannel(String channelId, Value valueState, + ChannelStateUpdateListener channelStateUpdateListener, @Nullable String commandTemplate, + @Nullable String commandTopic, @Nullable String stateTemplate, @Nullable String stateTopic) { + if ((commandTopic != null && !commandTopic.isBlank()) || (stateTopic != null && !stateTopic.isBlank())) { + return buildChannel(channelId, valueState, channelConfiguration.getName(), channelStateUpdateListener) + .stateTopic(stateTopic, stateTemplate, channelConfiguration.getValueTemplate()) + .commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos(), + commandTemplate) + .build(); } + return null; + } - NumberValue mainBrush = new NumberValue(null, null, null, null); - buildChannel(VACUUM_MAIN_BRUSH_CHANNEL_ID, mainBrush, "Main brush usage", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.mainBrush}}").build(); - - NumberValue sideBrush = new NumberValue(null, null, null, null); - buildChannel(VACUUM_SIDE_BRUSH_CHANNEL_ID, sideBrush, "Side brush usage", - componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.sideBrush}}").build(); - - NumberValue filterValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_FILTER_CHANNEL_ID, filterValue, "Filter time", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.filter}}").build(); - - NumberValue sensorValue = new NumberValue(null, null, null, null); - buildChannel(VACUUM_SENSOR_CHANNEL_ID, sensorValue, "Sensor", componentConfiguration.getUpdateListener()) - .stateTopic(channelConfiguration.jsonAttributesTopic, "{{value_json.sensor}}").build(); - - // if we have a custom command channel for zone cleanup, etc => create text channel - if (channelConfiguration.sendCommandTopic != null) { - TextValue customCommandValue = new TextValue(); - buildChannel(VACUUM_CUSMTOM_COMMAND_CHANNEL_ID, customCommandValue, "Custom Command", - componentConfiguration.getUpdateListener()) - .commandTopic(channelConfiguration.sendCommandTopic, false, 1) - .stateTopic(channelConfiguration.sendCommandTopic).build(); + private void addPayloadToList(List supportedFeatures, String feature, @Nullable String payload, + List list) { + if (supportedFeatures.contains(feature) && payload != null && !payload.isEmpty()) { + list.add(payload); } } + + public enum Schema { + @SerializedName("legacy") + LEGACY, + @SerializedName("state") + STATE + } } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java new file mode 100644 index 0000000000000..ec29ee6d8303c --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/VacuumTests.java @@ -0,0 +1,254 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mqtt.homeassistant.internal.component; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.openhab.binding.mqtt.generic.values.OnOffValue; +import org.openhab.binding.mqtt.generic.values.PercentageValue; +import org.openhab.binding.mqtt.generic.values.TextValue; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.UnDefType; + +/** + * Tests for {@link Vacuum} + * + * @author Anton Kharuzhy - Initial contribution + */ +@SuppressWarnings("ConstantConditions") +public class VacuumTests extends AbstractComponentTests { + public static final String CONFIG_TOPIC = "vacuum/rockrobo_vacuum"; + + @Test + public void testRoborockValetudo() { + // @formatter:off + var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" + + "\"name\":\"Rockrobo\"," + + "\"unique_id\":\"rockrobo_vacuum\"," + + "\"schema\":\"state\"," + + "\"device\":{" + + " \"manufacturer\":\"Roborock\"," + + " \"model\":\"v1\"," + + " \"name\":\"rockrobo\"," + + " \"identifiers\":[\"rockrobo\"]," + + " \"sw_version\":\"0.9.9\"" + + "}," + + "\"supported_features\":[\"start\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," + + " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," + + "\"command_topic\":\"valetudo/rockrobo/command\"," + + "\"state_topic\":\"valetudo/rockrobo/state\"," + + "\"set_fan_speed_topic\":\"valetudo/rockrobo/set_fan_speed\"," + + "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\",\"mop\"]," + + "\"send_command_topic\":\"valetudo/rockrobo/custom_command\"," + + "\"json_attributes_topic\":\"valetudo/rockrobo/attributes\"" + + "}"); + // @formatter:on + + assertThat(component.channels.size(), is(6)); // command, state, fan speed, send command, battery, json attrs + assertThat(component.getName(), is("Rockrobo")); + assertChannel(component, Vacuum.COMMAND_CH_ID, "", "valetudo/rockrobo/command", "Rockrobo", TextValue.class); + assertChannel(component, Vacuum.STATE_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo", TextValue.class); + assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "valetudo/rockrobo/state", "valetudo/rockrobo/set_fan_speed", + "Rockrobo", TextValue.class); + assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "valetudo/rockrobo/custom_command", "Rockrobo", + TextValue.class); + assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "valetudo/rockrobo/state", "", "Rockrobo", + PercentageValue.class); + assertChannel(component, Vacuum.JSON_ATTRIBUTES_CH_ID, "valetudo/rockrobo/attributes", "", "Rockrobo", + TextValue.class); + + assertState(component, Vacuum.STATE_CH_ID, UnDefType.UNDEF); + assertState(component, Vacuum.FAN_SPEED_CH_ID, UnDefType.UNDEF); + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, UnDefType.UNDEF); + assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, UnDefType.UNDEF); + + // @formatter:off + String jsonValue; + publishMessage("valetudo/rockrobo/attributes", jsonValue = "{" + + "\"mainBrush\":\"245.1\"," + + "\"sideBrush\":\"145.1\"," + + "\"filter\":\"95.1\"," + + "\"sensor\":\"0.0\"," + + "\"currentCleanTime\":\"52.0\"," + + "\"currentCleanArea\":\"46.7\"," + + "\"cleanTime\":\"54.9\"," + + "\"cleanArea\":\"3280.9\"," + + "\"cleanCount\":84," + + "\"last_run_stats\":{" + + " \"startTime\":1633257319000," + + " \"endTime\":1633260439000," + + " \"duration\":3120," + + " \"area\":\"46.7\"," + + " \"errorCode\":0," + + " \"errorDescription\":\"No error\"," + + " \"finishedFlag\":true" + + "}," + + "\"last_bin_out\":2147483647000," + + "\"state\":\"docked\"," + + "\"valetudo_state\":{" + + " \"id\":8," + + " \"name\":\"Charging\"" + + "}," + + "\"last_bin_full\":0" + + "}"); + // @formatter:on + + // @formatter:off + publishMessage("valetudo/rockrobo/state", "{" + + "\"state\":\"docked\"," + + "\"battery_level\":100," + + "\"fan_speed\":\"max\"" + + "}"); + // @formatter:on + + assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_DOCKED)); + assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max")); + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(100)); + assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue)); + + component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("start")); + assertPublished("valetudo/rockrobo/command", "start"); + + // @formatter:off + publishMessage("valetudo/rockrobo/state", "{" + + "\"state\":\"cleaning\"," + + "\"battery_level\":99," + + "\"fan_speed\":\"max\"" + + "}"); + // @formatter:on + + assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_CLEANING)); + assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("max")); + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(99)); + assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue)); + + component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("medium")); + assertPublished("valetudo/rockrobo/set_fan_speed", "medium"); + + // @formatter:off + publishMessage("valetudo/rockrobo/state", "{" + + "\"state\":\"returning\"," + + "\"battery_level\":80," + + "\"fan_speed\":\"medium\"" + + "}"); + // @formatter:on + + assertState(component, Vacuum.STATE_CH_ID, new StringType(Vacuum.STATE_RETURNING)); + assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium")); + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(80)); + assertState(component, Vacuum.JSON_ATTRIBUTES_CH_ID, new StringType(jsonValue)); + } + + @Test + public void testLegacySchema() { + // @formatter:off + var component = discoverComponent(configTopicToMqtt(CONFIG_TOPIC), "{" + + "\"name\":\"Rockrobo\"," + + "\"unique_id\":\"rockrobo_vacuum\"," + + "\"device\":{" + + " \"manufacturer\":\"Roborock\"," + + " \"model\":\"v1\"," + + " \"name\":\"rockrobo\"," + + " \"identifiers\":[\"rockrobo\"]," + + " \"sw_version\":\"0.9.9\"" + + "}," + + "\"supported_features\":[\"turn_on\", \"turn_off\",\"pause\",\"stop\",\"return_home\",\"battery\",\"status\"," + + " \"locate\",\"clean_spot\",\"fan_speed\",\"send_command\"]," + + "\"command_topic\":\"vacuum/command\"," + + "\"battery_level_topic\":\"vacuum/state\"," + + "\"battery_level_template\":\"{{ value_json.battery_level }}\"," + + "\"charging_topic\":\"vacuum/state\"," + + "\"charging_template\":\"{{ value_json.charging }}\"," + + "\"cleaning_topic\":\"vacuum/state\"," + + "\"cleaning_template\":\"{{ value_json.cleaning }}\"," + + "\"docked_topic\":\"vacuum/state\"," + + "\"docked_template\":\"{{ value_json.docked }}\"," + + "\"error_topic\":\"vacuum/state\"," + + "\"error_template\":\"{{ value_json.error }}\"," + + "\"fan_speed_topic\":\"vacuum/state\"," + + "\"set_fan_speed_topic\":\"vacuum/set_fan_speed\"," + + "\"fan_speed_template\":\"{{ value_json.fan_speed }}\"," + + "\"fan_speed_list\":[\"min\",\"medium\",\"high\",\"max\"]," + + "\"send_command_topic\":\"vacuum/send_command\"" + + "}"); + // @formatter:on + + assertThat(component.channels.size(), is(8)); // command, battery, charging, cleaning, docked, error, + // fan speed, send command + assertThat(component.getName(), is("Rockrobo")); + assertChannel(component, Vacuum.COMMAND_CH_ID, "", "vacuum/command", "Rockrobo", TextValue.class); + assertChannel(component, Vacuum.BATTERY_LEVEL_CH_ID, "vacuum/state", "", "Rockrobo", PercentageValue.class); + assertChannel(component, Vacuum.CHARGING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); + assertChannel(component, Vacuum.CLEANING_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); + assertChannel(component, Vacuum.DOCKED_CH_ID, "vacuum/state", "", "Rockrobo", OnOffValue.class); + assertChannel(component, Vacuum.ERROR_CH_ID, "vacuum/state", "", "Rockrobo", TextValue.class); + assertChannel(component, Vacuum.FAN_SPEED_CH_ID, "vacuum/state", "vacuum/set_fan_speed", "Rockrobo", + TextValue.class); + assertChannel(component, Vacuum.CUSTOM_COMMAND_CH_ID, "", "vacuum/send_command", "Rockrobo", TextValue.class); + + // @formatter:off + publishMessage("vacuum/state", "{" + + "\"battery_level\": 61," + + "\"docked\": true," + + "\"cleaning\": false," + + "\"charging\": true," + + "\"fan_speed\": \"off\"," + + "\"error\": \"Error message\"" + + "}"); + // @formatter:on + + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(61)); + assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.ON); + assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.OFF); + assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.ON); + assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("off")); + assertState(component, Vacuum.ERROR_CH_ID, new StringType("Error message")); + + component.getChannel(Vacuum.COMMAND_CH_ID).getState().publishValue(new StringType("turn_on")); + assertPublished("vacuum/command", "turn_on"); + + // @formatter:off + publishMessage("vacuum/state", "{" + + "\"battery_level\": 55," + + "\"docked\": false," + + "\"cleaning\": true," + + "\"charging\": false," + + "\"fan_speed\": \"medium\"," + + "\"error\": \"\"" + + "}"); + // @formatter:on + + assertState(component, Vacuum.BATTERY_LEVEL_CH_ID, new PercentType(55)); + assertState(component, Vacuum.DOCKED_CH_ID, OnOffType.OFF); + assertState(component, Vacuum.CLEANING_CH_ID, OnOffType.ON); + assertState(component, Vacuum.CHARGING_CH_ID, OnOffType.OFF); + assertState(component, Vacuum.FAN_SPEED_CH_ID, new StringType("medium")); + assertState(component, Vacuum.ERROR_CH_ID, new StringType("")); + + component.getChannel(Vacuum.FAN_SPEED_CH_ID).getState().publishValue(new StringType("high")); + assertPublished("vacuum/set_fan_speed", "high"); + + component.getChannel(Vacuum.CUSTOM_COMMAND_CH_ID).getState().publishValue(new StringType("custom_command")); + assertPublished("vacuum/send_command", "custom_command"); + } + + protected Set getConfigTopics() { + return Set.of(CONFIG_TOPIC); + } +} From 510d41130128451b90ad053b4bb3546ddc42086d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Sat, 20 Nov 2021 18:48:03 +0100 Subject: [PATCH 120/361] [XMLTV] Preparing for Crowdin and code refining. (#11594) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Preparing for Crowdin and code refining. Signed-off-by: Gaël L'hopital * Satisfying SAT Signed-off-by: Gaël L'hopital * Preventing two potential NPE Signed-off-by: Gaël L'hopital * Code review comments taken in account Signed-off-by: clinique * Reverting description removal Signed-off-by: clinique * Forgot spotless apply Signed-off-by: clinique Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.xmltv/README.md | 2 +- .../xmltv/internal/XmlTVBindingConstants.java | 8 +- .../xmltv/internal/XmlTVHandlerFactory.java | 58 +++++-------- .../XmlChannelConfiguration.java | 9 +- .../configuration/XmlTVConfiguration.java | 9 +- .../discovery/XmlTVDiscoveryService.java | 50 +++++++---- .../internal/handler/ChannelHandler.java | 83 +++++++++---------- .../xmltv/internal/handler/XmlTVHandler.java | 30 ++++--- .../xmltv/internal/jaxb/ObjectFactory.java | 69 --------------- .../resources/OH-INF/i18n/xmltv.properties | 64 ++++++++++++++ 10 files changed, 191 insertions(+), 191 deletions(-) delete mode 100644 bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/jaxb/ObjectFactory.java create mode 100644 bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv.properties diff --git a/bundles/org.openhab.binding.xmltv/README.md b/bundles/org.openhab.binding.xmltv/README.md index b7e6d308a3ade..8c04268aed8d0 100644 --- a/bundles/org.openhab.binding.xmltv/README.md +++ b/bundles/org.openhab.binding.xmltv/README.md @@ -8,7 +8,7 @@ The building of the XMLTV file itself is taken in charge by so called "grabbers" Some websites provides updated XMLTV files than can be directly downloaded. -Here is a sample for France : https://www.xmltv.fr/ +Here is a sample for France and Switzerland : https://xmltv.ch/ This binding takes an XMLTV file as input and creates a thing for each channel contained in it. XmlTV channels are called Media Channels in this binding in order to avoid messing with openHAB Channels. diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVBindingConstants.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVBindingConstants.java index c9f60e8cfddea..ffe02e01be2be 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVBindingConstants.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVBindingConstants.java @@ -12,10 +12,7 @@ */ package org.openhab.binding.xmltv.internal; -import java.util.Collections; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; @@ -36,7 +33,6 @@ public class XmlTVBindingConstants { public static final ThingTypeUID XMLTV_CHANNEL_THING_TYPE = new ThingTypeUID(BINDING_ID, "channel"); // Channel groups - public static final String GROUP_CURRENT_PROGRAMME = "currentprog"; public static final String GROUP_NEXT_PROGRAMME = "nextprog"; public static final String GROUP_CHANNEL_PROPERTIES = "channelprops"; @@ -56,6 +52,6 @@ public class XmlTVBindingConstants { public static final String CHANNEL_PROGRAMME_TIMELEFT = "timeLeft"; // Supported Thing types - public static final Set SUPPORTED_THING_TYPES_UIDS = Collections - .unmodifiableSet(Stream.of(XMLTV_FILE_BRIDGE_TYPE, XMLTV_CHANNEL_THING_TYPE).collect(Collectors.toSet())); + public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(XMLTV_FILE_BRIDGE_TYPE, + XMLTV_CHANNEL_THING_TYPE); } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVHandlerFactory.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVHandlerFactory.java index d88bef01c9eae..e39f90879753c 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVHandlerFactory.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/XmlTVHandlerFactory.java @@ -14,19 +14,18 @@ import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.*; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - +import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.XMLInputFactory; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.xmltv.internal.discovery.XmlTVDiscoveryService; import org.openhab.binding.xmltv.internal.handler.ChannelHandler; import org.openhab.binding.xmltv.internal.handler.XmlTVHandler; +import org.openhab.binding.xmltv.internal.jaxb.Tv; import org.openhab.core.config.core.Configuration; -import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -34,10 +33,9 @@ import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.osgi.service.component.annotations.Reference; /** * The {@link XmlTVHandlerFactory} is responsible for creating things and thing @@ -48,8 +46,16 @@ @NonNullByDefault @Component(configurationPid = "binding.xmltv", service = ThingHandlerFactory.class) public class XmlTVHandlerFactory extends BaseThingHandlerFactory { - private final Logger logger = LoggerFactory.getLogger(XmlTVHandlerFactory.class); - private final Map> discoveryServiceRegs = new HashMap<>(); + private final XMLInputFactory xif = XMLInputFactory.newFactory(); + private final TimeZoneProvider timeZoneProvider; + private final Unmarshaller unmarshaller; + + @Activate + public XmlTVHandlerFactory(final @Reference TimeZoneProvider timeZoneProvider) throws JAXBException { + this.timeZoneProvider = timeZoneProvider; + this.unmarshaller = JAXBContext.newInstance(Tv.class).createUnmarshaller(); + xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); + } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -79,37 +85,11 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (XMLTV_FILE_BRIDGE_TYPE.equals(thingTypeUID)) { - try { - XmlTVHandler bridgeHandler = new XmlTVHandler((Bridge) thing); - registerDeviceDiscoveryService(bridgeHandler); - return bridgeHandler; - } catch (JAXBException e) { - logger.error("Unable to create XmlTVHandler : {}", e.getMessage()); - } + return new XmlTVHandler((Bridge) thing, xif, unmarshaller); } else if (XMLTV_CHANNEL_THING_TYPE.equals(thingTypeUID)) { - return new ChannelHandler(thing); + return new ChannelHandler(thing, timeZoneProvider.getTimeZone()); } return null; } - - @Override - protected void removeHandler(ThingHandler thingHandler) { - if (thingHandler instanceof XmlTVHandler) { - Thing thing = thingHandler.getThing(); - unregisterDeviceDiscoveryService(thing); - } - super.removeHandler(thingHandler); - } - - private synchronized void registerDeviceDiscoveryService(XmlTVHandler bridgeHandler) { - XmlTVDiscoveryService discoveryService = new XmlTVDiscoveryService(bridgeHandler); - discoveryServiceRegs.put(bridgeHandler.getThing().getUID(), - bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>())); - } - - private synchronized void unregisterDeviceDiscoveryService(Thing thing) { - ServiceRegistration serviceReg = discoveryServiceRegs.remove(thing.getUID()); - serviceReg.unregister(); - } } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlChannelConfiguration.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlChannelConfiguration.java index c22db5f0d334c..b58375dd8824f 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlChannelConfiguration.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlChannelConfiguration.java @@ -12,16 +12,19 @@ */ package org.openhab.binding.xmltv.internal.configuration; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link XmlChannelConfiguration} class contains fields mapping * Channel thing configuration parameters. * * @author Gaël L'hopital - Initial contribution */ +@NonNullByDefault public class XmlChannelConfiguration { public static final String CHANNEL_ID = "channelId"; - public String channelId; - public Integer offset; - public Integer refresh; + public String channelId = ""; + public int offset = 0; + public int refresh = 60; } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlTVConfiguration.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlTVConfiguration.java index 9c5a2da0c9c0e..249c0c230beef 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlTVConfiguration.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/configuration/XmlTVConfiguration.java @@ -12,14 +12,17 @@ */ package org.openhab.binding.xmltv.internal.configuration; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link XmlTVConfiguration} class contains fields mapping TV bridge * configuration parameters. * * @author Gaël L'hopital - Initial contribution */ +@NonNullByDefault public class XmlTVConfiguration { - public String filePath; - public Integer refresh; - public String encoding; + public String filePath = ""; + public int refresh = 24; + public String encoding = "UTF8"; } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/discovery/XmlTVDiscoveryService.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/discovery/XmlTVDiscoveryService.java index 194b85d1c001c..3a45e50665c52 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/discovery/XmlTVDiscoveryService.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/discovery/XmlTVDiscoveryService.java @@ -12,18 +12,21 @@ */ package org.openhab.binding.xmltv.internal.discovery; -import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.XMLTV_CHANNEL_THING_TYPE; +import static org.openhab.binding.xmltv.internal.XmlTVBindingConstants.*; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.xmltv.internal.XmlTVBindingConstants; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.xmltv.internal.configuration.XmlChannelConfiguration; import org.openhab.binding.xmltv.internal.handler.XmlTVHandler; -import org.openhab.binding.xmltv.internal.jaxb.Tv; import org.openhab.core.config.discovery.AbstractDiscoveryService; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,28 +36,33 @@ * * @author Gaël L'hopital - Initial contribution */ +@Component(service = ThingHandlerService.class) @NonNullByDefault -public class XmlTVDiscoveryService extends AbstractDiscoveryService { - private final Logger logger = LoggerFactory.getLogger(XmlTVDiscoveryService.class); - - private static final int SEARCH_TIME = 10; +public class XmlTVDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { + private static final int SEARCH_TIME = 5; - private XmlTVHandler bridgeHandler; + private final Logger logger = LoggerFactory.getLogger(XmlTVDiscoveryService.class); + private @Nullable XmlTVHandler handler; /** * Creates a XmlTVDiscoveryService with background discovery disabled. */ - public XmlTVDiscoveryService(XmlTVHandler bridgeHandler) { - super(XmlTVBindingConstants.SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME); - this.bridgeHandler = bridgeHandler; + @Activate + public XmlTVDiscoveryService() { + super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME); + } + + @Override + public void deactivate() { + super.deactivate(); } @Override protected void startScan() { logger.debug("Starting XmlTV discovery scan"); - if (bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) { - Tv tv = bridgeHandler.getXmlFile(); - if (tv != null) { + XmlTVHandler bridgeHandler = handler; + if (bridgeHandler != null && bridgeHandler.getThing().getStatus() == ThingStatus.ONLINE) { + bridgeHandler.getXmlFile().ifPresent(tv -> { tv.getMediaChannels().stream().forEach(channel -> { String channelId = channel.getId(); String uid = channelId.replaceAll("[^A-Za-z0-9_]", "_"); @@ -67,7 +75,19 @@ protected void startScan() { thingDiscovered(discoveryResult); }); - } + }); } } + + @Override + public void setThingHandler(ThingHandler handler) { + if (handler instanceof XmlTVHandler) { + this.handler = (XmlTVHandler) handler; + } + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return handler; + } } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/ChannelHandler.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/ChannelHandler.java index 53dfc6640b0c4..260ef19a8b4d5 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/ChannelHandler.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/ChannelHandler.java @@ -30,7 +30,6 @@ import org.openhab.binding.xmltv.internal.jaxb.Icon; import org.openhab.binding.xmltv.internal.jaxb.MediaChannel; import org.openhab.binding.xmltv.internal.jaxb.Programme; -import org.openhab.binding.xmltv.internal.jaxb.Tv; import org.openhab.binding.xmltv.internal.jaxb.WithLangType; import org.openhab.core.io.net.http.HttpUtil; import org.openhab.core.library.types.DateTimeType; @@ -61,14 +60,16 @@ public class ChannelHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(ChannelHandler.class); - private @NonNullByDefault({}) ScheduledFuture globalJob; + private @Nullable ScheduledFuture globalJob; private @Nullable MediaChannel mediaChannel; - private @Nullable RawType mediaIcon = new RawType(new byte[0], RawType.DEFAULT_MIME_TYPE); + private State mediaIcon = UnDefType.UNDEF; public final List programmes = new ArrayList<>(); + private final ZoneId zoneId; - public ChannelHandler(Thing thing) { + public ChannelHandler(Thing thing, ZoneId zoneId) { super(thing); + this.zoneId = zoneId; } @Override @@ -77,14 +78,14 @@ public void initialize() { logger.debug("Initializing Broadcast Channel handler for uid '{}'", getThing().getUID()); - if (globalJob == null || globalJob.isCancelled()) { + ScheduledFuture job = globalJob; + if (job == null || job.isCancelled()) { globalJob = scheduler.scheduleWithFixedDelay(() -> { if (programmes.size() < 2) { refreshProgramList(); } if (programmes.isEmpty()) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, - "No programmes to come in the current XML file for this channel"); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/no-more-programs"); } else if (Instant.now().isAfter(programmes.get(0).getProgrammeStop())) { programmes.remove(0); } @@ -100,8 +101,7 @@ private void refreshProgramList() { if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) { XmlTVHandler handler = (XmlTVHandler) bridge.getHandler(); if (handler != null) { - Tv tv = handler.getXmlFile(); - if (tv != null) { + handler.getXmlFile().ifPresentOrElse(tv -> { String channelId = (String) getConfig().get(XmlChannelConfiguration.CHANNEL_ID); if (mediaChannel == null) { @@ -119,9 +119,7 @@ private void refreshProgramList() { .forEach(p -> programmes.add(p)); updateStatus(ThingStatus.ONLINE); - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "No file available"); - } + }, () -> updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/no-file-available")); } else { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); } @@ -132,8 +130,9 @@ private void refreshProgramList() { @Override public void dispose() { - if (globalJob != null && !globalJob.isCancelled()) { - globalJob.cancel(true); + ScheduledFuture job = globalJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); globalJob = null; } } @@ -153,6 +152,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { * */ private void updateChannel(ChannelUID channelUID) { + // TODO : usage extraction of groupname String[] uidElements = channelUID.getId().split("#"); if (uidElements.length == 2) { int target = GROUP_NEXT_PROGRAMME.equals(uidElements[0]) ? 1 : 0; @@ -161,29 +161,22 @@ private void updateChannel(ChannelUID channelUID) { switch (uidElements[1]) { case CHANNEL_ICON: - State icon = null; - if (GROUP_CHANNEL_PROPERTIES.equals(uidElements[0])) { - icon = mediaIcon; - } else { - icon = downloadIcon(programme.getIcons()); - } - updateState(channelUID, icon != null ? icon : UnDefType.UNDEF); + State icon = GROUP_CHANNEL_PROPERTIES.equals(uidElements[0]) ? mediaIcon + : downloadIcon(programme.getIcons()); + updateState(channelUID, icon); break; case CHANNEL_CHANNEL_URL: + MediaChannel channel = mediaChannel; updateState(channelUID, - mediaChannel != null ? !mediaChannel.getIcons().isEmpty() - ? new StringType(mediaChannel.getIcons().get(0).getSrc()) + channel != null ? !channel.getIcons().isEmpty() + ? new StringType(channel.getIcons().get(0).getSrc()) : UnDefType.UNDEF : UnDefType.UNDEF); break; case CHANNEL_PROGRAMME_START: - Instant is = programme.getProgrammeStart(); - ZonedDateTime zds = ZonedDateTime.ofInstant(is, ZoneId.systemDefault()); - updateState(channelUID, new DateTimeType(zds)); + updateDateTimeChannel(channelUID, programme.getProgrammeStart()); break; case CHANNEL_PROGRAMME_END: - ZonedDateTime zde = ZonedDateTime.ofInstant(programme.getProgrammeStop(), - ZoneId.systemDefault()); - updateState(channelUID, new DateTimeType(zde)); + updateDateTimeChannel(channelUID, programme.getProgrammeStop()); break; case CHANNEL_PROGRAMME_TITLE: List titles = programme.getTitles(); @@ -212,18 +205,15 @@ private void updateChannel(ChannelUID channelUID) { updateState(channelUID, getDurationInSeconds(Instant.now(), programme.getProgrammeStart())); break; case CHANNEL_PROGRAMME_PROGRESS: - Duration totalLength = Duration.between(programme.getProgrammeStart(), - programme.getProgrammeStop()); - Duration elapsed1 = Duration.between(programme.getProgrammeStart(), Instant.now()); - - long secondsElapsed1 = elapsed1.toMillis() / 1000; - long secondsLength = totalLength.toMillis() / 1000; + long totalLength = Duration.between(programme.getProgrammeStart(), programme.getProgrammeStop()) + .toSeconds(); + long elapsed1 = Duration.between(programme.getProgrammeStart(), Instant.now()).toSeconds(); - double progress = 100.0 * secondsElapsed1 / secondsLength; + double progress = 100.0 * elapsed1 / totalLength; if (progress > 100 || progress < 0) { logger.debug("Outstanding process"); } - updateState(channelUID, new QuantityType<>(progress, Units.PERCENT)); + updateState(channelUID, new QuantityType<>((int) progress, Units.PERCENT)); break; } @@ -233,17 +223,24 @@ private void updateChannel(ChannelUID channelUID) { } } + private void updateDateTimeChannel(ChannelUID channelUID, Instant instant) { + ZonedDateTime zds = ZonedDateTime.ofInstant(instant, zoneId); + updateState(channelUID, new DateTimeType(zds)); + } + private QuantityType getDurationInSeconds(Instant from, Instant to) { - Duration elapsed = Duration.between(from, to); - long secondsElapsed = TimeUnit.MILLISECONDS.toSeconds(elapsed.toMillis()); - return new QuantityType<>(secondsElapsed, Units.SECOND); + long elapsed = Duration.between(from, to).toSeconds(); + return new QuantityType<>(elapsed, Units.SECOND); } - private @Nullable RawType downloadIcon(List icons) { + private State downloadIcon(List icons) { if (!icons.isEmpty()) { String url = icons.get(0).getSrc(); - return HttpUtil.downloadImage(url); + RawType result = HttpUtil.downloadImage(url); + if (result != null) { + return result; + } } - return null; + return UnDefType.NULL; } } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/XmlTVHandler.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/XmlTVHandler.java index 85e7969462259..542994e244fe7 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/XmlTVHandler.java +++ b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/handler/XmlTVHandler.java @@ -16,12 +16,14 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.time.Instant; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; @@ -31,6 +33,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.xmltv.internal.configuration.XmlTVConfiguration; +import org.openhab.binding.xmltv.internal.discovery.XmlTVDiscoveryService; import org.openhab.binding.xmltv.internal.jaxb.Programme; import org.openhab.binding.xmltv.internal.jaxb.Tv; import org.openhab.core.thing.Bridge; @@ -38,6 +41,7 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,16 +55,16 @@ @NonNullByDefault public class XmlTVHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(XmlTVHandler.class); - private final XMLInputFactory xif = XMLInputFactory.newFactory(); - private final JAXBContext jc; + private final XMLInputFactory xif; + private final Unmarshaller unmarshaller; private @Nullable Tv currentXmlFile; private @NonNullByDefault({}) ScheduledFuture reloadJob; - public XmlTVHandler(Bridge thing) throws JAXBException { + public XmlTVHandler(Bridge thing, XMLInputFactory xif, Unmarshaller unmarshaller) { super(thing); - xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); - jc = JAXBContext.newInstance(Tv.class); + this.xif = xif; + this.unmarshaller = unmarshaller; } @Override @@ -74,9 +78,7 @@ public void initialize() { try { // This can take some seconds depending upon weight of the XmlTV source file xsr = xif.createXMLStreamReader(new FileInputStream(new File(config.filePath)), config.encoding); - try { - Unmarshaller unmarshaller = jc.createUnmarshaller(); Tv xmlFile = (Tv) unmarshaller.unmarshal(xsr); // Remove all finished programmes xmlFile.getProgrammes().removeIf(programme -> Instant.now().isAfter(programme.getProgrammeStop())); @@ -88,7 +90,7 @@ public void initialize() { currentXmlFile = xmlFile; updateStatus(ThingStatus.ONLINE); } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.DISABLED, "XMLTV file seems outdated"); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.DISABLED, "@text/file-outdated"); } xsr.close(); } catch (JAXBException e) { @@ -122,8 +124,12 @@ public void handleCommand(ChannelUID channelUID, Command command) { // nothing to do } - @Nullable - public Tv getXmlFile() { - return currentXmlFile; + public Optional getXmlFile() { + return Optional.ofNullable(currentXmlFile); + } + + @Override + public Collection> getServices() { + return Set.of(XmlTVDiscoveryService.class); } } diff --git a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/jaxb/ObjectFactory.java b/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/jaxb/ObjectFactory.java deleted file mode 100644 index 3fb6f97f5dff9..0000000000000 --- a/bundles/org.openhab.binding.xmltv/src/main/java/org/openhab/binding/xmltv/internal/jaxb/ObjectFactory.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2010-2021 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.xmltv.internal.jaxb; - -import javax.xml.bind.annotation.XmlRegistry; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * This object contains factory methods for each Java content - * interface and Java element interface generated in the - * org.openhab.binding.xmltv.internal.jaxb package. - * - * @author Gaël L'hopital - Initial contribution - */ -@XmlRegistry -@NonNullByDefault -public class ObjectFactory { - - /** - * Create an instance of {@link Tv } - * - */ - public Tv createTv() { - return new Tv(); - } - - /** - * Create an instance of {@link Programme } - * - */ - public Programme createProgramme() { - return new Programme(); - } - - /** - * Create an instance of {@link MediaChannel } - * - */ - public MediaChannel createChannel() { - return new MediaChannel(); - } - - /** - * Create an instance of {@link Icon } - * - */ - public Icon createIcon() { - return new Icon(); - } - - /** - * Create an instance of {@link WithLangType } - * - */ - public WithLangType createWithLangType() { - return new WithLangType(); - } -} diff --git a/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv.properties b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv.properties new file mode 100644 index 0000000000000..9b5f21afd24b8 --- /dev/null +++ b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv.properties @@ -0,0 +1,64 @@ +# binding + +binding.xmltv.name = XmlTV Binding +binding.xmltv.description = This is the binding for reading and parsing XmlTV files + +# bridge types + +thing-type.xmltv.xmltvfile.label = XmlTVFile +thing-type.xmltv.xmltvfile.description = This is the interface to a XmlTV file + +thing-type.config.xmltv.xmltvfile.filePath.label = XmlTV File Path +thing-type.config.xmltv.xmltvfile.filePath.description = Path to an XmlTV file. +thing-type.config.xmltv.xmltvfile.refresh.label = Refresh Interval +thing-type.config.xmltv.xmltvfile.refresh.description = Specifies the XMLTV file reload interval in hours. +thing-type.config.xmltv.xmltvfile.encoding.label = File encoding +thing-type.config.xmltv.xmltvfile.encoding.description = Specifies the XMLTV file encoding. + +# thing types + +thing-type.xmltv.channel.label = Channel +thing-type.xmltv.channel.description = This represent a channel on a given TV file + +thing-type.config.xmltv.channel.channelId.label = Channel Id +thing-type.config.xmltv.channel.channelId.description = Id of the channel as presented in the XmlTV file. +thing-type.config.xmltv.channel.offset.label = Offset +thing-type.config.xmltv.channel.offset.description = Moves an event or datetime value forward or backward (in minutes) +thing-type.config.xmltv.channel.refresh.label = Refresh Interval +thing-type.config.xmltv.channel.refresh.description = Specifies the refresh interval in seconds. + +# channel group types + +channel-group-type.xmltv.channelprops.label = Channel Properties +channel-group-type.xmltv.currentprog.label = Current Program +channel-group-type.xmltv.nextprog.label = Next Program + +# channel type + +channel-type.xmltv.iconUrl.label = Channel Icon URL +channel-type.xmltv.iconUrl.description = Icon URL of the TV channel. +channel-type.xmltv.progIconUrl.label = Program URL +channel-type.xmltv.progIconUrl.description = URL to an image of the program. +channel-type.xmltv.progTitle.label = Title +channel-type.xmltv.progTitle.description = Program Title. +channel-type.xmltv.progCategory.label = Category +channel-type.xmltv.progCategory.description = Program Category. +channel-type.xmltv.progStart.label = Start Time +channel-type.xmltv.progStart.description = Program Start Time +channel-type.xmltv.progEnd.label = End Time +channel-type.xmltv.progEnd.description = Program End Time +channel-type.xmltv.elapsedTime.label = Current Time +channel-type.xmltv.elapsedTime.description = Current time of currently playing program. +channel-type.xmltv.remainingTime.label = Remaining Time +channel-type.xmltv.remainingTime.description = Time remaining until end of the program. +channel-type.xmltv.timeLeft.label = Time Left +channel-type.xmltv.timeLeft.description = Time left before program start +channel-type.xmltv.progress.label = Progress +channel-type.xmltv.progress.description = Relative progression of the current program. +channel-type.xmltv.icon.label = Icon +channel-type.xmltv.icon.description = Icon of the channel / program. + +# messages +no-more-programs = No programmes to come in the current XML file for this channel +no-file-available = No file available +file-outdated = XMLTV file seems outdated From f91741613dac7e3019c0c9bb7f25ed40f1e6a5fb Mon Sep 17 00:00:00 2001 From: Luca Calcaterra Date: Sat, 20 Nov 2021 20:18:29 +0100 Subject: [PATCH 121/361] Update thing-types.xml (#11614) fix T14 typical - must be switch instead of trigger Signed-off-by: Luca Calcaterra Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/thing/thing-types.xml index 66a4e92bd261f..7b2abab9873f9 100644 --- a/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/thing/thing-types.xml @@ -1057,7 +1057,7 @@ - trigger + Switch Set Switch From cb603304f1b2a10274d92c90006df97dab3a3106 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 21 Nov 2021 10:22:28 +0100 Subject: [PATCH 122/361] Update Jackson version to 2.12.5 (#11609) This is the version used in the feature provided by openhab-core. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a25687bcdb1fb..5f326096b049c 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 6.0.0 3.7.2 2.2.1 - 2.12.3 + 2.12.5 4.3.3 4.1.68.Final 3.14.9 From 2e4807b81e4b69734c1858a87267ff5c11274a64 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 21 Nov 2021 12:40:56 +0100 Subject: [PATCH 123/361] Resolve runbundles for UoM dependency upgrades (#11610) Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- itests/org.openhab.binding.astro.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.avmfritz.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.feed.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.hue.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.max.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.mielecloud.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.modbus.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.nest.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.ntp.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.systeminfo.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.tradfri.tests/itest.bndrun | 6 +++--- itests/org.openhab.binding.wemo.tests/itest.bndrun | 6 +++--- itests/org.openhab.persistence.mapdb.tests/itest.bndrun | 6 +++--- 13 files changed, 39 insertions(+), 39 deletions(-) diff --git a/itests/org.openhab.binding.astro.tests/itest.bndrun b/itests/org.openhab.binding.astro.tests/itest.bndrun index ecb7fd9df09dc..e265ddfc99a9e 100644 --- a/itests/org.openhab.binding.astro.tests/itest.bndrun +++ b/itests/org.openhab.binding.astro.tests/itest.bndrun @@ -35,8 +35,6 @@ Fragment-Host: org.openhab.binding.astro org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -50,4 +48,6 @@ Fragment-Host: org.openhab.binding.astro org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun index 23bf948a88b55..bb71acf13d6b3 100644 --- a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun +++ b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun @@ -44,8 +44,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -75,4 +73,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.feed.tests/itest.bndrun b/itests/org.openhab.binding.feed.tests/itest.bndrun index 9378160408139..91b4b727a2ed3 100644 --- a/itests/org.openhab.binding.feed.tests/itest.bndrun +++ b/itests/org.openhab.binding.feed.tests/itest.bndrun @@ -43,8 +43,6 @@ Fragment-Host: org.openhab.binding.feed javax.measure.unit-api;version='[2.1.2,2.1.3)',\ org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -75,4 +73,6 @@ Fragment-Host: org.openhab.binding.feed org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.hue.tests/itest.bndrun b/itests/org.openhab.binding.hue.tests/itest.bndrun index f9a5396568b13..130bd397a5155 100644 --- a/itests/org.openhab.binding.hue.tests/itest.bndrun +++ b/itests/org.openhab.binding.hue.tests/itest.bndrun @@ -44,8 +44,6 @@ Fragment-Host: org.openhab.binding.hue org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -79,4 +77,6 @@ Fragment-Host: org.openhab.binding.hue org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.max.tests/itest.bndrun b/itests/org.openhab.binding.max.tests/itest.bndrun index 850570bdbf968..7c20ee86c83b8 100644 --- a/itests/org.openhab.binding.max.tests/itest.bndrun +++ b/itests/org.openhab.binding.max.tests/itest.bndrun @@ -40,8 +40,6 @@ Fragment-Host: org.openhab.binding.max org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -66,4 +64,6 @@ Fragment-Host: org.openhab.binding.max org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun index 47773da6de74d..83585371147c2 100644 --- a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun +++ b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun @@ -49,8 +49,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ xstream;version='[1.4.18,1.4.19)',\ @@ -85,4 +83,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.modbus.tests/itest.bndrun b/itests/org.openhab.binding.modbus.tests/itest.bndrun index c97da2062aaa8..1743c9d196411 100644 --- a/itests/org.openhab.binding.modbus.tests/itest.bndrun +++ b/itests/org.openhab.binding.modbus.tests/itest.bndrun @@ -47,8 +47,6 @@ Fragment-Host: org.openhab.binding.modbus org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -75,4 +73,6 @@ Fragment-Host: org.openhab.binding.modbus org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.nest.tests/itest.bndrun b/itests/org.openhab.binding.nest.tests/itest.bndrun index 2285316f4648f..747d200d2855d 100644 --- a/itests/org.openhab.binding.nest.tests/itest.bndrun +++ b/itests/org.openhab.binding.nest.tests/itest.bndrun @@ -58,8 +58,6 @@ Fragment-Host: org.openhab.binding.nest javax.measure.unit-api;version='[2.1.2,2.1.3)',\ org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -104,4 +102,6 @@ Fragment-Host: org.openhab.binding.nest org.apache.cxf.cxf-rt-rs-client;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-rs-sse;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-security;version='[3.4.5,3.4.6)',\ - org.apache.cxf.cxf-rt-transports-http;version='[3.4.5,3.4.6)' + org.apache.cxf.cxf-rt-transports-http;version='[3.4.5,3.4.6)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.ntp.tests/itest.bndrun b/itests/org.openhab.binding.ntp.tests/itest.bndrun index b83fea44b3855..5f8338cbc24f1 100644 --- a/itests/org.openhab.binding.ntp.tests/itest.bndrun +++ b/itests/org.openhab.binding.ntp.tests/itest.bndrun @@ -44,8 +44,6 @@ Fragment-Host: org.openhab.binding.ntp org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -70,4 +68,6 @@ Fragment-Host: org.openhab.binding.ntp org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index 9f636c59fdd24..fef7f3d9e1e04 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -45,8 +45,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -73,4 +71,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ com.sun.jna;version='[5.9.0,5.9.1)',\ com.sun.jna.platform;version='[5.9.0,5.9.1)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.tradfri.tests/itest.bndrun b/itests/org.openhab.binding.tradfri.tests/itest.bndrun index 866ac19bc6a30..62b4b0d96888d 100644 --- a/itests/org.openhab.binding.tradfri.tests/itest.bndrun +++ b/itests/org.openhab.binding.tradfri.tests/itest.bndrun @@ -48,8 +48,6 @@ Fragment-Host: org.openhab.binding.tradfri org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -76,4 +74,6 @@ Fragment-Host: org.openhab.binding.tradfri org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.binding.wemo.tests/itest.bndrun b/itests/org.openhab.binding.wemo.tests/itest.bndrun index 0e5f8e0e7a143..7e73d49e08b4e 100644 --- a/itests/org.openhab.binding.wemo.tests/itest.bndrun +++ b/itests/org.openhab.binding.wemo.tests/itest.bndrun @@ -47,8 +47,6 @@ Fragment-Host: org.openhab.binding.wemo org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.osgi.service.cm;version='[1.6.0,1.6.1)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.apache.felix.configadmin;version='[1.9.22,1.9.23)',\ @@ -83,4 +81,6 @@ Fragment-Host: org.openhab.binding.wemo org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' diff --git a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun index 2740fe5e9a2ef..1e54765adc071 100644 --- a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun +++ b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun @@ -38,8 +38,6 @@ Fragment-Host: org.openhab.persistence.mapdb javax.measure.unit-api;version='[2.1.2,2.1.3)',\ org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ - si-units;version='[2.0.1,2.0.2)',\ - si.uom.si-quantity;version='[2.0.1,2.0.2)',\ tech.units.indriya;version='[2.1.2,2.1.3)',\ uom-lib-common;version='[2.1.0,2.1.1)',\ org.openhab.core;version='[3.2.0,3.2.1)',\ @@ -57,4 +55,6 @@ Fragment-Host: org.openhab.persistence.mapdb org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)' + biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ + si-units;version='[2.1.0,2.1.1)',\ + si.uom.si-quantity;version='[2.1.0,2.1.1)' From 94e1eaa77437c9e2a508a18f06297a8877f49a86 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sun, 21 Nov 2021 15:54:43 +0100 Subject: [PATCH 124/361] [tr064] Added default i18n properties file (#11619) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../internal/phonebook/PhonebookActions.java | 25 +++--- .../OH-INF/config/phonebookProfile.xml | 6 +- .../resources/OH-INF/i18n/tr064.properties | 77 ++++++++++++++++++- .../resources/OH-INF/thing/thing-types.xml | 12 +-- 4 files changed, 92 insertions(+), 28 deletions(-) diff --git a/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/PhonebookActions.java b/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/PhonebookActions.java index 74493647cbd21..93518ac98ac8b 100644 --- a/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/PhonebookActions.java +++ b/bundles/org.openhab.binding.tr064/src/main/java/org/openhab/binding/tr064/internal/phonebook/PhonebookActions.java @@ -34,37 +34,36 @@ */ @ThingActionsScope(name = "tr064") @NonNullByDefault -@SuppressWarnings("unused") public class PhonebookActions implements ThingActions { private final Logger logger = LoggerFactory.getLogger(PhonebookActions.class); private @Nullable Tr064RootHandler handler; @RuleAction(label = "@text/phonebookLookupActionLabel", description = "@text/phonebookLookupActionDescription") - public @ActionOutput(name = "name", type = "java.lang.String") String phonebookLookup( - @ActionInput(name = "phonenumber") @Nullable String phonenumber, - @ActionInput(name = "matches") @Nullable Integer matchCount) { + public @ActionOutput(name = "name", label = "@text/phonebookLookupActionOutputLabel", description = "@text/phonebookLookupActionOutputDescription", type = "java.lang.String") String phonebookLookup( + @ActionInput(name = "phonenumber", label = "@text/phonebookLookupActionInputPhoneNumberLabel", description = "@text/phonebookLookupActionInputPhoneNumberDescription", type = "java.lang.String", required = true) @Nullable String phonenumber, + @ActionInput(name = "matches", label = "@text/phonebookLookupActionInputMatchesLabel", description = "@text/phonebookLookupActionInputMatchesDescription", type = "java.lang.Integer") @Nullable Integer matchCount) { return phonebookLookup(phonenumber, null, matchCount); } @RuleAction(label = "@text/phonebookLookupActionLabel", description = "@text/phonebookLookupActionDescription") - public @ActionOutput(name = "name", type = "java.lang.String") String phonebookLookup( - @ActionInput(name = "phonenumber") @Nullable String phonenumber) { + public @ActionOutput(name = "name", label = "@text/phonebookLookupActionOutputLabel", description = "@text/phonebookLookupActionOutputDescription", type = "java.lang.String") String phonebookLookup( + @ActionInput(name = "phonenumber", label = "@text/phonebookLookupActionInputPhoneNumberLabel", description = "@text/phonebookLookupActionInputPhoneNumberDescription", type = "java.lang.String", required = true) @Nullable String phonenumber) { return phonebookLookup(phonenumber, null, null); } @RuleAction(label = "@text/phonebookLookupActionLabel", description = "@text/phonebookLookupActionDescription") - public @ActionOutput(name = "name", type = "java.lang.String") String phonebookLookup( - @ActionInput(name = "phonenumber") @Nullable String phonenumber, - @ActionInput(name = "phonebook") @Nullable String phonebook) { + public @ActionOutput(name = "name", label = "@text/phonebookLookupActionOutputLabel", description = "@text/phonebookLookupActionOutputDescription", type = "java.lang.String") String phonebookLookup( + @ActionInput(name = "phonenumber", label = "@text/phonebookLookupActionInputPhoneNumberLabel", description = "@text/phonebookLookupActionInputPhoneNumberDescription", type = "java.lang.String", required = true) @Nullable String phonenumber, + @ActionInput(name = "phonebook", label = "@text/phonebookLookupActionInputPhoneBookLabel", description = "@text/phonebookLookupActionInputPhoneBookDescription", type = "java.lang.String") @Nullable String phonebook) { return phonebookLookup(phonenumber, phonebook, null); } @RuleAction(label = "@text/phonebookLookupActionLabel", description = "@text/phonebookLookupActionDescription") - public @ActionOutput(name = "name", type = "java.lang.String") String phonebookLookup( - @ActionInput(name = "phonenumber") @Nullable String phonenumber, - @ActionInput(name = "phonebook") @Nullable String phonebook, - @ActionInput(name = "matches") @Nullable Integer matchCount) { + public @ActionOutput(name = "name", label = "@text/phonebookLookupActionOutputLabel", description = "@text/phonebookLookupActionOutputDescription", type = "java.lang.String") String phonebookLookup( + @ActionInput(name = "phonenumber", label = "@text/phonebookLookupActionInputPhoneNumberLabel", description = "@text/phonebookLookupActionInputPhoneNumberDescription", type = "java.lang.String", required = true) @Nullable String phonenumber, + @ActionInput(name = "phonebook", label = "@text/phonebookLookupActionInputPhoneBookLabel", description = "@text/phonebookLookupActionInputPhoneBookDescription", type = "java.lang.String") @Nullable String phonebook, + @ActionInput(name = "matches", label = "@text/phonebookLookupActionInputMatchesLabel", description = "@text/phonebookLookupActionInputMatchesDescription", type = "java.lang.Integer") @Nullable Integer matchCount) { if (phonenumber == null) { logger.warn("Cannot lookup a missing number."); return ""; diff --git a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/config/phonebookProfile.xml b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/config/phonebookProfile.xml index 462e36cf96273..32de7b2667ecd 100644 --- a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/config/phonebookProfile.xml +++ b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/config/phonebookProfile.xml @@ -6,8 +6,8 @@ - - The name of the the phone book + + The name of the the phone book. @@ -17,7 +17,7 @@ The index of the phone number to be resolved from a CallItem state (StringListType), 0 or 1 (default is - 0) + 0). 0 diff --git a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064.properties b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064.properties index 884c9e5d725ce..ed7d11ae13ce8 100644 --- a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064.properties +++ b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064.properties @@ -1,11 +1,80 @@ -profile-type.transform.PHONEBOOK.label = Phonebook -profile.config.transform.PHONEBOOK.phonebook.label = Phonebook -profile.config.transform.PHONEBOOK.phonebook.description = The phonebook name. +# binding + +binding.tr064.name = TR-064 Binding +binding.tr064.description = This is the binding for TR-064 device support. + +# thing types + +thing-type.tr064.fritzbox.label = FRITZ!Box +thing-type.tr064.fritzbox.description = A physical FRITZ!Box device. +thing-type.tr064.generic.label = Generic CPE +thing-type.tr064.subdevice.label = Sub-Device +thing-type.tr064.subdevice.description = A virtual sub-device. +thing-type.tr064.subdeviceLan.label = Sub-Device (LAN) +thing-type.tr064.subdeviceLan.description = A virtual Sub-Device (LAN). + +# thing types config + +thing-type.config.tr064.fritzbox.callDeflectionIndices.label = Call Deflection +thing-type.config.tr064.fritzbox.callDeflectionIndices.description = List of call deflection IDs (starting with 0). +thing-type.config.tr064.fritzbox.callListDays.label = Call List Days +thing-type.config.tr064.fritzbox.callListDays.description = List of days for which JSON call list should be generated. +thing-type.config.tr064.fritzbox.host.label = Host +thing-type.config.tr064.fritzbox.host.description = Host name or IP address. +thing-type.config.tr064.fritzbox.inboundCallDays.label = Inbound Call Days +thing-type.config.tr064.fritzbox.inboundCallDays.description = List of days for which inbound calls should be calculated. +thing-type.config.tr064.fritzbox.missedCallDays.label = Missed Call Days +thing-type.config.tr064.fritzbox.missedCallDays.description = List of days for which missed calls should be calculated. +thing-type.config.tr064.fritzbox.outboundCallDays.label = Outbound Call Days +thing-type.config.tr064.fritzbox.outboundCallDays.description = List of days for which outbound calls should be calculated. +thing-type.config.tr064.fritzbox.password.label = Password +thing-type.config.tr064.fritzbox.phonebookInterval.label = Phone Book Interval +thing-type.config.tr064.fritzbox.phonebookInterval.description = The interval for refreshing the phone book (disabled = 0). +thing-type.config.tr064.fritzbox.refresh.label = Refresh Interval +thing-type.config.tr064.fritzbox.rejectedCallDays.label = Rejected Call Days +thing-type.config.tr064.fritzbox.rejectedCallDays.description = List of days for which rejected calls should be calculated. +thing-type.config.tr064.fritzbox.tamIndices.label = TAM +thing-type.config.tr064.fritzbox.tamIndices.description = List of answering machines (starting with 0). +thing-type.config.tr064.fritzbox.timeout.label = Timeout +thing-type.config.tr064.fritzbox.timeout.description = Timeout for all requests (SOAP requests, phone book retrieval, call lists, ...). +thing-type.config.tr064.fritzbox.user.label = Username +thing-type.config.tr064.fritzbox.wanBlockIPs.label = WAN Block IPs +thing-type.config.tr064.fritzbox.wanBlockIPs.description = List of IPs that can be blocked for WAN access. +thing-type.config.tr064.generic.host.label = Host +thing-type.config.tr064.generic.host.description = Host name or IP address. +thing-type.config.tr064.generic.password.label = Password +thing-type.config.tr064.generic.refresh.label = Refresh Interval +thing-type.config.tr064.generic.timeout.label = Timeout +thing-type.config.tr064.generic.timeout.description = Timeout for all requests (SOAP requests, phone book retrieval, call lists, ...). +thing-type.config.tr064.generic.user.label = Username +thing-type.config.tr064.subdevice.refresh.label = Refresh Interval +thing-type.config.tr064.subdevice.uuid.label = UUID +thing-type.config.tr064.subdevice.uuid.description = UUID of the sub-device +thing-type.config.tr064.subdeviceLan.macOnline.label = MAC Online +thing-type.config.tr064.subdeviceLan.macOnline.description = List of MACs for "online" status detection (format: 11:11:11:11:11:11). +thing-type.config.tr064.subdeviceLan.refresh.label = Refresh Interval +thing-type.config.tr064.subdeviceLan.uuid.label = UUID +thing-type.config.tr064.subdeviceLan.uuid.description = UUID of the sub-device + +# thing types config + +profile-type.transform.PHONEBOOK.label = Phone Book +profile.config.transform.PHONEBOOK.phonebook.label = Phone Book +profile.config.transform.PHONEBOOK.phonebook.description = The phone book name. profile.config.transform.PHONEBOOK.matchCount.label = Match Count profile.config.transform.PHONEBOOK.matchCount.description = The number of matching numbers required for matches. Matching is done from the far end of numbers. The default value is 0, which is considered as "match everything". profile.config.transform.PHONEBOOK.phoneNumberIndex.label = Phone Number Index profile.config.transform.PHONEBOOK.phoneNumberIndex.description = The index of the phone number that is resolved from a CallItem-State (StringListType), 0 (default) or 1. # actions -phonebookLookupActionLabel = lookup a phonenumber + +phonebookLookupActionLabel = lookup a phone number phonebookLookupActionDescription = Lookup a phone number. +phonebookLookupActionOutputLabel = Name +phonebookLookupActionOutputDescription = The name associated with the phone number (or the phone number if no match can be found). +phonebookLookupActionInputPhoneNumberLabel = Phone Number +phonebookLookupActionInputPhoneNumberDescription = The phone number to be resolved. +phonebookLookupActionInputPhoneBookLabel = Phone Book +phonebookLookupActionInputPhoneBookDescription = The name of the the phone book. +phonebookLookupActionInputMatchesLabel = Match Count +phonebookLookupActionInputMatchesDescription = The number of digits matching the incoming value, counted from far right (default is 0 = all matching). Negative numbers skip digits from the left. diff --git a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/thing/thing-types.xml index fd911ddd8eef5..04ad07f9c88d7 100644 --- a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/thing/thing-types.xml @@ -26,14 +26,13 @@ 60 - s - - A physical FritzBox Device. + + A physical FRITZ!Box device. host @@ -54,7 +53,6 @@ 60 - s @@ -97,8 +95,8 @@ true - - The interval for refreshing the phonebook (disabled = 0) + + The interval for refreshing the phone book (disabled = 0). 600 true @@ -123,7 +121,6 @@ 60 - s @@ -146,7 +143,6 @@ 60 - s From 22638bcf40028c3456a4237b6eebc9b657df555a Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sun, 21 Nov 2021 15:56:13 +0100 Subject: [PATCH 125/361] [feed] Change patter for DateTime channel types to be considered by i18n-tool (#11618) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/i18n/feed.properties | 2 ++ .../src/main/resources/OH-INF/thing/thing-types.xml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed.properties b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed.properties index a2fcf337ea49c..b8cfef11b448a 100644 --- a/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed.properties +++ b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed.properties @@ -23,8 +23,10 @@ channel-type.feed.description.label = Description channel-type.feed.description.description = Description of the feed. channel-type.feed.last-update.label = Last Update channel-type.feed.last-update.description = The last update date of the feed. +channel-type.feed.last-update.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS channel-type.feed.latest-date.label = Latest Published Date channel-type.feed.latest-date.description = Contains the published date of the last feed entry. +channel-type.feed.latest-date.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS channel-type.feed.latest-description.label = Latest Description channel-type.feed.latest-description.description = Contains the description of the last feed entry. channel-type.feed.latest-enclosure.label = Latest Enclosure diff --git a/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/thing/thing-types.xml index 017295641e39e..188872273b172 100644 --- a/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/thing/thing-types.xml @@ -62,7 +62,7 @@ DateTime Contains the published date of the last feed entry. - + @@ -104,7 +104,7 @@ DateTime The last update date of the feed. - + From 1b0bdea0ac9e1686c5ba842f5344025bd8d476f6 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 21 Nov 2021 17:51:43 +0100 Subject: [PATCH 126/361] [googletts] Fix place holders issue (#11623) When the docs are generated any {{ }} constructs are substituted with variables causing the place holders to get lost. As a result the docs are less easy to understand. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- bundles/org.openhab.voice.googletts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.voice.googletts/README.md b/bundles/org.openhab.voice.googletts/README.md index e9c8887f7246d..88fc55b2b82d6 100644 --- a/bundles/org.openhab.voice.googletts/README.md +++ b/bundles/org.openhab.voice.googletts/README.md @@ -38,7 +38,7 @@ Using your favorite configuration UI to edit **Settings / Other Services - Googl * **Client Secret** - Google Cloud Platform OAuth 2.0-Client Secret. * **Authorization Code** - The auth-code is a one-time code needed to retrieve the necessary access-codes from Google Cloud Platform. **Please go to your browser ...** -[https://accounts.google.com/o/oauth2/auth?client_id={{clientId}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/cloud-platform&response_type=code](https://accounts.google.com/o/oauth2/auth?client_id={{clientId}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/cloud-platform&response_type=code) (replace `{{clientId}}` by your Client Id) +[https://accounts.google.com/o/oauth2/auth?client_id=&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/cloud-platform&response_type=code](https://accounts.google.com/o/oauth2/auth?client_id=&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/cloud-platform&response_type=code) (replace `` by your Client Id) **... to generate an auth-code and paste it here**. After initial authorization, this code is not needed anymore. It is recommended to clear this configuration parameter afterwards. From 24779bfe127a021dc5f8a9db35749a5ca0850f23 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 21 Nov 2021 17:52:32 +0100 Subject: [PATCH 127/361] [nest] Fix place holders issue (#11622) When the docs are generated any {{ }} constructs are substituted with variables. As a result the docs are less easy to understand. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.nest/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.nest/README.md b/bundles/org.openhab.binding.nest/README.md index b2857d32fda4a..ea6b549b6ae9a 100644 --- a/bundles/org.openhab.binding.nest/README.md +++ b/bundles/org.openhab.binding.nest/README.md @@ -88,7 +88,7 @@ Finally, an SDM Account Thing can be created to access the SDM project using the 1. Create an authorization code for the binding: 1. Replace the **Project ID** and **Client ID** in the URL below with your SDM Project ID and SDM OAuth 2.0 Client ID and open the URL in a new browser tab: - `https://nestservices.google.com/partnerconnections/{{ProjectID}}/auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&prompt=consent&client_id={{ClientID}}&response_type=code&scope=https://www.googleapis.com/auth/sdm.service` + `https://nestservices.google.com/partnerconnections//auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&prompt=consent&client_id=&response_type=code&scope=https://www.googleapis.com/auth/sdm.service` For the example values used so far this is: @@ -151,7 +151,7 @@ Finally, the existing SDM Account Thing can be updated so it can subscribe to SD 1. Create an authorization code for the binding: 1. Replace the **Client ID** in the URL below with your Pub/Sub OAuth 2.0 Client ID and open the URL in a new browser tab: - `https://accounts.google.com/o/oauth2/auth?client_id={{ClientID}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/pubsub` + `https://accounts.google.com/o/oauth2/auth?client_id=&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/pubsub` For the example client this is: From a65dc3defc48eabf56fe2ef9fe9da6480ac45f0e Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 21 Nov 2021 21:28:40 +0100 Subject: [PATCH 128/361] [max] Added default translation properties file (#11626) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/i18n/max.properties | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max.properties diff --git a/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max.properties b/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max.properties new file mode 100644 index 0000000000000..4c1f02f10ea9d --- /dev/null +++ b/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max.properties @@ -0,0 +1,199 @@ +# binding + +binding.max.name = MAX! Binding +binding.max.description = This is the binding for the eQ-3 MAX! Home Solution. + +# thing types + +thing-type.max.bridge.label = MAX! Cube LAN Gateway +thing-type.max.bridge.description = This bridge represents the MAX! Cube LAN Gateway. +thing-type.max.ecoswitch.label = MAX! Ecoswitch +thing-type.max.ecoswitch.description = This is a MAX! EcoSwitch +thing-type.max.shuttercontact.label = MAX! Shutter Contact +thing-type.max.shuttercontact.description = This is a MAX! Shutter Contact +thing-type.max.thermostat.label = MAX! HeatingThermostat +thing-type.max.thermostat.description = This is a MAX! HeatingThermostat +thing-type.max.thermostatplus.label = MAX! HeatingThermostat+ +thing-type.max.thermostatplus.description = This is a MAX! HeatingThermostat+ +thing-type.max.wallthermostat.label = MAX! WallThermostat+ +thing-type.max.wallthermostat.description = This is a MAX! WallThermostat+ + +# thing types config + +thing-type.config.max.bridge.action-cubeReboot.label = Restart Cube +thing-type.config.max.bridge.action-cubeReboot.description = Restarts the Cube. +thing-type.config.max.bridge.action-cubeReboot.option.1234 = Reboot +thing-type.config.max.bridge.action-cubeReboot.option.-1 = No Action +thing-type.config.max.bridge.action-cubeReset.label = Reset Cube Configuration +thing-type.config.max.bridge.action-cubeReset.description = Resets the MAX! Cube room and device information. Devices will need to be included again! +thing-type.config.max.bridge.action-cubeReset.option.1234 = Reset +thing-type.config.max.bridge.action-cubeReset.option.-1 = No Action +thing-type.config.max.bridge.exclusive.label = Exclusive Mode +thing-type.config.max.bridge.exclusive.description = If set to true, the binding will leave the connection to the Cube open. +thing-type.config.max.bridge.group.actions.label = Actions +thing-type.config.max.bridge.group.actions.description = Action Buttons +thing-type.config.max.bridge.group.device.label = Device Settings +thing-type.config.max.bridge.group.device.description = Device parameter settings +thing-type.config.max.bridge.group.identification.label = Identification +thing-type.config.max.bridge.group.identification.description = Hardware & location identification +thing-type.config.max.bridge.group.network.label = Connection +thing-type.config.max.bridge.group.network.description = Connection Settings +thing-type.config.max.bridge.ipAddress.label = MAX! Cube LAN Gateway IP +thing-type.config.max.bridge.ipAddress.description = The IP address of the MAX! Cube LAN gateway +thing-type.config.max.bridge.maxRequestsPerConnection.label = Max Requests Per Connection +thing-type.config.max.bridge.maxRequestsPerConnection.description = In exclusive mode, how many requests are allowed until connection is closed and reopened. +thing-type.config.max.bridge.ntpServer1.label = NTP Server 1 +thing-type.config.max.bridge.ntpServer1.description = The hostname for NTP Server 1 used by the Cube to get the time. +thing-type.config.max.bridge.ntpServer2.label = NTP Server 2 +thing-type.config.max.bridge.ntpServer2.description = The hostname for NTP Server 2 used by the Cube to get the time. +thing-type.config.max.bridge.port.label = MAX! Cube LAN Gateway Port +thing-type.config.max.bridge.port.description = Port of the LAN gateway +thing-type.config.max.bridge.refreshInterval.label = Refresh Interval +thing-type.config.max.bridge.refreshInterval.description = The refresh interval in seconds which is used to poll given MAX! Cube. +thing-type.config.max.bridge.rfAddress.label = RF Address +thing-type.config.max.bridge.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.bridge.serialNumber.label = Serial Number +thing-type.config.max.bridge.serialNumber.description = The Serial Number identifies one specific device. +thing-type.config.max.ecoswitch.group.device.label = Device Settings +thing-type.config.max.ecoswitch.group.device.description = Device parameter settings +thing-type.config.max.ecoswitch.group.identification.label = Identification +thing-type.config.max.ecoswitch.group.identification.description = Hardware & location identification +thing-type.config.max.ecoswitch.name.label = Device Name +thing-type.config.max.ecoswitch.name.description = The device description. +thing-type.config.max.ecoswitch.rfAddress.label = RF Address +thing-type.config.max.ecoswitch.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.ecoswitch.room.label = Room +thing-type.config.max.ecoswitch.room.description = The room name. +thing-type.config.max.ecoswitch.serialNumber.label = Serial Number +thing-type.config.max.ecoswitch.serialNumber.description = The Serial Number identifies one specific device. +thing-type.config.max.shuttercontact.action-deviceDelete.label = Delete Device from Cube +thing-type.config.max.shuttercontact.action-deviceDelete.description = Deletes the device from the MAX! Cube. Device will need to be included again! +thing-type.config.max.shuttercontact.action-deviceDelete.option.1234 = Delete +thing-type.config.max.shuttercontact.action-deviceDelete.option.-1 = No Action +thing-type.config.max.shuttercontact.group.actions.label = Actions +thing-type.config.max.shuttercontact.group.actions.description = Action Buttons +thing-type.config.max.shuttercontact.group.device.label = Device Settings +thing-type.config.max.shuttercontact.group.device.description = Device parameter settings +thing-type.config.max.shuttercontact.group.identification.label = Identification +thing-type.config.max.shuttercontact.group.identification.description = Hardware & location identification +thing-type.config.max.shuttercontact.name.label = Device Name +thing-type.config.max.shuttercontact.name.description = The device description. +thing-type.config.max.shuttercontact.rfAddress.label = RF Address +thing-type.config.max.shuttercontact.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.shuttercontact.room.label = Room +thing-type.config.max.shuttercontact.room.description = The room name. +thing-type.config.max.shuttercontact.serialNumber.label = Serial Number +thing-type.config.max.shuttercontact.serialNumber.description = The Serial Number identifies one specific device. +thing-type.config.max.thermostat.action-deviceDelete.label = Delete Device from Cube +thing-type.config.max.thermostat.action-deviceDelete.description = Deletes the device from the MAX! Cube. Device will need to be included again! +thing-type.config.max.thermostat.action-deviceDelete.option.1234 = Delete +thing-type.config.max.thermostat.action-deviceDelete.option.-1 = No Action +thing-type.config.max.thermostat.comfortTemp.label = Comfort Temperature +thing-type.config.max.thermostat.comfortTemp.description = Set the Comfort Temperature. +thing-type.config.max.thermostat.ecoTemp.label = Eco Temperature +thing-type.config.max.thermostat.ecoTemp.description = Set the Eco Temperature. +thing-type.config.max.thermostat.group.actions.label = Actions +thing-type.config.max.thermostat.group.actions.description = Action Buttons +thing-type.config.max.thermostat.group.binding.label = Binding Settings +thing-type.config.max.thermostat.group.binding.description = Binding settings for this device +thing-type.config.max.thermostat.group.device.label = Device Settings +thing-type.config.max.thermostat.group.device.description = Device parameter settings +thing-type.config.max.thermostat.group.identification.label = Identification +thing-type.config.max.thermostat.group.identification.description = Hardware & location identification +thing-type.config.max.thermostat.maxTempSetpoint.label = Max Temperature +thing-type.config.max.thermostat.maxTempSetpoint.description = Set the Thermostat maximum temperature. +thing-type.config.max.thermostat.minTempSetpoint.label = Min Temperature +thing-type.config.max.thermostat.minTempSetpoint.description = Set the Thermostat minimum temperature. +thing-type.config.max.thermostat.name.label = Device Name +thing-type.config.max.thermostat.name.description = The device description. +thing-type.config.max.thermostat.offsetTemp.label = OffSet Temperature +thing-type.config.max.thermostat.offsetTemp.description = Set the Thermostat offset. +thing-type.config.max.thermostat.refreshActualRate.label = Actual Temperature Refresh Rate +thing-type.config.max.thermostat.refreshActualRate.description = Experimental feature! Rate of the actual refresh in minutes. 0-9=refresh disabled. Minimum refresh rate once/10 minutes, recommended 60min. The settings of the heating thermostats are changed to trigger an update of temperature, as the actual temperature only is updated when the valves changes. +thing-type.config.max.thermostat.rfAddress.label = RF Address +thing-type.config.max.thermostat.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.thermostat.room.label = Room +thing-type.config.max.thermostat.room.description = The room name. +thing-type.config.max.thermostat.serialNumber.label = Serial Number +thing-type.config.max.thermostat.serialNumber.description = The Serial Number identifies one specific device. +thing-type.config.max.thermostat.windowOpenDuration.label = Window Open Duration +thing-type.config.max.thermostat.windowOpenDuration.description = Set the Thermostat Window Open Duration. +thing-type.config.max.thermostat.windowOpenTemp.label = Window Open Temp +thing-type.config.max.thermostat.windowOpenTemp.description = Set the Window Open Temperature. +thing-type.config.max.thermostatplus.action-deviceDelete.label = Delete Device from Cube +thing-type.config.max.thermostatplus.action-deviceDelete.description = Deletes the device from the MAX! Cube. Device will need to be included again! +thing-type.config.max.thermostatplus.action-deviceDelete.option.1234 = Delete +thing-type.config.max.thermostatplus.action-deviceDelete.option.-1 = No Action +thing-type.config.max.thermostatplus.comfortTemp.label = Comfort Temperature +thing-type.config.max.thermostatplus.comfortTemp.description = Set the Comfort Temperature. +thing-type.config.max.thermostatplus.ecoTemp.label = Eco Temperature +thing-type.config.max.thermostatplus.ecoTemp.description = Set the Eco Temperature. +thing-type.config.max.thermostatplus.group.actions.label = Actions +thing-type.config.max.thermostatplus.group.actions.description = Action Buttons +thing-type.config.max.thermostatplus.group.binding.label = Binding Settings +thing-type.config.max.thermostatplus.group.binding.description = Binding settings for this device +thing-type.config.max.thermostatplus.group.device.label = Device Settings +thing-type.config.max.thermostatplus.group.device.description = Device parameter settings +thing-type.config.max.thermostatplus.group.identification.label = Identification +thing-type.config.max.thermostatplus.group.identification.description = Hardware & location identification +thing-type.config.max.thermostatplus.maxTempSetpoint.label = Max Temperature +thing-type.config.max.thermostatplus.maxTempSetpoint.description = Set the Thermostat maximum temperature. +thing-type.config.max.thermostatplus.minTempSetpoint.label = Min Temperature +thing-type.config.max.thermostatplus.minTempSetpoint.description = Set the Thermostat minimum temperature. +thing-type.config.max.thermostatplus.name.label = Device Name +thing-type.config.max.thermostatplus.name.description = The device description. +thing-type.config.max.thermostatplus.offsetTemp.label = OffSet Temperature +thing-type.config.max.thermostatplus.offsetTemp.description = Set the Thermostat offset. +thing-type.config.max.thermostatplus.refreshActualRate.label = Actual Temperature Refresh Rate +thing-type.config.max.thermostatplus.refreshActualRate.description = Experimental feature! Rate of the actual refresh in minutes. 0-9=refresh disabled. Minimum refresh rate once/10 minutes, recommended 60min. The settings of the heating thermostats are changed to trigger an update of temperature, as the actual temperature only is updated when the valves changes. +thing-type.config.max.thermostatplus.rfAddress.label = RF Address +thing-type.config.max.thermostatplus.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.thermostatplus.room.label = Room +thing-type.config.max.thermostatplus.room.description = The room name. +thing-type.config.max.thermostatplus.serialNumber.label = Serial Number +thing-type.config.max.thermostatplus.serialNumber.description = The Serial Number identifies one specific device. +thing-type.config.max.thermostatplus.windowOpenDuration.label = Window Open Duration +thing-type.config.max.thermostatplus.windowOpenDuration.description = Set the Thermostat Window Open Duration. +thing-type.config.max.thermostatplus.windowOpenTemp.label = Window Open Temp +thing-type.config.max.thermostatplus.windowOpenTemp.description = Set the Window Open Temperature. +thing-type.config.max.wallthermostat.action-deviceDelete.label = Delete Device from Cube +thing-type.config.max.wallthermostat.action-deviceDelete.description = Deletes the device from the MAX! Cube. Device will need to be included again! +thing-type.config.max.wallthermostat.action-deviceDelete.option.1234 = Delete +thing-type.config.max.wallthermostat.action-deviceDelete.option.-1 = No Action +thing-type.config.max.wallthermostat.group.actions.label = Actions +thing-type.config.max.wallthermostat.group.actions.description = Action Buttons +thing-type.config.max.wallthermostat.group.device.label = Device Settings +thing-type.config.max.wallthermostat.group.device.description = Device parameter settings +thing-type.config.max.wallthermostat.group.identification.label = Identification +thing-type.config.max.wallthermostat.group.identification.description = Hardware & location identification +thing-type.config.max.wallthermostat.name.label = Device Name +thing-type.config.max.wallthermostat.name.description = The device description. +thing-type.config.max.wallthermostat.rfAddress.label = RF Address +thing-type.config.max.wallthermostat.rfAddress.description = The RF Address used for communication between the devices. +thing-type.config.max.wallthermostat.room.label = Room +thing-type.config.max.wallthermostat.room.description = The room name. +thing-type.config.max.wallthermostat.serialNumber.label = Serial Number +thing-type.config.max.wallthermostat.serialNumber.description = The Serial Number identifies one specific device. + +# channel types + +channel-type.max.actual_temp.label = Current Temperature +channel-type.max.actual_temp.description = Current measured room temperature +channel-type.max.contact_state.label = Contact State +channel-type.max.contact_state.description = Contact state information +channel-type.max.duty_cycle.label = Duty Cycle +channel-type.max.duty_cycle.description = Duty Cycle for sending commands to the devices +channel-type.max.free_mem.label = Free Memory Slots +channel-type.max.free_mem.description = Free memory slots to store commands send to the devices +channel-type.max.locked.label = Thermostat Locked +channel-type.max.locked.description = Thermostat is locked for adjustments +channel-type.max.mode.label = Mode +channel-type.max.mode.description = Thermostat Mode Setting +channel-type.max.mode.state.option.AUTOMATIC = AUTOMATIC +channel-type.max.mode.state.option.MANUAL = MANUAL +channel-type.max.mode.state.option.BOOST = BOOST +channel-type.max.mode.state.option.VACATION = VACATION +channel-type.max.set_temp.label = Setpoint Temperature +channel-type.max.set_temp.description = Thermostat Setpoint temperature +channel-type.max.valve.label = Valve Position +channel-type.max.valve.description = Thermostat Valve Position From 0eab0960a5fec7c80be1bc62e8ed15f6f1521fe2 Mon Sep 17 00:00:00 2001 From: Kai Kreuzer Date: Sun, 21 Nov 2021 23:12:43 +0100 Subject: [PATCH 129/361] [amplipi] Add discovery and PA support (#11586) Signed-off-by: Kai Kreuzer Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.amplipi/README.md | 10 +- .../amplipi-api.yml | 2595 +++++++++++++---- .../amplipi/internal/model/Announcement.java | 182 ++ .../internal/model/GroupUpdateWithId.java | 199 ++ .../internal/model/MultiZoneUpdate.java | 125 + .../amplipi/internal/model/SourceInfo.java | 192 ++ .../internal/model/SourceUpdateWithId.java | 112 + .../internal/model/ZoneUpdateWithId.java | 194 ++ .../internal/AmpliPiConfiguration.java | 6 +- .../amplipi/internal/AmpliPiGroupHandler.java | 5 +- .../amplipi/internal/AmpliPiHandler.java | 44 +- .../internal/AmpliPiHandlerFactory.java | 34 +- .../amplipi/internal/AmpliPiZoneHandler.java | 5 +- .../amplipi/internal/audio/PAAudioSink.java | 151 + .../AmpliPiMDNSDiscoveryParticipant.java | 28 +- .../AmpliPiZoneAndGroupDiscoveryService.java | 4 +- 16 files changed, 3315 insertions(+), 571 deletions(-) create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/Announcement.java create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/GroupUpdateWithId.java create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/MultiZoneUpdate.java create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceInfo.java create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceUpdateWithId.java create mode 100644 bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/ZoneUpdateWithId.java create mode 100644 bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/audio/PAAudioSink.java diff --git a/bundles/org.openhab.binding.amplipi/README.md b/bundles/org.openhab.binding.amplipi/README.md index ec341b008bdc0..ed36308b3e7cd 100644 --- a/bundles/org.openhab.binding.amplipi/README.md +++ b/bundles/org.openhab.binding.amplipi/README.md @@ -1,6 +1,6 @@ # AmpliPi Binding -This binding supports the multi room audio system [AmpliPi](http://www.amplipi.com/) from [MicroNova](http://www.micro-nova.com/). +This binding supports the multi-room audio system [AmpliPi](http://www.amplipi.com/) from [MicroNova](http://www.micro-nova.com/). ## Supported Things @@ -10,7 +10,7 @@ Every available zone as well as group is managed as an individual Thing of type ## Discovery -Once the AmpliPi announces itself through mDNS (still a pending feature), it will be automatically discovered on the network. +The AmpliPi announces itself through mDNS, so that the bindings is able to find it automatically. As soon as the AmpliPi is online, its zones and groups are automatically retrieved and added as Things to the Inbox. @@ -45,6 +45,12 @@ The `zone` and `group` Things have the following channels: | mute | Switch | Mutes the zone/group | | source | Number | The source (1-4) that this zone/group is playing | +## Audio Sink + +For every AmpliPi controller, an audio sink is registered with the id of the thing. +This audio sink accepts urls and audio files to be played. +It uses the AmpliPi's PA feature for announcements on all available zones. +If no volume value is passed, the current volume of each zone is used, otherwise the provided volume is temporarily set on all zones for the announcement. ## Full Example diff --git a/bundles/org.openhab.binding.amplipi/amplipi-api.yml b/bundles/org.openhab.binding.amplipi/amplipi-api.yml index fe1731dfac0ba..d5d1c3743727e 100644 --- a/bundles/org.openhab.binding.amplipi/amplipi-api.yml +++ b/bundles/org.openhab.binding.amplipi/amplipi-api.yml @@ -15,26 +15,43 @@ info: 1. Go to an API request 1. Pick one of the examples - 2. Edit it - 3. Press try button, it will send an API command/request to the AmpliPi + 1. Edit it + 1. Press the try button, it will send an API command/request to the AmpliPi - __Try using the get status:__ + __Try getting the status:__ - 1. Go to [Status -> Get Status](#get-/api/) - 2. Click the Try button, you will see a response below with the full status/config of the AmpliPi controller + 1. Go to [Status -> Get Status](#get-/api) + 1. Click the Try button, you will see a response below with the full status/config of the AmpliPi controller + + __Try changing a zone's name:__ + + 1. Go to [Zone -> Update Zone](#patch-/api/zones/-zid-) + 1. Next to **PATH PARAMETERS** click Zone 2 to fill in Zone 2's id + 1. Under **REQUEST BODY** click Example and select "Change Name" + 1. Edit the name to what you want to call the zone + 1. Click the Try button, you will see a response below with the full status/config of the AmpliPi controller + + __Try changing a group's name and zones:__ + + 1. Go to [Group -> Update Group](#patch-/api/groups/-gid-) + 1. Next to **PATH PARAMETERS** click Group 1 to fill in Group 1's id + 1. Under **REQUEST BODY** click Example and select "Rezone Group" + 1. Edit the name to what you want to call the group + 1. Edit the zones that belong to the group + 1. Click the Try button, you will see a response below with the full status/config of the AmpliPi controller __Try creating a new group:__ 1. Go to [Group -> Create Group](#post-/api/group) - 2. Click Example - 3. Edit the zones and group name - 4. Click the try button, you will see a response with the newly created group + 1. Under **REQUEST BODY** click Example and select "Upstairs Group" + 1. Edit the group name or zones array + 1. Click the Try button, you will see a response below with the new group __Here are some other things that you might want to change:__ - [Stream -> Create new stream](#post-/api/stream) - - [Zone -> Update Zone](#patch-/api/zones/-zid-) (to change the zone name) - [Preset -> Create preset](#post-/api/preset) (Have a look at the model to see what can be added here) + - [Source -> Set source](#patch-/api/sources/-sid-) (Try updating Source 1's name to "TV") # More Info @@ -58,7 +75,7 @@ info: url: http://micro-nova.com license: name: GPL - url: /license + url: https://github.com/micro-nova/AmpliPi/blob/master/COPYING servers: - url: '' description: AmpliPi Controller @@ -257,13 +274,201 @@ paths: name: Living Room source_id: 0 vol: -46 - /api/: - get: + /api/load: + post: tags: - status - summary: Get Status - description: 'Get the system status and configuration ' - operationId: get_status_api__get + summary: Load Config + description: 'Load a new configuration (and return the configuration loaded). + This will overwrite the current configuration so it is advised to save the + previous config from. ' + operationId: load_config_api_load_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + examples: + Status of Jason's AmpliPi: + value: + groups: + - id: 0 + mute: false + name: Whole House + source_id: null + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + info: + version: 0.0.1 + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 + required: true responses: '200': description: Successful Response @@ -451,130 +656,726 @@ paths: name: Living Room source_id: 0 vol: -46 - /api/sources: - get: - tags: - - source - summary: Get Sources - description: 'Get all sources ' - operationId: get_sources_api_sources_get - responses: - '200': - description: Successful Response + '422': + description: Validation Error content: application/json: schema: - title: Response Get Sources Api Sources Get - type: object - additionalProperties: - type: array - items: - $ref: '#/components/schemas/Source' - /api/sources/{sid}: - get: + $ref: '#/components/schemas/HTTPValidationError' + /api/reset: + post: tags: - - source - summary: Get Source - description: 'Get Source with id=**sid** ' - operationId: get_source_api_sources__sid__get - parameters: - - description: Source ID - required: true - schema: - title: Sid - maximum: 3.0 - minimum: 0.0 - type: integer - description: Source ID - name: sid - in: path - examples: - '1': - value: 0 - summary: '1' - '2': - value: 1 - summary: '2' - '3': - value: 2 - summary: '3' - '4': - value: 3 - summary: '4' + - status + summary: Reset + description: 'Reload the current configuration, resetting the firmware in the + process. ' + operationId: reset_api_reset_post responses: '200': description: Successful Response content: application/json: schema: - $ref: '#/components/schemas/Source' + $ref: '#/components/schemas/Status' examples: - stream connected: - value: - id: 1 - name: '1' - input: stream=1009 - nothing connected: - value: - id: 2 - name: '2' - input: '' - rca connected: + Status of Jason's AmpliPi: value: - id: 3 - name: '3' - input: local - '422': - description: Validation Error - content: - application/json: - schema: - $ref: '#/components/schemas/HTTPValidationError' - patch: - tags: - - source - summary: Set Source - description: 'Update a source''s configuration (source=**sid**) ' - operationId: set_source_api_sources__sid__patch - parameters: - - description: Source ID - required: true - schema: - title: Sid - maximum: 3.0 - minimum: 0.0 - type: integer - description: Source ID - name: sid - in: path - examples: - '1': - value: 0 - summary: '1' - '2': - value: 1 - summary: '2' - '3': - value: 2 - summary: '3' - '4': - value: 3 - summary: '4' - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/SourceUpdate' - examples: - Update Input to RCA input: - value: - input: local - Update name: - value: - name: J2 - Update Input to Matt and Kim Radio: + groups: + - id: 0 + mute: false + name: Whole House + source_id: null + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + info: + version: 0.0.1 + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 + /api/sources: + get: + tags: + - source + summary: Get Sources + description: 'Get all sources ' + operationId: get_sources_api_sources_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + title: Response Get Sources Api Sources Get + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/Source' + example: + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + /api/sources/{sid}: + get: + tags: + - source + summary: Get Source + description: 'Get Source with id=**sid** ' + operationId: get_source_api_sources__sid__get + parameters: + - description: Source ID + required: true + schema: + title: Sid + maximum: 3.0 + minimum: 0.0 + type: integer + description: Source ID + name: sid + in: path + examples: + openHAB: + value: 0 + summary: openHAB + Chromecast Audio: + value: 1 + summary: Chromecast Audio + Input 3: + value: 2 + summary: Input 3 + Input 4: + value: 3 + summary: Input 4 + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Source' + examples: + stream connected: + value: + id: 1 + name: '1' + input: stream=1009 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + state: playing + nothing connected: + value: + id: 2 + name: '2' + input: '' + info: + img_url: static/imgs/disconnected.png + state: stopped + rca connected: + value: + id: 3 + name: '3' + input: local + info: + img_url: static/imgs/rca_inputs.svg + state: unknown + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + patch: + tags: + - source + summary: Set Source + description: 'Update a source''s configuration (source=**sid**) ' + operationId: set_source_api_sources__sid__patch + parameters: + - description: Source ID + required: true + schema: + title: Sid + maximum: 3.0 + minimum: 0.0 + type: integer + description: Source ID + name: sid + in: path + examples: + openHAB: + value: 0 + summary: openHAB + Chromecast Audio: + value: 1 + summary: Chromecast Audio + Input 3: + value: 2 + summary: Input 3 + Input 4: + value: 3 + summary: Input 4 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SourceUpdate' + examples: + Update Input to RCA input: + value: + input: local + Update name: + value: + name: J2 + Update Input to Matt and Kim Radio: + value: + input: stream=10001 + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + examples: + Status of Jason's AmpliPi: + value: + groups: + - id: 0 + mute: false + name: Whole House + source_id: null + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + info: + version: 0.0.1 + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /api/sources/{sid}/image/{height}: + get: + tags: + - source + summary: Get Image + description: 'Get a square jpeg image representing the current media playing + on source @sid + + + This was added to support low power touch panels ' + operationId: get_image_api_sources__sid__image__height__get + parameters: + - description: Source ID + required: true + schema: + title: Sid + maximum: 3.0 + minimum: 0.0 + type: integer + description: Source ID + name: sid + in: path + examples: + openHAB: + value: 0 + summary: openHAB + Chromecast Audio: + value: 1 + summary: Chromecast Audio + Input 3: + value: 2 + summary: Input 3 + Input 4: + value: 3 + summary: Input 4 + - description: Image Height in pixels + required: true + schema: + title: Height + maximum: 500.0 + minimum: 1.0 + type: integer + description: Image Height in pixels + name: height + in: path + responses: + '200': + description: Successful Response + content: + image/jpg: {} + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /api/zones: + get: + tags: + - zone + summary: Get Zones + description: 'Get all zones ' + operationId: get_zones_api_zones_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + title: Response Get Zones Api Zones Get + type: object + additionalProperties: + type: array + items: + $ref: '#/components/schemas/Zone' + example: + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 + patch: + tags: + - zone + summary: Set Zones + description: 'Update a bunch of zones (and groups) with the same configuration + changes ' + operationId: set_zones_api_zones_patch + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MultiZoneUpdate' + examples: + Connect all zones to source 1: value: - input: stream=10001 + zones: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + update: + source_id: 0 + required: true responses: '200': description: Successful Response @@ -768,25 +1569,6 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - /api/zones: - get: - tags: - - zone - summary: Get Zones - description: 'Get all zones ' - operationId: get_zones_api_zones_get - responses: - '200': - description: Successful Response - content: - application/json: - schema: - title: Response Get Zones Api Zones Get - type: object - additionalProperties: - type: array - items: - $ref: '#/components/schemas/Zone' /api/zones/{zid}: get: tags: @@ -806,24 +1588,24 @@ paths: name: zid in: path examples: - Local: + Flur/Küche/Bad: value: 0 - summary: Local - Office: + summary: Flur/Küche/Bad + Wohnzimmer: value: 1 - summary: Office - Laundry Room: + summary: Wohnzimmer + Schlafzimmer: value: 2 - summary: Laundry Room - Dining Room: + summary: Schlafzimmer + Tino: value: 3 - summary: Dining Room - BROKEN: + summary: Tino + Stella: value: 4 - summary: BROKEN - Guest Bedroom: + summary: Stella + Enzo: value: 5 - summary: Guest Bedroom + summary: Enzo responses: '200': description: Successful Response @@ -870,24 +1652,24 @@ paths: name: zid in: path examples: - Local: + Flur/Küche/Bad: value: 0 - summary: Local - Office: + summary: Flur/Küche/Bad + Wohnzimmer: value: 1 - summary: Office - Laundry Room: + summary: Wohnzimmer + Schlafzimmer: value: 2 - summary: Laundry Room - Dining Room: + summary: Schlafzimmer + Tino: value: 3 - summary: Dining Room - BROKEN: + summary: Tino + Stella: value: 4 - summary: BROKEN - Guest Bedroom: + summary: Stella + Enzo: value: 5 - summary: Guest Bedroom + summary: Enzo requestBody: content: application/json: @@ -906,6 +1688,7 @@ paths: Mute: value: mute: true + required: true responses: '200': description: Successful Response @@ -1184,6 +1967,35 @@ paths: type: array items: $ref: '#/components/schemas/Group' + example: + groups: + - id: 0 + mute: false + name: Whole House + source_id: null + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 /api/groups/{gid}: get: tags: @@ -1201,10 +2013,7 @@ paths: description: Stream ID name: gid in: path - examples: - Whole House: - value: 0 - summary: Whole House + examples: {} responses: '200': description: Successful Response @@ -1256,10 +2065,7 @@ paths: description: Stream ID name: gid in: path - examples: - Whole House: - value: 0 - summary: Whole House + examples: {} responses: '200': description: Successful Response @@ -1469,16 +2275,20 @@ paths: description: Stream ID name: gid in: path - examples: - Whole House: - value: 0 - summary: Whole House + examples: {} requestBody: content: application/json: schema: $ref: '#/components/schemas/GroupUpdate' examples: + Rezone Group: + value: + name: Upstairs + zones: + - 3 + - 4 + - 5 Change Name: value: name: Upstairs @@ -1491,6 +2301,7 @@ paths: Mute: value: mute: true + required: true responses: '200': description: Successful Response @@ -1689,7 +2500,11 @@ paths: tags: - stream summary: Create Stream - description: 'Create a new audio stream ' + description: 'Create a new audio stream + + - For Pandora the station is the number at the end of the Pandora URL for + a ''station'', e.g. 4610303469018478727 from https://www.pandora.com/station/play/4610303469018478727. + ''user'' and ''password'' are the account username and password' operationId: create_stream_api_stream_post requestBody: content: @@ -1740,6 +2555,16 @@ paths: value: name: Micronova AP type: shairport + Play single file or announcement: + value: + name: Play NASA Announcement + url: https://www.nasa.gov/mp3/640149main_Computers%20are%20in%20Control.mp3 + Add FM Radio Station: + value: + name: WXYZ + type: fmradio + freq: '100.1' + logo: static/imgs/fmradio.png required: true responses: '200': @@ -1749,21 +2574,15 @@ paths: schema: $ref: '#/components/schemas/Stream' examples: - Regina Spektor Radio (playing): + Regina Spektor Radio: value: id: 90890 name: Regina Spektor Radio password: '' station: '4473713754798410236' - status: playing + status: connected type: pandora user: example1@micro-nova.com - info: - album: Far (Deluxe Version) - artist: Regina Spektor - img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg - station: Regina Spektor Radio - track: Eet Matt and Kim Radio (disconnected): value: id: 90891 @@ -1816,6 +2635,51 @@ paths: type: array items: $ref: '#/components/schemas/Stream' + example: + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport /api/streams/{sid}: get: tags: @@ -1834,54 +2698,15 @@ paths: name: sid in: path examples: - Regina Spektor Radio: - value: 90890 - summary: Regina Spektor Radio - Matt and Kim Radio: - value: 90891 - summary: Matt and Kim Radio - Pink Radio: - value: 90892 - summary: Pink Radio - Jason's iPhone: - value: 44590 - summary: Jason's iPhone - Marc's iPhone: - value: 4893 - summary: Marc's iPhone - Rnay: - value: 4894 - summary: Rnay - Jeremy's Spotify: - value: 4895 - summary: Jeremy's Spotify - Lincoln's Spotify: - value: 4896 - summary: Lincoln's Spotify - Indie Pop Rocks: - value: 90893 - summary: Indie Pop Rocks + AmpliPi: + value: 1004 + summary: AmpliPi - dlna + Radio Station, needs user/pass/station-id: + value: 1001 + summary: Radio Station, needs user/pass/station-id - pandora Groove Salad: - value: 90894 - summary: Groove Salad - SP_TEST: - value: 90895 - summary: SP_TEST - Trial_DLNA: - value: 90896 - summary: Trial_DLNA - T2: - value: 90897 - summary: T2 - T3: - value: 90898 - summary: T3 - T2.5: - value: 90899 - summary: T2.5 - Jeremy's DLNA: - value: 90900 - summary: Jeremy's DLNA + value: 1003 + summary: Groove Salad - internetradio responses: '200': description: Successful Response @@ -1890,21 +2715,15 @@ paths: schema: $ref: '#/components/schemas/Stream' examples: - Regina Spektor Radio (playing): + Regina Spektor Radio: value: id: 90890 name: Regina Spektor Radio password: '' station: '4473713754798410236' - status: playing + status: connected type: pandora user: example1@micro-nova.com - info: - album: Far (Deluxe Version) - artist: Regina Spektor - img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg - station: Regina Spektor Radio - track: Eet Matt and Kim Radio (disconnected): value: id: 90891 @@ -1955,54 +2774,15 @@ paths: name: sid in: path examples: - Regina Spektor Radio: - value: 90890 - summary: Regina Spektor Radio - Matt and Kim Radio: - value: 90891 - summary: Matt and Kim Radio - Pink Radio: - value: 90892 - summary: Pink Radio - Jason's iPhone: - value: 44590 - summary: Jason's iPhone - Marc's iPhone: - value: 4893 - summary: Marc's iPhone - Rnay: - value: 4894 - summary: Rnay - Jeremy's Spotify: - value: 4895 - summary: Jeremy's Spotify - Lincoln's Spotify: - value: 4896 - summary: Lincoln's Spotify - Indie Pop Rocks: - value: 90893 - summary: Indie Pop Rocks + AmpliPi: + value: 1004 + summary: AmpliPi - dlna + Radio Station, needs user/pass/station-id: + value: 1001 + summary: Radio Station, needs user/pass/station-id - pandora Groove Salad: - value: 90894 - summary: Groove Salad - SP_TEST: - value: 90895 - summary: SP_TEST - Trial_DLNA: - value: 90896 - summary: Trial_DLNA - T2: - value: 90897 - summary: T2 - T3: - value: 90898 - summary: T3 - T2.5: - value: 90899 - summary: T2.5 - Jeremy's DLNA: - value: 90900 - summary: Jeremy's DLNA + value: 1003 + summary: Groove Salad - internetradio responses: '200': description: Successful Response @@ -2213,54 +2993,15 @@ paths: name: sid in: path examples: - Regina Spektor Radio: - value: 90890 - summary: Regina Spektor Radio - Matt and Kim Radio: - value: 90891 - summary: Matt and Kim Radio - Pink Radio: - value: 90892 - summary: Pink Radio - Jason's iPhone: - value: 44590 - summary: Jason's iPhone - Marc's iPhone: - value: 4893 - summary: Marc's iPhone - Rnay: - value: 4894 - summary: Rnay - Jeremy's Spotify: - value: 4895 - summary: Jeremy's Spotify - Lincoln's Spotify: - value: 4896 - summary: Lincoln's Spotify - Indie Pop Rocks: - value: 90893 - summary: Indie Pop Rocks + AmpliPi: + value: 1004 + summary: AmpliPi - dlna + Radio Station, needs user/pass/station-id: + value: 1001 + summary: Radio Station, needs user/pass/station-id - pandora Groove Salad: - value: 90894 - summary: Groove Salad - SP_TEST: - value: 90895 - summary: SP_TEST - Trial_DLNA: - value: 90896 - summary: Trial_DLNA - T2: - value: 90897 - summary: T2 - T3: - value: 90898 - summary: T3 - T2.5: - value: 90899 - summary: T2.5 - Jeremy's DLNA: - value: 90900 - summary: Jeremy's DLNA + value: 1003 + summary: Groove Salad - internetradio requestBody: content: application/json: @@ -2490,6 +3231,16 @@ paths: description: Stream ID name: sid in: path + examples: + AmpliPi: + value: 1004 + summary: AmpliPi - dlna + Radio Station, needs user/pass/station-id: + value: 1001 + summary: Radio Station, needs user/pass/station-id - pandora + Groove Salad: + value: 1003 + summary: Groove Salad - internetradio - description: Number found on the end of a pandora url while playing the station, ie 4610303469018478727 in https://www.pandora.com/station/play/4610303469018478727 required: true @@ -2501,55 +3252,6 @@ paths: station, ie 4610303469018478727 in https://www.pandora.com/station/play/4610303469018478727 name: station in: path - examples: - Regina Spektor Radio: - value: 90890 - summary: Regina Spektor Radio - Matt and Kim Radio: - value: 90891 - summary: Matt and Kim Radio - Pink Radio: - value: 90892 - summary: Pink Radio - Jason's iPhone: - value: 44590 - summary: Jason's iPhone - Marc's iPhone: - value: 4893 - summary: Marc's iPhone - Rnay: - value: 4894 - summary: Rnay - Jeremy's Spotify: - value: 4895 - summary: Jeremy's Spotify - Lincoln's Spotify: - value: 4896 - summary: Lincoln's Spotify - Indie Pop Rocks: - value: 90893 - summary: Indie Pop Rocks - Groove Salad: - value: 90894 - summary: Groove Salad - SP_TEST: - value: 90895 - summary: SP_TEST - Trial_DLNA: - value: 90896 - summary: Trial_DLNA - T2: - value: 90897 - summary: T2 - T3: - value: 90898 - summary: T3 - T2.5: - value: 90899 - summary: T2.5 - Jeremy's DLNA: - value: 90900 - summary: Jeremy's DLNA responses: '200': description: Successful Response @@ -2748,7 +3450,7 @@ paths: tags: - stream summary: Exec Command - description: "Execute a comamnds on a stream (stream=**sid**).\n\n Command\ + description: "Executes a comamnd on a stream (stream=**sid**).\n\n Command\ \ options:\n * Play Stream: **play**\n * Pause Stream: **pause**\n * Skip\ \ to next song: **next**\n * Stop Stream: **stop**\n * Like/Love Current\ \ Song: **love**\n * Ban Current Song (pandora only): **ban**\n * Shelve\ @@ -2765,60 +3467,21 @@ paths: description: Stream ID name: sid in: path + examples: + AmpliPi: + value: 1004 + summary: AmpliPi - dlna + Radio Station, needs user/pass/station-id: + value: 1001 + summary: Radio Station, needs user/pass/station-id - pandora + Groove Salad: + value: 1003 + summary: Groove Salad - internetradio - required: true schema: $ref: '#/components/schemas/StreamCommand' name: cmd in: path - examples: - Regina Spektor Radio: - value: 90890 - summary: Regina Spektor Radio - Matt and Kim Radio: - value: 90891 - summary: Matt and Kim Radio - Pink Radio: - value: 90892 - summary: Pink Radio - Jason's iPhone: - value: 44590 - summary: Jason's iPhone - Marc's iPhone: - value: 4893 - summary: Marc's iPhone - Rnay: - value: 4894 - summary: Rnay - Jeremy's Spotify: - value: 4895 - summary: Jeremy's Spotify - Lincoln's Spotify: - value: 4896 - summary: Lincoln's Spotify - Indie Pop Rocks: - value: 90893 - summary: Indie Pop Rocks - Groove Salad: - value: 90894 - summary: Groove Salad - SP_TEST: - value: 90895 - summary: SP_TEST - Trial_DLNA: - value: 90896 - summary: Trial_DLNA - T2: - value: 90897 - summary: T2 - T3: - value: 90898 - summary: T3 - T2.5: - value: 90899 - summary: T2.5 - Jeremy's DLNA: - value: 90900 - summary: Jeremy's DLNA responses: '200': description: Successful Response @@ -3094,6 +3757,24 @@ paths: type: array items: $ref: '#/components/schemas/Preset' + example: + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true /api/presets/{pid}: get: tags: @@ -3115,9 +3796,9 @@ paths: Mute All: value: 10000 summary: Mute All - Restore last config: - value: 9999 - summary: Restore last config + Play Pandora: + value: 10001 + summary: Play Pandora responses: '200': description: Successful Response @@ -3150,12 +3831,228 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - delete: + delete: + tags: + - preset + summary: Delete Preset + description: 'Delete a preset ' + operationId: delete_preset_api_presets__pid__delete + parameters: + - description: Preset ID + required: true + schema: + title: Pid + minimum: 0.0 + type: integer + description: Preset ID + name: pid + in: path + examples: + Mute All: + value: 10000 + summary: Mute All + Play Pandora: + value: 10001 + summary: Play Pandora + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' + examples: + Status of Jason's AmpliPi: + value: + groups: + - id: 0 + mute: false + name: Whole House + source_id: null + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + info: + version: 0.0.1 + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + patch: tags: - preset - summary: Delete Preset - description: 'Delete a preset ' - operationId: delete_preset_api_presets__pid__delete + summary: Set Preset + description: 'Update a preset''s configuration (preset=**pid**) ' + operationId: set_preset_api_presets__pid__patch parameters: - description: Preset ID required: true @@ -3170,9 +4067,28 @@ paths: Mute All: value: 10000 summary: Mute All - Restore last config: - value: 9999 - summary: Restore last config + Play Pandora: + value: 10001 + summary: Play Pandora + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PresetUpdate' + examples: + Only mute some: + value: + name: Mute Some + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 5 + mute: true responses: '200': description: Successful Response @@ -3366,12 +4282,13 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - patch: + /api/presets/{pid}/load: + post: tags: - preset - summary: Set Preset - description: 'Update a preset''s configuration (preset=**pid**) ' - operationId: set_preset_api_presets__pid__patch + summary: Load Preset + description: 'Load a preset configuration ' + operationId: load_preset_api_presets__pid__load_post parameters: - description: Preset ID required: true @@ -3386,28 +4303,9 @@ paths: Mute All: value: 10000 summary: Mute All - Restore last config: - value: 9999 - summary: Restore last config - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/PresetUpdate' - examples: - Only mute some: - value: - name: Mute Some - state: - zones: - - id: 0 - mute: true - - id: 1 - mute: true - - id: 2 - mute: true - - id: 5 - mute: true + Play Pandora: + value: 10001 + summary: Play Pandora responses: '200': description: Successful Response @@ -3601,30 +4499,23 @@ paths: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' - /api/presets/{pid}/load: + /api/announce: post: tags: - - preset - summary: Load Preset - description: 'Load a preset configuration ' - operationId: load_preset_api_presets__pid__load_post - parameters: - - description: Preset ID + - announce + summary: Announce + description: 'Make an announcement ' + operationId: announce_api_announce_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Announcement' + examples: + Make NASA Announcement: + value: + media: https://www.nasa.gov/mp3/640149main_Computers%20are%20in%20Control.mp3 required: true - schema: - title: Pid - minimum: 0.0 - type: integer - description: Preset ID - name: pid - in: path - examples: - Mute All: - value: 10000 - summary: Mute All - Restore last config: - value: 9999 - summary: Restore last config responses: '200': description: Successful Response @@ -3820,6 +4711,49 @@ paths: $ref: '#/components/schemas/HTTPValidationError' components: schemas: + Announcement: + title: Announcement + required: + - media + type: object + properties: + media: + title: Media + type: string + description: URL to media to play as the announcement + vol: + title: Vol + maximum: 0.0 + minimum: -79.0 + type: integer + description: Output volume in dB + default: -40 + source_id: + title: Source Id + maximum: 3.0 + minimum: 0.0 + type: integer + description: Source to announce with + default: 3 + zones: + title: Zones + type: array + items: + type: integer + description: Set of zone ids belonging to a group + groups: + title: Groups + type: array + items: + type: integer + description: List of group ids + description: 'A PA-like Announcement + + IF no zones or groups are specified, all available zones are used' + examples: + Make NASA Announcement: + value: + media: https://www.nasa.gov/mp3/640149main_Computers%20are%20in%20Control.mp3 Command: title: Command required: @@ -3857,31 +4791,67 @@ components: minimum: 0.0 type: integer description: id of the connected source - default: 0 zones: title: Zones - uniqueItems: true type: array items: type: integer - description: Set of zones belonging to a group + description: Set of zone ids belonging to a group mute: title: Mute type: boolean description: Set to true if output is all zones muted - default: true vol_delta: title: Vol Delta maximum: 0.0 minimum: -79.0 type: integer - description: Average utput volume in dB - default: -79 + description: Average input volume in dB description: 'A group of zones that can share the same audio input and be controlled as a group ie. Updstairs. Volume, mute, and source_id fields are aggregates of the member zones.' + examples: + Upstairs Group: + value: + id: 101 + name: Upstairs + zones: + - 1 + - 2 + - 3 + - 4 + - 5 + vol_delta: -65 + Downstairs Group: + value: + id: 102 + name: Downstairs + zones: + - 6 + - 7 + - 8 + - 9 + vol_delta: -30 + creation_examples: + Upstairs Group: + value: + name: Upstairs + zones: + - 1 + - 2 + - 3 + - 4 + - 5 + Downstairs Group: + value: + name: Downstairs + zones: + - 6 + - 7 + - 8 + - 9 GroupUpdate: title: GroupUpdate type: object @@ -3896,28 +4866,45 @@ components: minimum: 0.0 type: integer description: id of the connected source - default: 0 zones: title: Zones type: array items: type: integer - description: Set of zones belonging to a group + description: Set of zone ids belonging to a group mute: title: Mute type: boolean description: Set to true if output is all zones muted - default: true vol_delta: title: Vol Delta maximum: 0.0 minimum: -79.0 type: integer - description: Average utput volume in dB - default: -79 + description: Average input volume in dB description: 'Reconfiguration of a Group ' - GroupUpdate2: - title: GroupUpdate2 + examples: + Rezone Group: + value: + name: Upstairs + zones: + - 3 + - 4 + - 5 + Change Name: + value: + name: Upstairs + Change audio source: + value: + source-id: 3 + Increase Volume: + value: + vol_delta: -45 + Mute: + value: + mute: true + GroupUpdateWithId: + title: GroupUpdateWithId required: - id type: object @@ -3932,29 +4919,46 @@ components: minimum: 0.0 type: integer description: id of the connected source - default: 0 zones: title: Zones type: array items: type: integer - description: Set of zones belonging to a group + description: Set of zone ids belonging to a group mute: title: Mute type: boolean description: Set to true if output is all zones muted - default: true vol_delta: title: Vol Delta maximum: 0.0 minimum: -79.0 type: integer - description: Average utput volume in dB - default: -79 + description: Average input volume in dB id: title: Id type: integer description: 'Reconfiguration of a specific Group ' + examples: + Rezone Group: + value: + name: Upstairs + zones: + - 3 + - 4 + - 5 + Change Name: + value: + name: Upstairs + Change audio source: + value: + source-id: 3 + Increase Volume: + value: + vol_delta: -45 + Mute: + value: + mute: true HTTPValidationError: title: HTTPValidationError type: object @@ -3985,11 +4989,43 @@ components: type: boolean default: false description: 'Information about the settings used by the controller ' + MultiZoneUpdate: + title: MultiZoneUpdate + required: + - update + type: object + properties: + zones: + title: Zones + type: array + items: + type: integer + description: Set of zone ids belonging to a group + groups: + title: Groups + type: array + items: + type: integer + description: List of group ids + update: + $ref: '#/components/schemas/ZoneUpdate' + description: 'Reconfiguration of multiple zones specified by zone_ids and group_ids ' + examples: + Connect all zones to source 1: + value: + zones: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + update: + source_id: 0 Preset: title: Preset required: - name - - state type: object properties: id: @@ -4007,7 +5043,6 @@ components: type: array items: $ref: '#/components/schemas/Command' - default: [] last_used: title: Last Used type: integer @@ -4015,6 +5050,43 @@ components: In addition to most of the configuration found in Status, this can contain commands as well that configure the state of different streaming services.' + examples: + Mute All: + value: + id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + creation_examples: + Add Mute All: + value: + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true PresetState: title: PresetState type: object @@ -4023,17 +5095,17 @@ components: title: Sources type: array items: - $ref: '#/components/schemas/SourceUpdate2' + $ref: '#/components/schemas/SourceUpdateWithId' zones: title: Zones type: array items: - $ref: '#/components/schemas/ZoneUpdate2' + $ref: '#/components/schemas/ZoneUpdateWithId' groups: title: Groups type: array items: - $ref: '#/components/schemas/GroupUpdate2' + $ref: '#/components/schemas/GroupUpdateWithId' description: 'A set of partial configuration changes to make to sources, zones, and groups ' PresetUpdate: @@ -4057,6 +5129,20 @@ components: The contents of state and commands will be completely replaced if populated. Merging old and new updates seems too complicated and error prone.' + examples: + Only mute some: + value: + name: Mute Some + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 5 + mute: true Source: title: Source required: @@ -4079,7 +5165,70 @@ components: \ connects to the RCA inputs associated\n * Nothing ('') behind the scenes\ \ this is muxed to a digital output\n " default: '' + info: + title: Info + allOf: + - $ref: '#/components/schemas/SourceInfo' + description: Additional info about the current audio playing from the stream + (generated during playback description: 'An audio source ' + examples: + stream connected: + value: + id: 1 + name: '1' + input: stream=1009 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + state: playing + nothing connected: + value: + id: 2 + name: '2' + input: '' + info: + img_url: static/imgs/disconnected.png + state: stopped + rca connected: + value: + id: 3 + name: '3' + input: local + info: + img_url: static/imgs/rca_inputs.svg + state: unknown + SourceInfo: + title: SourceInfo + required: + - name + - state + type: object + properties: + name: + title: Name + type: string + state: + title: State + type: string + artist: + title: Artist + type: string + track: + title: Track + type: string + album: + title: Album + type: string + station: + title: Station + type: string + img_url: + title: Img Url + type: string SourceUpdate: title: SourceUpdate type: object @@ -4092,8 +5241,18 @@ components: title: Input type: string description: 'Partial reconfiguration of an audio Source ' - SourceUpdate2: - title: SourceUpdate2 + examples: + Update Input to RCA input: + value: + input: local + Update name: + value: + name: J2 + Update Input to Matt and Kim Radio: + value: + input: stream=10001 + SourceUpdateWithId: + title: SourceUpdateWithId required: - id type: object @@ -4111,6 +5270,16 @@ components: minimum: 0.0 type: integer description: 'Partial reconfiguration of a specific audio Source ' + examples: + Update Input to RCA input: + value: + input: local + Update name: + value: + name: J2 + Update Input to Matt and Kim Radio: + value: + input: stream=10001 Status: title: Status type: object @@ -4140,37 +5309,37 @@ components: $ref: '#/components/schemas/Zone' default: - id: 0 - name: Zone 0 + name: Zone 1 source_id: 0 mute: true vol: -79 disabled: false - id: 1 - name: Zone 1 + name: Zone 2 source_id: 0 mute: true vol: -79 disabled: false - id: 2 - name: Zone 2 + name: Zone 3 source_id: 0 mute: true vol: -79 disabled: false - id: 3 - name: Zone 3 + name: Zone 4 source_id: 0 mute: true vol: -79 disabled: false - id: 4 - name: Zone 4 + name: Zone 5 source_id: 0 mute: true vol: -79 disabled: false - id: 5 - name: Zone 5 + name: Zone 6 source_id: 0 mute: true vol: -79 @@ -4196,6 +5365,185 @@ components: info: $ref: '#/components/schemas/Info' description: 'Full Controller Configuration and Status ' + examples: + Status of Jason's AmpliPi: + value: + groups: + - id: 0 + mute: false + name: Whole House + vol_delta: -44 + zones: + - 0 + - 1 + - 2 + - 3 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - id: 1 + mute: true + name: KitchLivDining + source_id: 0 + vol_delta: -49 + zones: + - 3 + - 9 + - 10 + - 11 + presets: + - id: 10000 + name: Mute All + state: + zones: + - id: 0 + mute: true + - id: 1 + mute: true + - id: 2 + mute: true + - id: 3 + mute: true + - id: 4 + mute: true + - id: 5 + mute: true + sources: + - id: 0 + input: stream=90890 + name: J1 + - id: 1 + input: stream=44590 + name: J2 + - id: 2 + input: local + name: Marc + - id: 3 + input: local + name: Source 4 + streams: + - id: 90890 + info: + album: Far (Deluxe Version) + artist: Regina Spektor + img_url: http://mediaserver-cont-dc6-1-v4v6.pandora.com/images/public/int/2/1/5/4/093624974512_500W_500H.jpg + station: Regina Spektor Radio + track: Eet + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: playing + type: pandora + user: example1@micro-nova.com + - id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + - id: 90892 + info: + details: No info available + name: Pink Radio + password: '' + station: '4326539910057675260' + status: disconnected + type: pandora + user: example3@micro-nova.com + - id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + - id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + info: + version: 0.0.1 + zones: + - disabled: false + id: 0 + mute: false + name: Local + source_id: 1 + vol: -35 + - disabled: false + id: 1 + mute: false + name: Office + source_id: 0 + vol: -41 + - disabled: false + id: 2 + mute: true + name: Laundry Room + source_id: 0 + vol: -48 + - disabled: false + id: 3 + mute: true + name: Dining Room + source_id: 0 + vol: -44 + - disabled: true + id: 4 + mute: true + name: BROKEN + source_id: 0 + vol: -50 + - disabled: false + id: 5 + mute: true + name: Guest Bedroom + source_id: 0 + vol: -48 + - disabled: false + id: 6 + mute: true + name: Main Bedroom + source_id: 0 + vol: -40 + - disabled: false + id: 7 + mute: true + name: Main Bathroom + source_id: 0 + vol: -44 + - disabled: false + id: 8 + mute: true + name: Master Bathroom + source_id: 0 + vol: -41 + - disabled: false + id: 9 + mute: true + name: Kitchen High + source_id: 0 + vol: -53 + - disabled: false + id: 10 + mute: true + name: kitchen Low + source_id: 0 + vol: -52 + - disabled: false + id: 11 + mute: true + name: Living Room + source_id: 0 + vol: -46 Stream: title: Stream required: @@ -4215,7 +5563,7 @@ components: title: Type type: string description: "stream type\n\n * pandora\n * shairport\n * dlna\n * internetradio\n\ - \ * spotify\n " + \ * spotify\n * plexamp\n * file\n * fmradio\n " user: title: User type: string @@ -4231,29 +5579,124 @@ components: url: title: Url type: string - description: Stream url, used for internetradio + description: Stream url, used for internetradio and file logo: title: Logo type: string description: Icon/Logo url, used for internetradio - info: - title: Info - type: object - description: Additional info about the current audio playing from the stream - (generated during playback - status: - title: Status + freq: + title: Freq type: string - description: State of the stream + description: FM Frequency (MHz), used for fmradio + client_id: + title: Client Id + type: string + description: Plexamp client_id, becomes "identifier" in server.json + token: + title: Token + type: string + description: Plexamp token for server.json description: 'Digital stream such as Pandora, Airplay or Spotify ' + examples: + Regina Spektor Radio: + value: + id: 90890 + name: Regina Spektor Radio + password: '' + station: '4473713754798410236' + status: connected + type: pandora + user: example1@micro-nova.com + Matt and Kim Radio (disconnected): + value: + id: 90891 + info: + details: No info available + name: Matt and Kim Radio + password: '' + station: '4610303469018478727' + status: disconnected + type: pandora + user: example2@micro-nova.com + Shairport (connected): + value: + id: 44590 + info: + details: No info available + name: Jason's iPhone + status: connected + type: shairport + Shairport (disconnected): + value: + id: 4894 + info: + details: No info available + name: Rnay + status: disconnected + type: shairport + creation_examples: + Add Beatles Internet Radio Station: + value: + logo: http://www.beatlesradio.com/content/images/thumbs/0000587.gif + name: Beatles Radio + type: internetradio + url: http://www.beatlesradio.com:8000/stream/1/ + Add Classical KING Internet Radio Station: + value: + logo: https://i.iheart.com/v3/re/assets/images/7bcfd87a-de3e-47d0-b896-be0ed38c9d74.png + name: Classical KING FM 98.1 + type: internetradio + url: http://classicalking.streamguys1.com/king-fm-aac-iheart + Add Generic DLNA: + value: + name: Replace this text with a name you like! + type: dlna + Add Groove Salad Internet Radio Station: + value: + logo: https://somafm.com/img3/groovesalad-200.jpg + name: Groove Salad + type: internetradio + url: http://ice2.somafm.com/groovesalad-16-aac + Add KEXP Internet Radio Station: + value: + logo: https://i.iheart.com/v3/re/new_assets/cc4e0a17-5233-4e4b-9b6b-7799904f78ea + name: KEXP 90.3 + type: internetradio + url: http://live-aacplus-64.kexp.org/kexp64.aac + Add Matt and Kim Pandora Station: + value: + name: Matt and Kim Radio + password: s79sDDkjf + station: '4473713754798410236' + type: pandora + user: test@micro-nova.com + Add MicroNova Spotify: + value: + name: MicroNova Spotify + type: spotify + Add Micronova Airplay: + value: + name: Micronova AP + type: shairport + Play single file or announcement: + value: + name: Play NASA Announcement + url: https://www.nasa.gov/mp3/640149main_Computers%20are%20in%20Control.mp3 + Add FM Radio Station: + value: + name: WXYZ + type: fmradio + freq: '100.1' + logo: static/imgs/fmradio.png StreamCommand: title: StreamCommand enum: - play - pause - next + - prev - stop - - like + - love - ban - shelve type: string @@ -4281,7 +5724,24 @@ components: logo: title: Logo type: string + freq: + title: Freq + type: string description: 'Reconfiguration of a Stream ' + examples: + Change account info: + value: + password: sd9sk3k30 + user: test@micro-nova.com + Change name: + value: + name: Matt and Kim Radio + Change pandora radio station: + value: + station: 0982034049300 + Upgrade groove salad stream quality: + value: + url: http://ice2.somafm.com/groovesalad-64-aac ValidationError: title: ValidationError required: @@ -4341,6 +5801,21 @@ components: default: false description: 'Audio output to a stereo pair of speakers, typically belonging to a room ' + examples: + Living Room: + value: + name: Living Room + source_id: 1 + mute: false + vol: -25 + disabled: false + Dining Room: + value: + name: Dining Room + source_id: 2 + mute: true + vol: -65 + disabled: false ZoneUpdate: title: ZoneUpdate type: object @@ -4355,27 +5830,36 @@ components: minimum: 0.0 type: integer description: id of the connected source - default: 0 mute: title: Mute type: boolean description: Set to true if output is muted - default: true vol: title: Vol maximum: 0.0 minimum: -79.0 type: integer description: Output volume in dB - default: -79 disabled: title: Disabled type: boolean description: Set to true if not connected to a speaker - default: false description: 'Reconfiguration of a Zone ' - ZoneUpdate2: - title: ZoneUpdate2 + examples: + Change Name: + value: + name: Bedroom + Change audio source: + value: + source-id: 3 + Increase Volume: + value: + vol: -45 + Mute: + value: + mute: true + ZoneUpdateWithId: + title: ZoneUpdateWithId required: - id type: object @@ -4390,36 +5874,45 @@ components: minimum: 0.0 type: integer description: id of the connected source - default: 0 mute: title: Mute type: boolean description: Set to true if output is muted - default: true vol: title: Vol maximum: 0.0 minimum: -79.0 type: integer description: Output volume in dB - default: -79 disabled: title: Disabled type: boolean description: Set to true if not connected to a speaker - default: false id: title: Id maximum: 35.0 minimum: 0.0 type: integer description: 'Reconfiguration of a specific Zone ' + examples: + Change Name: + value: + name: Bedroom + Change audio source: + value: + source-id: 3 + Increase Volume: + value: + vol: -45 + Mute: + value: + mute: true tags: - name: status - description: The status and configuration of the entire system, including source, + description: The status and configuration of the entire system, including sources, zones, groups, and streams. - name: source - description: Audio source. Can accept sudio input from a local (RCA) connection + description: Audio source. Can accept audio input from a local (RCA) connection or any stream. Sources can be connected to one or multiple zones, or connected to nothing at all. - name: zone @@ -4429,9 +5922,9 @@ tags: - name: group description: Group of zones. Grouping allows a set of zones to be controlled together. A zone can belong to multiple groups, allowing for different levels of abstraction, - ie. Guest Bedroom can belong to both the 'Upstairs' and 'Whole House' groups., + e.g. Guest Bedroom can belong to both the 'Upstairs' and 'Whole House' groups. - name: stream - description: Digital stream that can be connected to a source, ie. Pandora, Airplay, + description: Digital stream that can be connected to a source, e.g. Pandora, Airplay, Spotify, Internet Radio, DLNA. - name: preset description: A partial system configuration. Used to load specific configurations, diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/Announcement.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/Announcement.java new file mode 100644 index 0000000000000..88e31cd410d22 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/Announcement.java @@ -0,0 +1,182 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A PA-like Announcement IF no zones or groups are specified, all available zones are used + **/ +public class Announcement { + + /** + * URL to media to play as the announcement + **/ + private String media; + + /** + * Output volume in dB + **/ + private Integer vol = -40; + + /** + * Source to announce with + **/ + private Integer sourceId = 3; + + /** + * Set of zone ids belonging to a group + **/ + private List zones = null; + + /** + * List of group ids + **/ + private List groups = null; + + /** + * URL to media to play as the announcement + * + * @return media + **/ + @JsonProperty("media") + public String getMedia() { + return media; + } + + public void setMedia(String media) { + this.media = media; + } + + public Announcement media(String media) { + this.media = media; + return this; + } + + /** + * Output volume in dB + * minimum: -79 + * maximum: 0 + * + * @return vol + **/ + @JsonProperty("vol") + public Integer getVol() { + return vol; + } + + public void setVol(Integer vol) { + this.vol = vol; + } + + public Announcement vol(Integer vol) { + this.vol = vol; + return this; + } + + /** + * Source to announce with + * minimum: 0 + * maximum: 3 + * + * @return sourceId + **/ + @JsonProperty("source_id") + public Integer getSourceId() { + return sourceId; + } + + public void setSourceId(Integer sourceId) { + this.sourceId = sourceId; + } + + public Announcement sourceId(Integer sourceId) { + this.sourceId = sourceId; + return this; + } + + /** + * Set of zone ids belonging to a group + * + * @return zones + **/ + @JsonProperty("zones") + public List getZones() { + return zones; + } + + public void setZones(List zones) { + this.zones = zones; + } + + public Announcement zones(List zones) { + this.zones = zones; + return this; + } + + public Announcement addZonesItem(Integer zonesItem) { + this.zones.add(zonesItem); + return this; + } + + /** + * List of group ids + * + * @return groups + **/ + @JsonProperty("groups") + public List getGroups() { + return groups; + } + + public void setGroups(List groups) { + this.groups = groups; + } + + public Announcement groups(List groups) { + this.groups = groups; + return this; + } + + public Announcement addGroupsItem(Integer groupsItem) { + this.groups.add(groupsItem); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Announcement {\n"); + + sb.append(" media: ").append(toIndentedString(media)).append("\n"); + sb.append(" vol: ").append(toIndentedString(vol)).append("\n"); + sb.append(" sourceId: ").append(toIndentedString(sourceId)).append("\n"); + sb.append(" zones: ").append(toIndentedString(zones)).append("\n"); + sb.append(" groups: ").append(toIndentedString(groups)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/GroupUpdateWithId.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/GroupUpdateWithId.java new file mode 100644 index 0000000000000..9f948e1920158 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/GroupUpdateWithId.java @@ -0,0 +1,199 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Reconfiguration of a specific Group + **/ +public class GroupUpdateWithId { + + /** + * Friendly name + **/ + private String name; + + /** + * id of the connected source + **/ + private Integer sourceId; + + /** + * Set of zone ids belonging to a group + **/ + private List zones = null; + + /** + * Set to true if output is all zones muted + **/ + private Boolean mute; + + /** + * Average input volume in dB + **/ + private Integer volDelta; + + private Integer id; + + /** + * Friendly name + * + * @return name + **/ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public GroupUpdateWithId name(String name) { + this.name = name; + return this; + } + + /** + * id of the connected source + * minimum: 0 + * maximum: 3 + * + * @return sourceId + **/ + @JsonProperty("source_id") + public Integer getSourceId() { + return sourceId; + } + + public void setSourceId(Integer sourceId) { + this.sourceId = sourceId; + } + + public GroupUpdateWithId sourceId(Integer sourceId) { + this.sourceId = sourceId; + return this; + } + + /** + * Set of zone ids belonging to a group + * + * @return zones + **/ + @JsonProperty("zones") + public List getZones() { + return zones; + } + + public void setZones(List zones) { + this.zones = zones; + } + + public GroupUpdateWithId zones(List zones) { + this.zones = zones; + return this; + } + + public GroupUpdateWithId addZonesItem(Integer zonesItem) { + this.zones.add(zonesItem); + return this; + } + + /** + * Set to true if output is all zones muted + * + * @return mute + **/ + @JsonProperty("mute") + public Boolean getMute() { + return mute; + } + + public void setMute(Boolean mute) { + this.mute = mute; + } + + public GroupUpdateWithId mute(Boolean mute) { + this.mute = mute; + return this; + } + + /** + * Average input volume in dB + * minimum: -79 + * maximum: 0 + * + * @return volDelta + **/ + @JsonProperty("vol_delta") + public Integer getVolDelta() { + return volDelta; + } + + public void setVolDelta(Integer volDelta) { + this.volDelta = volDelta; + } + + public GroupUpdateWithId volDelta(Integer volDelta) { + this.volDelta = volDelta; + return this; + } + + /** + * Get id + * + * @return id + **/ + @JsonProperty("id") + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public GroupUpdateWithId id(Integer id) { + this.id = id; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class GroupUpdateWithId {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" sourceId: ").append(toIndentedString(sourceId)).append("\n"); + sb.append(" zones: ").append(toIndentedString(zones)).append("\n"); + sb.append(" mute: ").append(toIndentedString(mute)).append("\n"); + sb.append(" volDelta: ").append(toIndentedString(volDelta)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/MultiZoneUpdate.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/MultiZoneUpdate.java new file mode 100644 index 0000000000000..b1ac8a40c6451 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/MultiZoneUpdate.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Reconfiguration of multiple zones specified by zone_ids and group_ids + **/ +public class MultiZoneUpdate { + + /** + * Set of zone ids belonging to a group + **/ + private List zones = null; + + /** + * List of group ids + **/ + private List groups = null; + + private ZoneUpdate update; + + /** + * Set of zone ids belonging to a group + * + * @return zones + **/ + @JsonProperty("zones") + public List getZones() { + return zones; + } + + public void setZones(List zones) { + this.zones = zones; + } + + public MultiZoneUpdate zones(List zones) { + this.zones = zones; + return this; + } + + public MultiZoneUpdate addZonesItem(Integer zonesItem) { + this.zones.add(zonesItem); + return this; + } + + /** + * List of group ids + * + * @return groups + **/ + @JsonProperty("groups") + public List getGroups() { + return groups; + } + + public void setGroups(List groups) { + this.groups = groups; + } + + public MultiZoneUpdate groups(List groups) { + this.groups = groups; + return this; + } + + public MultiZoneUpdate addGroupsItem(Integer groupsItem) { + this.groups.add(groupsItem); + return this; + } + + /** + * Get update + * + * @return update + **/ + @JsonProperty("update") + public ZoneUpdate getUpdate() { + return update; + } + + public void setUpdate(ZoneUpdate update) { + this.update = update; + } + + public MultiZoneUpdate update(ZoneUpdate update) { + this.update = update; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class MultiZoneUpdate {\n"); + + sb.append(" zones: ").append(toIndentedString(zones)).append("\n"); + sb.append(" groups: ").append(toIndentedString(groups)).append("\n"); + sb.append(" update: ").append(toIndentedString(update)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceInfo.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceInfo.java new file mode 100644 index 0000000000000..ad797948e76b6 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceInfo.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class SourceInfo { + + private String name; + + private String state; + + private String artist; + + private String track; + + private String album; + + private String station; + + private String imgUrl; + + /** + * Get name + * + * @return name + **/ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SourceInfo name(String name) { + this.name = name; + return this; + } + + /** + * Get state + * + * @return state + **/ + @JsonProperty("state") + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public SourceInfo state(String state) { + this.state = state; + return this; + } + + /** + * Get artist + * + * @return artist + **/ + @JsonProperty("artist") + public String getArtist() { + return artist; + } + + public void setArtist(String artist) { + this.artist = artist; + } + + public SourceInfo artist(String artist) { + this.artist = artist; + return this; + } + + /** + * Get track + * + * @return track + **/ + @JsonProperty("track") + public String getTrack() { + return track; + } + + public void setTrack(String track) { + this.track = track; + } + + public SourceInfo track(String track) { + this.track = track; + return this; + } + + /** + * Get album + * + * @return album + **/ + @JsonProperty("album") + public String getAlbum() { + return album; + } + + public void setAlbum(String album) { + this.album = album; + } + + public SourceInfo album(String album) { + this.album = album; + return this; + } + + /** + * Get station + * + * @return station + **/ + @JsonProperty("station") + public String getStation() { + return station; + } + + public void setStation(String station) { + this.station = station; + } + + public SourceInfo station(String station) { + this.station = station; + return this; + } + + /** + * Get imgUrl + * + * @return imgUrl + **/ + @JsonProperty("img_url") + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public SourceInfo imgUrl(String imgUrl) { + this.imgUrl = imgUrl; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SourceInfo {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" artist: ").append(toIndentedString(artist)).append("\n"); + sb.append(" track: ").append(toIndentedString(track)).append("\n"); + sb.append(" album: ").append(toIndentedString(album)).append("\n"); + sb.append(" station: ").append(toIndentedString(station)).append("\n"); + sb.append(" imgUrl: ").append(toIndentedString(imgUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceUpdateWithId.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceUpdateWithId.java new file mode 100644 index 0000000000000..7fa59e20ecf81 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/SourceUpdateWithId.java @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Partial reconfiguration of a specific audio Source + **/ +public class SourceUpdateWithId { + + /** + * Friendly name + **/ + private String name; + + private String input; + + private Integer id; + + /** + * Friendly name + * + * @return name + **/ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SourceUpdateWithId name(String name) { + this.name = name; + return this; + } + + /** + * Get input + * + * @return input + **/ + @JsonProperty("input") + public String getInput() { + return input; + } + + public void setInput(String input) { + this.input = input; + } + + public SourceUpdateWithId input(String input) { + this.input = input; + return this; + } + + /** + * Get id + * minimum: 0 + * maximum: 4 + * + * @return id + **/ + @JsonProperty("id") + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public SourceUpdateWithId id(Integer id) { + this.id = id; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SourceUpdateWithId {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" input: ").append(toIndentedString(input)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/ZoneUpdateWithId.java b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/ZoneUpdateWithId.java new file mode 100644 index 0000000000000..f04c947c0d517 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/gen/java/org/openhab/binding/amplipi/internal/model/ZoneUpdateWithId.java @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Reconfiguration of a specific Zone + **/ +public class ZoneUpdateWithId { + + /** + * Friendly name + **/ + private String name; + + /** + * id of the connected source + **/ + private Integer sourceId; + + /** + * Set to true if output is muted + **/ + private Boolean mute; + + /** + * Output volume in dB + **/ + private Integer vol; + + /** + * Set to true if not connected to a speaker + **/ + private Boolean disabled; + + private Integer id; + + /** + * Friendly name + * + * @return name + **/ + @JsonProperty("name") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ZoneUpdateWithId name(String name) { + this.name = name; + return this; + } + + /** + * id of the connected source + * minimum: 0 + * maximum: 3 + * + * @return sourceId + **/ + @JsonProperty("source_id") + public Integer getSourceId() { + return sourceId; + } + + public void setSourceId(Integer sourceId) { + this.sourceId = sourceId; + } + + public ZoneUpdateWithId sourceId(Integer sourceId) { + this.sourceId = sourceId; + return this; + } + + /** + * Set to true if output is muted + * + * @return mute + **/ + @JsonProperty("mute") + public Boolean getMute() { + return mute; + } + + public void setMute(Boolean mute) { + this.mute = mute; + } + + public ZoneUpdateWithId mute(Boolean mute) { + this.mute = mute; + return this; + } + + /** + * Output volume in dB + * minimum: -79 + * maximum: 0 + * + * @return vol + **/ + @JsonProperty("vol") + public Integer getVol() { + return vol; + } + + public void setVol(Integer vol) { + this.vol = vol; + } + + public ZoneUpdateWithId vol(Integer vol) { + this.vol = vol; + return this; + } + + /** + * Set to true if not connected to a speaker + * + * @return disabled + **/ + @JsonProperty("disabled") + public Boolean getDisabled() { + return disabled; + } + + public void setDisabled(Boolean disabled) { + this.disabled = disabled; + } + + public ZoneUpdateWithId disabled(Boolean disabled) { + this.disabled = disabled; + return this; + } + + /** + * Get id + * minimum: 0 + * maximum: 35 + * + * @return id + **/ + @JsonProperty("id") + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public ZoneUpdateWithId id(Integer id) { + this.id = id; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ZoneUpdateWithId {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" sourceId: ").append(toIndentedString(sourceId)).append("\n"); + sb.append(" mute: ").append(toIndentedString(mute)).append("\n"); + sb.append(" vol: ").append(toIndentedString(vol)).append("\n"); + sb.append(" disabled: ").append(toIndentedString(disabled)).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private static String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiConfiguration.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiConfiguration.java index a207161e73499..558f61c03d017 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiConfiguration.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiConfiguration.java @@ -12,16 +12,20 @@ */ package org.openhab.binding.amplipi.internal; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + /** * The {@link AmpliPiConfiguration} class contains fields mapping thing configuration parameters. * * @author Kai Kreuzer - Initial contribution */ +@NonNullByDefault public class AmpliPiConfiguration { /** * Sample configuration parameters. Replace with your own. */ - public String hostname; + public @Nullable String hostname; public int refreshInterval; } diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiGroupHandler.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiGroupHandler.java index 9962b484f88fb..f854273790880 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiGroupHandler.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiGroupHandler.java @@ -16,7 +16,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; @@ -90,7 +89,7 @@ public void initialize() { } @Override - public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command command) { + public void handleCommand(ChannelUID channelUID, Command command) { if (command == RefreshType.REFRESH) { // do nothing - we just wait for the next automatic refresh return; @@ -134,7 +133,7 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma } @Override - public void receive(@NonNull Status status) { + public void receive(Status status) { int id = getId(thing); Optional group = status.getGroups().stream().filter(z -> z.getId().equals(id)).findFirst(); if (group.isPresent()) { diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandler.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandler.java index 41523c6ec7269..fc091122162f5 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandler.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandler.java @@ -31,12 +31,16 @@ import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; +import org.openhab.binding.amplipi.internal.audio.PAAudioSink; import org.openhab.binding.amplipi.internal.discovery.AmpliPiZoneAndGroupDiscoveryService; +import org.openhab.binding.amplipi.internal.model.Announcement; import org.openhab.binding.amplipi.internal.model.Preset; import org.openhab.binding.amplipi.internal.model.SourceUpdate; import org.openhab.binding.amplipi.internal.model.Status; import org.openhab.binding.amplipi.internal.model.Stream; +import org.openhab.core.audio.AudioHTTPServer; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; @@ -67,7 +71,9 @@ public class AmpliPiHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(AmpliPiHandler.class); private final HttpClient httpClient; + private AudioHTTPServer audioHTTPServer; private final Gson gson; + private @Nullable String callbackUrl; private String url = "http://amplipi"; private List presets = List.of(); @@ -76,9 +82,12 @@ public class AmpliPiHandler extends BaseBridgeHandler { private @Nullable ScheduledFuture refreshJob; - public AmpliPiHandler(Thing thing, HttpClient httpClient) { + public AmpliPiHandler(Thing thing, HttpClient httpClient, AudioHTTPServer audioHTTPServer, + @Nullable String callbackUrl) { super((Bridge) thing); this.httpClient = httpClient; + this.audioHTTPServer = audioHTTPServer; + this.callbackUrl = callbackUrl; this.gson = new Gson(); } @@ -190,7 +199,7 @@ public void dispose() { @Override public Collection> getServices() { return Set.of(PresetCommandOptionProvider.class, InputStateOptionProvider.class, - AmpliPiZoneAndGroupDiscoveryService.class); + AmpliPiZoneAndGroupDiscoveryService.class, PAAudioSink.class); } public List getPresets() { @@ -205,6 +214,10 @@ public String getUrl() { return url; } + public AudioHTTPServer getAudioHTTPServer() { + return audioHTTPServer; + } + public void addStatusChangeListener(AmpliPiStatusChangeListener listener) { changeListeners.add(listener); } @@ -212,4 +225,31 @@ public void addStatusChangeListener(AmpliPiStatusChangeListener listener) { public void removeStatusChangeListener(AmpliPiStatusChangeListener listener) { changeListeners.remove(listener); } + + public void playPA(String audioUrl, @Nullable PercentType volume) { + Announcement announcement = new Announcement(); + announcement.setMedia(audioUrl); + if (volume != null) { + announcement.setVol(AmpliPiUtils.percentTypeToVolume(volume)); + } + String url = getUrl() + "/api/announce"; + StringContentProvider contentProvider = new StringContentProvider(gson.toJson(announcement)); + try { + ContentResponse response = httpClient.newRequest(url).method(HttpMethod.POST) + .content(contentProvider, "application/json").send(); + if (response.getStatus() != HttpStatus.OK_200) { + logger.error("AmpliPi API returned HTTP status {}.", response.getStatus()); + logger.debug("Content: {}", response.getContentAsString()); + } else { + logger.debug("PA request sent successfully."); + } + } catch (InterruptedException | TimeoutException | ExecutionException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + "AmpliPi request failed: " + e.getMessage()); + } + } + + public @Nullable String getCallbackUrl() { + return callbackUrl; + } } diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandlerFactory.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandlerFactory.java index e548682a27f1c..f7da9cb7e24d9 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandlerFactory.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiHandlerFactory.java @@ -19,7 +19,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; +import org.openhab.core.audio.AudioHTTPServer; import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.core.net.HttpServiceUtil; +import org.openhab.core.net.NetworkAddressService; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; @@ -28,6 +31,8 @@ import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The {@link AmpliPiHandlerFactory} is responsible for creating things and thing @@ -39,11 +44,18 @@ @Component(configurationPid = "binding.amplipi", service = ThingHandlerFactory.class) public class AmpliPiHandlerFactory extends BaseThingHandlerFactory { + private final Logger logger = LoggerFactory.getLogger(AmpliPiHandlerFactory.class); + private HttpClient httpClient; + private AudioHTTPServer audioHttpServer; + private final NetworkAddressService networkAddressService; @Activate - public AmpliPiHandlerFactory(@Reference HttpClientFactory httpClientFactory) { + public AmpliPiHandlerFactory(@Reference HttpClientFactory httpClientFactory, + @Reference AudioHTTPServer audioHttpServer, @Reference NetworkAddressService networkAddressService) { this.httpClient = httpClientFactory.getCommonHttpClient(); + this.audioHttpServer = audioHttpServer; + this.networkAddressService = networkAddressService; } private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_CONTROLLER, THING_TYPE_ZONE, @@ -59,7 +71,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (THING_TYPE_CONTROLLER.equals(thingTypeUID)) { - return new AmpliPiHandler(thing, httpClient); + String callbackUrl = createCallbackUrl(); + return new AmpliPiHandler(thing, httpClient, audioHttpServer, callbackUrl); } if (THING_TYPE_ZONE.equals(thingTypeUID)) { return new AmpliPiZoneHandler(thing, httpClient); @@ -70,4 +83,21 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { return null; } + + private @Nullable String createCallbackUrl() { + final String ipAddress = networkAddressService.getPrimaryIpv4HostAddress(); + if (ipAddress == null) { + logger.warn("No network interface could be found."); + return null; + } + + // we do not use SSL as it can cause certificate validation issues. + final int port = HttpServiceUtil.getHttpServicePort(bundleContext); + if (port == -1) { + logger.warn("Cannot find port of the http service."); + return null; + } + + return "http://" + ipAddress + ":" + port; + } } diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiZoneHandler.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiZoneHandler.java index ff3ad20e3377e..252f4c3ebf747 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiZoneHandler.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/AmpliPiZoneHandler.java @@ -16,7 +16,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; @@ -90,7 +89,7 @@ private int getId(Thing thing) { } @Override - public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command command) { + public void handleCommand(ChannelUID channelUID, Command command) { if (command == RefreshType.REFRESH) { // do nothing - we just wait for the next automatic refresh return; @@ -133,7 +132,7 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma } @Override - public void receive(@NonNull Status status) { + public void receive(Status status) { int id = getId(thing); Optional zone = status.getZones().stream().filter(z -> z.getId().equals(id)).findFirst(); if (zone.isPresent()) { diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/audio/PAAudioSink.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/audio/PAAudioSink.java new file mode 100644 index 0000000000000..83438f396da5a --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/audio/PAAudioSink.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.amplipi.internal.audio; + +import java.io.IOException; +import java.util.Locale; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.amplipi.internal.AmpliPiHandler; +import org.openhab.core.audio.AudioFormat; +import org.openhab.core.audio.AudioSink; +import org.openhab.core.audio.AudioStream; +import org.openhab.core.audio.FixedLengthAudioStream; +import org.openhab.core.audio.URLAudioStream; +import org.openhab.core.audio.UnsupportedAudioFormatException; +import org.openhab.core.audio.UnsupportedAudioStreamException; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is an audio sink that allows to do public announcements on the AmpliPi. + * + * @author Kai Kreuzer - Initial contribution + * + */ +@NonNullByDefault +public class PAAudioSink implements AudioSink, ThingHandlerService { + + private final Logger logger = LoggerFactory.getLogger(PAAudioSink.class); + + private static final Set SUPPORTED_AUDIO_FORMATS = Set.of(AudioFormat.MP3, AudioFormat.WAV); + private static final Set> SUPPORTED_AUDIO_STREAMS = Set + .of(FixedLengthAudioStream.class, URLAudioStream.class); + + private @Nullable AmpliPiHandler handler; + + private @Nullable PercentType volume; + + @Override + public void process(@Nullable AudioStream audioStream) + throws UnsupportedAudioFormatException, UnsupportedAudioStreamException { + if (audioStream == null) { + // in case the audioStream is null, this should be interpreted as a request to end any currently playing + // stream. + logger.debug("Web Audio sink does not support stopping the currently playing stream."); + return; + } + AmpliPiHandler localHandler = this.handler; + if (localHandler != null) { + try (AudioStream stream = audioStream) { + logger.debug("Received audio stream of format {}", audioStream.getFormat()); + String audioUrl; + if (audioStream instanceof URLAudioStream) { + // it is an external URL, so we can directly pass this on. + URLAudioStream urlAudioStream = (URLAudioStream) audioStream; + audioUrl = urlAudioStream.getURL(); + } else if (audioStream instanceof FixedLengthAudioStream) { + String callbackUrl = localHandler.getCallbackUrl(); + if (callbackUrl == null) { + throw new UnsupportedAudioStreamException( + "Cannot play audio since no callback url is available.", audioStream.getClass()); + } else { + // we need to serve it for a while, hence only + // FixedLengthAudioStreams are supported. + String relativeUrl = localHandler.getAudioHTTPServer() + .serve((FixedLengthAudioStream) audioStream, 10).toString(); + audioUrl = callbackUrl + relativeUrl; + } + } else { + throw new UnsupportedAudioStreamException( + "Web audio sink can only handle FixedLengthAudioStreams and URLAudioStreams.", + audioStream.getClass()); + } + localHandler.playPA(audioUrl, volume); + // we reset the volume value again, so that a next invocation without a volume will again use the zones + // defaults. + volume = null; + } catch (IOException e) { + logger.debug("Error while closing the audio stream: {}", e.getMessage(), e); + } + } + } + + @Override + public Set getSupportedFormats() { + return SUPPORTED_AUDIO_FORMATS; + } + + @Override + public Set> getSupportedStreams() { + return SUPPORTED_AUDIO_STREAMS; + } + + @Override + public String getId() { + if (handler != null) { + return handler.getThing().getUID().toString(); + } else { + throw new IllegalStateException(); + } + } + + @Override + public @Nullable String getLabel(@Nullable Locale locale) { + if (handler != null) { + return handler.getThing().getLabel(); + } else { + return null; + } + } + + @Override + public PercentType getVolume() throws IOException { + PercentType vol = volume; + if (vol != null) { + return vol; + } else { + throw new IOException("Audio sink does not support reporting the volume."); + } + } + + @Override + public void setVolume(final PercentType volume) throws IOException { + this.volume = volume; + } + + @Override + public void setThingHandler(ThingHandler handler) { + this.handler = (AmpliPiHandler) handler; + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return handler; + } +} diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiMDNSDiscoveryParticipant.java index 129c1baff9c0a..0af6785c3d190 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiMDNSDiscoveryParticipant.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.amplipi.internal.discovery; +import java.net.InetAddress; import java.util.Set; import javax.jmdns.ServiceInfo; @@ -24,6 +25,7 @@ import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.annotations.Component; /** * This is a discovery participant which finds AmpliPis on the local network @@ -33,8 +35,11 @@ * */ @NonNullByDefault +@Component public class AmpliPiMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant { + private static final String AMPLIPI_API = "amplipi-api"; + @Override public Set getSupportedThingTypeUIDs() { return Set.of(AmpliPiBindingConstants.THING_TYPE_CONTROLLER); @@ -42,16 +47,15 @@ public Set getSupportedThingTypeUIDs() { @Override public String getServiceType() { - return "_http._tcp"; + return "_http._tcp.local."; } @Override public @Nullable DiscoveryResult createResult(ServiceInfo service) { ThingUID uid = getThingUID(service); if (uid != null) { - DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel(service.getName()) - .withProperty(AmpliPiBindingConstants.CFG_PARAM_HOSTNAME, - service.getInet4Addresses()[0].getHostAddress()) + DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel("AmpliPi Controller") + .withProperty(AmpliPiBindingConstants.CFG_PARAM_HOSTNAME, getIpAddress(service).getHostAddress()) .withRepresentationProperty(AmpliPiBindingConstants.CFG_PARAM_HOSTNAME).build(); return result; } else { @@ -61,7 +65,21 @@ public String getServiceType() { @Override public @Nullable ThingUID getThingUID(ServiceInfo service) { - // TODO: Currently, the AmpliPi does not seem to announce any services. + if (service.getName().equals(AMPLIPI_API)) { + InetAddress ip = getIpAddress(service); + if (ip != null) { + String id = ip.toString().substring(1).replaceAll("\\.", ""); + return new ThingUID(AmpliPiBindingConstants.THING_TYPE_CONTROLLER, id); + } + } return null; } + + private @Nullable InetAddress getIpAddress(ServiceInfo service) { + if (service.getInet4Addresses().length > 0) { + return service.getInet4Addresses()[0]; + } else { + return null; + } + } } diff --git a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiZoneAndGroupDiscoveryService.java b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiZoneAndGroupDiscoveryService.java index 5ebf8a3b26ce4..4b508a0d41a30 100644 --- a/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiZoneAndGroupDiscoveryService.java +++ b/bundles/org.openhab.binding.amplipi/src/main/java/org/openhab/binding/amplipi/internal/discovery/AmpliPiZoneAndGroupDiscoveryService.java @@ -78,7 +78,7 @@ private void createZone(Zone z) { if (handler != null) { ThingUID bridgeUID = handler.getThing().getUID(); ThingUID uid = new ThingUID(AmpliPiBindingConstants.THING_TYPE_ZONE, bridgeUID, z.getId().toString()); - DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel(z.getName()) + DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel("AmpliPi Zone '" + z.getName() + "'") .withProperty(AmpliPiBindingConstants.CFG_PARAM_ID, z.getId()).withBridge(bridgeUID) .withRepresentationProperty(AmpliPiBindingConstants.CFG_PARAM_ID).build(); thingDiscovered(result); @@ -89,7 +89,7 @@ private void createGroup(Group g) { if (handler != null) { ThingUID bridgeUID = handler.getThing().getUID(); ThingUID uid = new ThingUID(AmpliPiBindingConstants.THING_TYPE_GROUP, bridgeUID, g.getId().toString()); - DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel(g.getName()) + DiscoveryResult result = DiscoveryResultBuilder.create(uid).withLabel("AmpliPi Group '" + g.getName() + "'") .withProperty(AmpliPiBindingConstants.CFG_PARAM_ID, g.getId()).withBridge(bridgeUID) .withRepresentationProperty(AmpliPiBindingConstants.CFG_PARAM_ID).build(); thingDiscovered(result); From 5302e1d298af9008c11cdcddbec88994e24e8862 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Mon, 22 Nov 2021 00:58:03 +0100 Subject: [PATCH 130/361] New Crowdin updates (#11608) * New translations openhabcloud.properties (French) * New translations transform.properties (French) * New translations voicerss.properties (French) * New translations actions.properties (German) * New translations errors.properties (German) * New translations stateflags.properties (German) * New translations nanoleaf.properties (German) * New translations surepetcare.properties (German) * New translations deconz.properties (German) * New translations tr064.properties (German) * New translations deconz.properties (German) * New translations openhabcloud.properties (German) * New translations astro.properties (French) * New translations hue.properties (French) * New translations ntp.properties (French) * New translations feed.properties (German) * New translations lgwebos.properties (French) * New translations gce.properties (French) * New translations airquality.properties (French) * New translations airquality.properties (French) * New translations rotel.properties (French) * New translations feed.properties (German) * New translations hue.properties (French) * New translations mail.properties (German) * New translations sonyprojector.properties (French) * New translations tradfri.properties (French) * New translations powermax.properties (French) Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/airquality_fr.properties | 16 +- .../resources/OH-INF/i18n/astro_fr.properties | 100 ++++----- .../OH-INF/i18n/deconz_de.properties | 189 +++++++++++++++++- .../resources/OH-INF/i18n/feed_de.properties | 41 ++++ .../resources/OH-INF/i18n/gce_fr.properties | 18 +- .../resources/OH-INF/i18n/hue_fr.properties | 167 +++++++++++++--- .../OH-INF/i18n/lgwebos_fr.properties | 4 +- .../resources/OH-INF/i18n/mail_de.properties | 2 +- .../OH-INF/i18n/actions_de.properties | 2 - .../OH-INF/i18n/errors_de.properties | 52 ++--- .../OH-INF/i18n/stateflags_de.properties | 18 +- .../OH-INF/i18n/nanoleaf_de.properties | 6 +- .../resources/OH-INF/i18n/ntp_fr.properties | 6 +- .../OH-INF/i18n/powermax_fr.properties | 58 +++--- .../resources/OH-INF/i18n/rotel_fr.properties | 80 ++++---- .../OH-INF/i18n/sonyprojector_fr.properties | 64 +++--- .../OH-INF/i18n/surepetcare_de.properties | 10 +- .../resources/OH-INF/i18n/tr064_de.properties | 2 +- .../OH-INF/i18n/tradfri_fr.properties | 14 +- .../OH-INF/i18n/openhabcloud_de.properties | 4 +- .../OH-INF/i18n/openhabcloud_fr.properties | 14 ++ .../OH-INF/i18n/transform_fr.properties | 6 + .../OH-INF/i18n/voicerss_fr.properties | 8 + 23 files changed, 612 insertions(+), 269 deletions(-) create mode 100644 bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed_de.properties create mode 100644 bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties create mode 100644 bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties create mode 100644 bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_fr.properties diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties index 4ffa7a1877bf5..3dd0892af31d1 100644 --- a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties @@ -5,8 +5,8 @@ binding.airquality.description = Indice de qualité de l'air et informations sur # thing types thing-type.airquality.api.label = API Air Quality thing-type.airquality.api.description = Passerelle vers le service de données Air Quality. -thing-type.airquality.station.label = Qualité de l'air -thing-type.airquality.station.description = Fournit diverses données sur la qualité de l'air du World Air Quality Project. Pour recevoir les données, vous devez créer un compte sur http\://aqicn.org/data-platform/token/ pour obtenir votre token API. +thing-type.airquality.station.label = Station Qualité Air +thing-type.airquality.station.description = Fournit diverses données sur la qualité de l'air du projet World Air Quality. Pour recevoir les données, vous devez créer un compte sur http\://aqicn.org/data-platform/token/ pour obtenir votre token API. # thing types config thing-type.config.airquality.api.apiKey.label = Clé API @@ -16,21 +16,21 @@ thing-type.config.airquality.station.location.description = Coordonnées géogra thing-type.config.airquality.station.stationId.label = ID Station thing-type.config.airquality.station.stationId.description = Renseignez cette valeur si vous souhaitez les données d'une station spécifique. thing-type.config.airquality.station.refresh.label = Période de mise à jour -thing-type.config.airquality.station.refresh.description = Définisser l'intervalle de mise à jour en minutes. +thing-type.config.airquality.station.refresh.description = Définissez l'intervalle de mise à jour en minutes. # Channel groups labels -pm25ChannelGroupLabel = PM 2.5 - Particules de diametre inférieur à 2.5 µm. +pm25ChannelGroupLabel = PM 2.5 - Particules de diamètre inférieur à 2.5 µm. pm10ChannelGroupLabel = PM 10 - Particules fines de poussière. no2ChannelGroupLabel = NO2 - Dioxyde d'azote. so2ChannelGroupLabel = SO2 - Dioxyde de soufre. coChannelGroupLabel = CO - Monoxyde de carbone. o3ChannelGroupLabel = O3 - Ozone. aqiChannelGroupLabel = AQI - Indice Global de Qualité de l'Air. -weatherChannelGroupLabel = Données Méteo. +weatherChannelGroupLabel = Données Météorologiques # Channel types labels -timestampChannelLabel = Horodatage -timestampChannelDescription = Date et heure des oObservations. +timestampChannelLabel = Horodatage Observation +timestampChannelDescription = Date et heure des observations. dominentChannelLabel = Polluant Principal dewPointLabel = Température de Rosée dewPointDescription = Température du point de Rosée. @@ -50,7 +50,7 @@ alertLevelOption3 = Mauvaise alertLevelOption4 = Très mauvaise alertLevelOption5 = Dangereuse -pollutantPm25 = Particules de diametre inférieur à 2.5 µm. +pollutantPm25 = Particules de diamètre inférieur à 2.5 µm pollutantPm10 = Particules fines de poussière. pollutantO3 = Ozone pollutantNO2 = Dioxyde d'azote. diff --git a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties index 08c19861f1223..32fc35e2c4d8f 100644 --- a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties +++ b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties @@ -3,41 +3,41 @@ binding.astro.name = Extension Astro binding.astro.description = L'extension Astro calcule les données astronomiques du soleil et de la lune. # thing types -thing-type.astro.sun.label = Données astro du soleil +thing-type.astro.sun.label = Données Astro du Soleil thing-type.astro.sun.description = Fournit des données astronomiques du soleil -thing-type.astro.sun.group.rise.label = Lever du soleil +thing-type.astro.sun.group.rise.label = Lever thing-type.astro.sun.group.rise.description = La période de lever du soleil -thing-type.astro.sun.group.set.label = Coucher du soleil +thing-type.astro.sun.group.set.label = Coucher thing-type.astro.sun.group.set.description = La période de coucher du soleil -thing-type.astro.sun.group.noon.label = Midi solaire +thing-type.astro.sun.group.noon.label = Midi thing-type.astro.sun.group.noon.description = La période du midi solaire -thing-type.astro.sun.group.night.label = Minuit solaire +thing-type.astro.sun.group.night.label = Minuit thing-type.astro.sun.group.night.description = La période du minuit solaire -thing-type.astro.sun.group.morningNight.label = Nuit du matin +thing-type.astro.sun.group.morningNight.label = Nuit du Matin thing-type.astro.sun.group.morningNight.description = La période de nuit du matin -thing-type.astro.sun.group.astroDawn.label = Aube astronomique +thing-type.astro.sun.group.astroDawn.label = Aube Astronomique thing-type.astro.sun.group.astroDawn.description = La période d'aube astronomique -thing-type.astro.sun.group.nauticDawn.label = Aube nautique +thing-type.astro.sun.group.nauticDawn.label = Aube Nautique thing-type.astro.sun.group.nauticDawn.description = La période d'aube nautique -thing-type.astro.sun.group.civilDawn.label = Aube civile +thing-type.astro.sun.group.civilDawn.label = Aube Civile thing-type.astro.sun.group.civilDawn.description = La période d'aube civile -thing-type.astro.sun.group.astroDusk.label = Crépuscule astronomique +thing-type.astro.sun.group.astroDusk.label = Crépuscule Astronomique thing-type.astro.sun.group.astroDusk.description = La période de crépuscule astronomique -thing-type.astro.sun.group.nauticDusk.label = Crépuscule nautique +thing-type.astro.sun.group.nauticDusk.label = Crépuscule Nautique thing-type.astro.sun.group.nauticDusk.description = La période de crépuscule nautique -thing-type.astro.sun.group.civilDusk.label = Crépuscule civil +thing-type.astro.sun.group.civilDusk.label = Crépuscule Civil thing-type.astro.sun.group.civilDusk.description = La période de crépuscule civil -thing-type.astro.sun.group.eveningNight.label = Nuit du soir +thing-type.astro.sun.group.eveningNight.label = Nuit du Soir thing-type.astro.sun.group.eveningNight.description = La période de nuit du soir -thing-type.astro.sun.group.daylight.label = Plein jour +thing-type.astro.sun.group.daylight.label = Plein Jour thing-type.astro.sun.group.daylight.description = La période de plein jour thing-type.astro.sun.group.position.description = La position du soleil -thing-type.astro.moon.label = Données astro de lune +thing-type.astro.moon.label = Données Astro de Lune thing-type.astro.moon.description = Fournit des données astronomiques de la lune -thing-type.astro.moon.group.rise.label = Lever de lune +thing-type.astro.moon.group.rise.label = Lever thing-type.astro.moon.group.rise.description = La période de lever de lune -thing-type.astro.moon.group.set.label = Coucher de lune +thing-type.astro.moon.group.set.label = Coucher thing-type.astro.moon.group.set.description = La période de coucher de lune thing-type.astro.moon.group.distance.description = Distance de la lune thing-type.astro.moon.group.perigee.label = Périgée @@ -67,9 +67,9 @@ channel-group-type.astro.position.label = Position channel-group-type.astro.position.description = La position de la planète channel-group-type.astro.radiation.label = Rayonnement channel-group-type.astro.radiation.description = Le niveau de rayonnement du soleil -channel-group-type.astro.sunRange.label = Période du soleil +channel-group-type.astro.sunRange.label = Période channel-group-type.astro.sunRange.description = Une période du soleil -channel-group-type.astro.moonRange.label = Période de la lune +channel-group-type.astro.moonRange.label = Période channel-group-type.astro.moonRange.description = Une période de la lune channel-group-type.astro.sunZodiac.label = Zodiaque channel-group-type.astro.sunZodiac.description = Le zodiaque du soleil @@ -77,9 +77,9 @@ channel-group-type.astro.season.label = Saison channel-group-type.astro.season.description = La saison de l'année channel-group-type.astro.sunEclipse.label = Éclipses channel-group-type.astro.sunEclipse.description = La date et l'heure des prochaines éclipses solaires -channel-group-type.astro.sunPhase.label = Phase solaire +channel-group-type.astro.sunPhase.label = Phase Solaire channel-group-type.astro.sunPhase.description = Les détails de la phase solaire actuelle -channel-group-type.astro.moonPhase.label = Phase lunaire +channel-group-type.astro.moonPhase.label = Phase Lunaire channel-group-type.astro.moonPhase.description = Les détails des phases lunaires actuelle et suivante channel-group-type.astro.moonEclipse.label = Éclipses channel-group-type.astro.moonEclipse.description = La date et l'heure des prochaines éclipses lunaires @@ -88,9 +88,9 @@ channel-group-type.astro.distance.description = Données de distance channel-group-type.astro.moonZodiac.label = Zodiaque channel-group-type.astro.moonZodiac.description = Le zodiaque de la lune -channel-group-type.astro.moonEclipse.channel.total.label = Eclipse lunaire totale +channel-group-type.astro.moonEclipse.channel.total.label = Eclipse Lunaire Totale channel-group-type.astro.moonEclipse.channel.total.description = La date et l'heure de la prochaine éclipse lunaire totale -channel-group-type.astro.moonEclipse.channel.partial.label = Eclipse lunaire partielle +channel-group-type.astro.moonEclipse.channel.partial.label = Eclipse Lunaire Partielle channel-group-type.astro.moonEclipse.channel.partial.description = La date et l'heure de la prochaine éclipse lunaire partielle # channel types @@ -98,17 +98,17 @@ channel-type.astro.azimuth.label = Azimut channel-type.astro.azimuth.description = L'azimut de la planète channel-type.astro.elevation.label = Élévation channel-type.astro.elevation.description = L'élévation de la planète -channel-type.astro.shadeLength.label = Ratio de longueur d'ombre +channel-type.astro.shadeLength.label = Ratio Longueur Ombre channel-type.astro.shadeLength.description = Le ratio de longueur de l'ombre projetée (dérivé de l'altitude) -channel-type.astro.directRadiation.label = Rayonnement direct +channel-type.astro.directRadiation.label = Rayonnement Direct channel-type.astro.directRadiation.description = Le niveau de rayonnement après pénétration de la couche atmosphérique -channel-type.astro.diffuseRadiation.label = Rayonnement diffus +channel-type.astro.diffuseRadiation.label = Rayonnement Diffus channel-type.astro.diffuseRadiation.description = Le niveau de rayonnement diffusé par les nuages et l'atmosphère -channel-type.astro.totalRadiation.label = Rayonnement total +channel-type.astro.totalRadiation.label = Rayonnement Total channel-type.astro.totalRadiation.description = Quantité totale de rayonnement au sol -channel-type.astro.start.label = Heure de début +channel-type.astro.start.label = Heure Début channel-type.astro.start.description = L'heure de début de l'événement -channel-type.astro.end.label = Heure de fin +channel-type.astro.end.label = Heure Fin channel-type.astro.end.description = L'heure de fin de l'événement channel-type.astro.duration.label = Durée channel-type.astro.duration.description = La durée de l'événement @@ -126,7 +126,7 @@ channel-type.astro.sign.state.option.SAGITTARIUS = Sagittaire channel-type.astro.sign.state.option.CAPRICORN = Capricorne channel-type.astro.sign.state.option.AQUARIUS = Verseau channel-type.astro.sign.state.option.PISCES = Poissons -channel-type.astro.seasonName.label = Nom de la saison +channel-type.astro.seasonName.label = Nom Saison channel-type.astro.seasonName.description = Le nom de la saison en cours channel-type.astro.seasonName.state.option.SPRING = Printemps channel-type.astro.seasonName.state.option.SUMMER = Été @@ -140,13 +140,13 @@ channel-type.astro.autumn.label = Automne channel-type.astro.autumn.description = Le début de l'automne channel-type.astro.winter.label = Hiver channel-type.astro.winter.description = Le début de l'hiver -channel-type.astro.total.label = Eclipse totale +channel-type.astro.total.label = Eclipse Totale channel-type.astro.total.description = La date et l'heure de la prochaine éclipse totale -channel-type.astro.partial.label = Éclipse partielle +channel-type.astro.partial.label = Éclipse Partielle channel-type.astro.partial.description = La date et l'heure de la prochaine éclipse partielle -channel-type.astro.ring.label = Éclipse annulaire +channel-type.astro.ring.label = Éclipse Annulaire channel-type.astro.ring.description = La date et l'heure de la prochaine éclipse annulaire -channel-type.astro.sunPhaseName.label = Nom de la phase solaire +channel-type.astro.sunPhaseName.label = Nom Phase Solaire channel-type.astro.sunPhaseName.description = Le nom de la phase solaire actuelle channel-type.astro.sunPhaseName.state.option.SUN_RISE = Lever du soleil channel-type.astro.sunPhaseName.state.option.ASTRO_DAWN = Aube Astronomique @@ -159,23 +159,23 @@ channel-type.astro.sunPhaseName.state.option.SUN_SET = Coucher du soleil channel-type.astro.sunPhaseName.state.option.DAYLIGHT = Plein jour channel-type.astro.sunPhaseName.state.option.NOON = Midi channel-type.astro.sunPhaseName.state.option.NIGHT = Nuit -channel-type.astro.firstQuarter.label = Premier quartier +channel-type.astro.firstQuarter.label = Premier Quartier channel-type.astro.firstQuarter.description = La date et l'heure d'atteinte du premier quartier de lune -channel-type.astro.thirdQuarter.label = Troisième quartier +channel-type.astro.thirdQuarter.label = Troisième Quartier channel-type.astro.thirdQuarter.description = La date et l'heure d'atteinte du troisième quartier de lune -channel-type.astro.fullMoon.label = Pleine lune +channel-type.astro.fullMoon.label = Pleine Lune channel-type.astro.fullMoon.description = Horodatage de la pleine lune channel-type.astro.newMoon.label = Nouvelle Lune channel-type.astro.newMoon.description = Horodatage de la nouvelle lune -channel-type.astro.age.label = Âge de la Lune +channel-type.astro.age.label = Âge Lune channel-type.astro.age.description = L'âge de la lune en jours -channel-type.astro.ageDegree.label = Âge de la Lune +channel-type.astro.ageDegree.label = Âge Lune channel-type.astro.ageDegree.description = L'âge de la lune en degrés -channel-type.astro.agePercent.label = Âge de la Lune +channel-type.astro.agePercent.label = Âge Lune channel-type.astro.agePercent.description = L'âge de la lune en pourcentage -channel-type.astro.illumination.label = Illumination de la Lune +channel-type.astro.illumination.label = Illumination Lune channel-type.astro.illumination.description = L'illumination de la lune -channel-type.astro.phaseName.label = Nom de la phase lunaire +channel-type.astro.phaseName.label = Nom Phase Lunaire channel-type.astro.phaseName.description = Le nom de la phase lunaire actuelle channel-type.astro.phaseName.state.option.NEW = Nouvelle lune channel-type.astro.phaseName.state.option.WAXING_CRESCENT = Premier croissant @@ -187,17 +187,17 @@ channel-type.astro.phaseName.state.option.THIRD_QUARTER = Troisième quartier channel-type.astro.phaseName.state.option.WANING_CRESCENT = Dernier croissant channel-type.astro.distanceDate.label = Date channel-type.astro.distanceDate.description = La date et l'heure lorsque la distance est atteinte -channel-type.astro.distance.label = Distance  +channel-type.astro.distance.label = Distance channel-type.astro.distance.description = La distance de l'objet -channel-type.astro.rangeEvent.label = Événement d'une période +channel-type.astro.rangeEvent.label = Événement Période channel-type.astro.rangeEvent.description = L'évènement d'une période -channel-type.astro.sunEclipseEvent.label = Événement éclipse solaire +channel-type.astro.sunEclipseEvent.label = Événement Eclipse Solaire channel-type.astro.sunEclipseEvent.description = Événement d'éclipse solaire -channel-type.astro.phaseEvent.label = Événement phase lunaire +channel-type.astro.phaseEvent.label = Événement Phase Lunaire channel-type.astro.phaseEvent.description = Événement de phase lunaire -channel-type.astro.moonEclipseEvent.label = Événement éclipse lunaire +channel-type.astro.moonEclipseEvent.label = Événement Eclipse Lunaire channel-type.astro.moonEclipseEvent.description = Événement d'éclipse lunaire -channel-type.astro.distanceEvent.label = Événement distance de lune +channel-type.astro.distanceEvent.label = Événement Distance Lune channel-type.astro.distanceEvent.description = Événement de distance de lune # channel types config @@ -211,5 +211,5 @@ channel-type.config.astro.config.latest.label = Au plus tard channel-type.config.astro.config.latest.description = La dernière heure de la journée pour l'événement ou la valeur de la date (hh\:mm). # Discovery result -discovery.astro.sun.local.label = Soleil depuis l'emplacement local -discovery.astro.moon.local.label = Lune depuis l'emplacement local +discovery.astro.sun.local.label = Soleil Depuis Emplacement Local +discovery.astro.moon.local.label = Lune Depuis Emplacement Local diff --git a/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties index e4363e1f2b56f..d50738216ae4b 100644 --- a/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties +++ b/bundles/org.openhab.binding.deconz/src/main/resources/OH-INF/i18n/deconz_de.properties @@ -1,21 +1,192 @@ # binding + binding.deconz.name = Dresden Elektronik deCONZ Binding -binding.deconz.description = Unterstützt die Raspbee und Conbee Zigbee Dongles via deCONZ +binding.deconz.description = Unterstützt die Raspbee und Conbee Zigbee Dongles via deCONZ. + +# thing types +thing-type.deconz.alarmsensor.label = Alarmsensor +thing-type.deconz.alarmsensor.description = Ein Alarmsensor +thing-type.deconz.batterysensor.label = Batteriesensor +thing-type.deconz.batterysensor.description = Ein Batteriesensor +thing-type.deconz.carbonmonoxidesensor.label = Kohlenmonoxid-Sensor +thing-type.deconz.colorcontrol.label = Farbregler +thing-type.deconz.colorlight.label = Farbige Lampe +thing-type.deconz.colorlight.description = Dimmbare Lampe mit einstellbarer Farbe. +thing-type.deconz.colortemperaturelight.label = Farbtemperatur Lampe (weiß) +thing-type.deconz.colortemperaturelight.description = Dimmbare Lampe mit einstellbarer Farbtemperatur. +thing-type.deconz.consumptionsensor.label = Verbrauchssensor +thing-type.deconz.consumptionsensor.description = Ein Verbrauchssensor +thing-type.deconz.daylightsensor.label = Tageslicht-Sensor +thing-type.deconz.daylightsensor.description = Ein Tageslicht-Sensor +thing-type.deconz.deconz.label = deCONZ-Gateway +thing-type.deconz.deconz.description = Ein deCONZ-Gateway +thing-type.deconz.dimmablelight.label = Dimmbare Lampe (weiß) +thing-type.deconz.dimmablelight.description = Dimmbare Lampe mit fester Farbtemperatur. +thing-type.deconz.doorlock.label = Türschloss +thing-type.deconz.doorlock.description = Ein Türschloss, welches gesperrt (ON) oder entsperrt werden kann (OFF). +thing-type.deconz.extendedcolorlight.label = Farbige Lampe +thing-type.deconz.extendedcolorlight.description = Dimmbare Lampe mit einstellbarer Farbe. +thing-type.deconz.firesensor.label = Feuermelder +thing-type.deconz.firesensor.description = Ein Feuermelder +thing-type.deconz.humiditysensor.label = Luftfeuchtigkeitssensor +thing-type.deconz.humiditysensor.description = Ein Luftfeuchtigkeitssensor +thing-type.deconz.lightgroup.label = Gruppe +thing-type.deconz.lightsensor.label = Lichtsensor +thing-type.deconz.lightsensor.description = Ein Lichtsensor +thing-type.deconz.onofflight.label = Lampe (weiß) +thing-type.deconz.onofflight.description = Ein Licht, das eingeschaltet oder ausgeschaltet werden kann. +thing-type.deconz.openclosesensor.label = Offen/Geschlossen-Sensor +thing-type.deconz.openclosesensor.description = Ein Offen/Geschlossen-Sensor +thing-type.deconz.powersensor.label = Leistungssensor +thing-type.deconz.powersensor.description = Ein Leistungssensor thing-type.deconz.presencesensor.label = Bewegungsmelder thing-type.deconz.presencesensor.description = Bewegungsmelder mit einstellbarer Sensitivität. +thing-type.deconz.pressuresensor.label = Drucksensor +thing-type.deconz.pressuresensor.description = Ein Drucksensor +thing-type.deconz.switch.label = Schalter/Taster +thing-type.deconz.switch.description = Ein Schalter oder Taster +thing-type.deconz.temperaturesensor.label = Temperatursensor +thing-type.deconz.temperaturesensor.description = Ein Temperatursensor +thing-type.deconz.thermostat.label = Thermostat +thing-type.deconz.thermostat.description = Ein Thermostat +thing-type.deconz.vibrationsensor.label = Vibrationssensor +thing-type.deconz.vibrationsensor.description = Ein Vibrationssensor +thing-type.deconz.warningdevice.label = Warnmelder +thing-type.deconz.warningdevice.description = Ein Warnmelder +thing-type.deconz.waterleakagesensor.label = Wasserleck-Sensor +thing-type.deconz.waterleakagesensor.description = Ein Wasserleck-Sensor +thing-type.deconz.windowcovering.label = Fensterabdeckung +thing-type.deconz.windowcovering.description = Eine Vorrichtung zum Abdecken von Fenstern +# thing types config + +thing-type.config.deconz.bridge.apikey.label = API-Schlüssel +thing-type.config.deconz.bridge.apikey.description = Wenn kein API-Schlüssel angegeben wird, wird ein neuer angefordert. Sie müssen den Zugriff auf die deCONZ HTTP-Schnittstelle autorisieren. +thing-type.config.deconz.bridge.host.label = IP-Adresse +thing-type.config.deconz.bridge.host.description = IP-Adresse oder Hostname des deCONZ-Gateways. +thing-type.config.deconz.bridge.httpPort.label = HTTP-Port +thing-type.config.deconz.bridge.httpPort.description = Port der deCONZ HTTP-Schnittstelle +thing-type.config.deconz.bridge.port.label = Websocket-Port +thing-type.config.deconz.bridge.port.description = Port des deCONZ Websockets. +thing-type.config.deconz.bridge.timeout.label = Timeout +thing-type.config.deconz.bridge.timeout.description = Timeout für asynchrone HTTP-Abfragen der deCONZ API (in Millisekunden). +thing-type.config.deconz.colorlight.colormode.label = Farbmodus +thing-type.config.deconz.colorlight.colormode.description = Überschreibt den Standard-Farbmodus (Auto-Erkennung). +thing-type.config.deconz.colorlight.colormode.option.hs = HSB +thing-type.config.deconz.colorlight.colormode.option.xy = XY +thing-type.config.deconz.colorlight.id.label = ID der Lampe +thing-type.config.deconz.colorlight.id.description = ID zur Identifikation der Lampe. +thing-type.config.deconz.colorlight.transitiontime.label = Überblendzeit +thing-type.config.deconz.colorlight.transitiontime.description = Zeit für den Übergang zwischen zwei Zuständen. Wenn leer, dann wird die Voreinstellung des Geräts verwendet. Die Auflösung beträgt 1/10 Sekunden. +thing-type.config.deconz.light.id.label = ID der Lampe +thing-type.config.deconz.light.id.description = ID zur Identifikation der Lampe. +thing-type.config.deconz.light.transitiontime.label = Überblendzeit +thing-type.config.deconz.light.transitiontime.description = Zeit für den Übergang zwischen zwei Zuständen. Wenn leer, dann wird die Voreinstellung des Geräts verwendet. Die Auflösung beträgt 1/10 Sekunden. +thing-type.config.deconz.lightgroup.colormode.label = Farbmodus +thing-type.config.deconz.lightgroup.colormode.description = Überschreibt den Standard-Farbmodus (Auto-Erkennung). +thing-type.config.deconz.lightgroup.colormode.option.hs = HSB +thing-type.config.deconz.lightgroup.colormode.option.xy = XY +thing-type.config.deconz.lightgroup.id.label = ID der Gruppe +thing-type.config.deconz.lightgroup.id.description = ID zur Identifikation des Gruppe. thing-type.config.deconz.sensor.id.label = ID des Sensors thing-type.config.deconz.sensor.id.description = ID zur Identifikation des Sensors. thing-type.config.deconz.sensor.lastSeenPolling.label = Abfrageintervall -thing-type.config.deconz.sensor.lastSeenPolling.description = Intervall zur Abfrage des deCONZ-Gateways nach dem "last_seen" Channel dieses Sensors. Polling wird deaktiviert, wenn der Wert auf 0 eingestellt wird (Standard: 1440, einmal pro Tag). +thing-type.config.deconz.sensor.lastSeenPolling.description = Intervall zur Abfrage des deCONZ-Gateways nach dem "last_seen" Channel dieses Sensors. Polling wird deaktiviert, wenn der Wert auf 0 eingestellt wird (Standard\: 1440, einmal pro Tag). -channel-type.deconz.ct.label = Farbtemperatur -channel-type.deconz.ct.description = Steuert die Farbtemperatur des Lichts in Kelvin. +# channel types -channel-type.deconz.last_updated.label = Letzte Aktualisierung -channel-type.deconz.last_updated.description = Zeit, zu der sich dieser Wert geändert hat. -channel-type.deconz.last_updated.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS +channel-type.deconz.alarm.label = Alarm +channel-type.deconz.alarm.description = Zeigt an, wenn ein Alarm ausgelöst wurde. +channel-type.deconz.alert.label = Alert +channel-type.deconz.alert.command.option.none = Kein Blinken +channel-type.deconz.alert.command.option.select = Einmaliges Blinken +channel-type.deconz.alert.command.option.lselect = Mehrfaches Blinken +channel-type.deconz.all_on.label = Alle An +channel-type.deconz.all_on.description = Zeigt "ON" an, wenn alle Lampen in dieser Gruppe "ON" sind, sonst "OFF". +channel-type.deconz.any_on.label = Eine An +channel-type.deconz.any_on.description = Zeigt "ON" an, wenn mindestens eine Lampe in dieser Gruppe "ON" ist, sonst "OFF". +channel-type.deconz.button.label = Schaltfläche +channel-type.deconz.button.description = Zeigt die Schaltfläche an, welche zuletzt auf dem Schalter oder Taster gedrückt wurde. +channel-type.deconz.buttonevent.label = Schaltflächen-Trigger +channel-type.deconz.buttonevent.description = Dieser Channel wird bei Bestätigung einer Schaltfläche ausgelöst. Der Trigger-Payload besteht aus der Nummer der Schaltfläche. +channel-type.deconz.carbonmonoxide.label = Kohlenmonoxid +channel-type.deconz.carbonmonoxide.description = Zeigt an, ob ein erhöhter Kohlenmonoxid-Wert erkannt wurde. +channel-type.deconz.consumption.label = Verbrauch +channel-type.deconz.consumption.description = Zeigt den aktuellen Verbrauch an. +channel-type.deconz.ct.label = Farbtemperatur +channel-type.deconz.ct.description = Steuert die Farbtemperatur des Lichts (in Kelvin). +channel-type.deconz.current.label = Stromstärke +channel-type.deconz.current.description = Zeigt die aktuelle Stromstärke an. +channel-type.deconz.dark.label = Dunkel +channel-type.deconz.dark.description = Das Licht Level ist unter dem Dunkel-Schwellwert. +channel-type.deconz.daylight.label = Hell +channel-type.deconz.daylight.description = Das Licht Level ist über dem Hell-Schwellwert. +channel-type.deconz.effect.label = Farbeffekt +channel-type.deconz.effectSpeed.label = Geschwindigkeit für Farbeffekt +channel-type.deconz.fire.label = Feuer +channel-type.deconz.fire.description = Zeigt an, ob ein Feuer erkannt wurde. +channel-type.deconz.gesture.label = Geste +channel-type.deconz.gesture.description = Zeigt die Geste an, die durch Betätigung des Schalters oder Tasters ausgelöst wurde. +channel-type.deconz.gesture.state.option.0 = Keine +channel-type.deconz.gesture.state.option.1 = Schütteln +channel-type.deconz.gesture.state.option.2 = Fallen +channel-type.deconz.gesture.state.option.3 = Drehung 90° +channel-type.deconz.gesture.state.option.4 = Drehung 180° +channel-type.deconz.gesture.state.option.5 = Drücken +channel-type.deconz.gesture.state.option.6 = Doppeltippen +channel-type.deconz.gesture.state.option.7 = Im Uhrzeigersinn Drehen +channel-type.deconz.gesture.state.option.8 = Gegen den Uhrzeigersinn Drehen +channel-type.deconz.gestureevent.label = Gesten-Trigger +channel-type.deconz.gestureevent.description = Dieser Channel wird bei einer erkannten Geste ausgelöst. Der Trigger-Payload besteht aus dem Namen der Geste. +channel-type.deconz.heatsetpoint.label = Solltemperatur +channel-type.deconz.heatsetpoint.description = Steuert die Solltemperatur des Heizkörperreglers. +channel-type.deconz.humidity.label = Luftfeuchtigkeit +channel-type.deconz.humidity.description = Zeigt die aktuelle Luftfeuchtigkeit an. channel-type.deconz.last_seen.label = Zuletzt Gesehen -channel-type.deconz.last_seen.description = Zeit, zu der sich dieser Wert geändert hat. -channel-type.deconz.last_seen.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS +channel-type.deconz.last_seen.description = Zeigt die Zeit an, zu der dieser Sensor zuletzt gesehen wurde. +channel-type.deconz.last_seen.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.deconz.last_updated.label = Letzte Aktualisierung +channel-type.deconz.last_updated.description = Zeigt die Zeit, zu der sich dieser Wert zuletzt geändert hat. +channel-type.deconz.last_updated.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.deconz.light.label = Licht Level +channel-type.deconz.light.description = Zeigt das aktuelle Licht Level an. +channel-type.deconz.light.state.option.daylight = Tageslicht +channel-type.deconz.light.state.option.sunset = Sonnenuntergang +channel-type.deconz.light.state.option.dark = Dunkel +channel-type.deconz.light_level.label = Licht Level +channel-type.deconz.light_level.description = Zeigt das aktuelle Licht Level an. +channel-type.deconz.lightlux.label = Beleuchtungsstärke +channel-type.deconz.lightlux.description = Zeigt die aktuelle Beleuchtungsstärke an. +channel-type.deconz.lock.label = Schloss +channel-type.deconz.mode.label = Modus des Heizkörperreglers +channel-type.deconz.mode.description = Steuert den aktuellen Modus des Heizkörperreglers (AUTO, HEAT, OFF). +channel-type.deconz.mode.state.option.AUTO = Automatisch +channel-type.deconz.mode.state.option.HEAT = Heizen +channel-type.deconz.mode.state.option.OFF = Aus +channel-type.deconz.offset.label = Versatz +channel-type.deconz.offset.description = Temperaturversatz +channel-type.deconz.ontime.label = Dauer +channel-type.deconz.ontime.description = Steuert die Dauer, welche die Lampe eingeschaltet bleibt, bevor sie automatisch ausgeschaltet wird (0\=für immer an). +channel-type.deconz.open.label = Offen/Geschlossen +channel-type.deconz.open.description = Zeigt an, ob Offen oder Geschlossen erkannt wurde. +channel-type.deconz.position.label = Position +channel-type.deconz.power.label = Leistung +channel-type.deconz.power.description = Zeigt die aktuelle Leistung an. +channel-type.deconz.pressure.label = Druck +channel-type.deconz.pressure.description = Zeigt den aktuellen Druck an. +channel-type.deconz.scene.label = Szene +channel-type.deconz.tampered.label = Bereich Manipuliert +channel-type.deconz.tampered.description = Zeigt an, ob ein Bereich manipuliert wurde. +channel-type.deconz.temperature.label = Temperatur +channel-type.deconz.temperature.description = Zeigt die aktuelle Temperatur an. +channel-type.deconz.value.label = Tageslicht Wert +channel-type.deconz.value.description = Zeigt den Tageslicht Wert an. Der Wert für Morgendämmerung ist etwa 130, Sonnenaufgang 140, Sonnenuntergang 190 und Dämmerung 210. +channel-type.deconz.valve.label = Ventilposition +channel-type.deconz.valve.description = Zeigt die aktuelle Ventilposition des Heizkörperreglers an. +channel-type.deconz.vibration.label = Vibration +channel-type.deconz.vibration.description = Zeigt an, ob eine Vibration erkannt wurde. +channel-type.deconz.voltage.label = Spannung +channel-type.deconz.voltage.description = Zeigt die aktuelle Spannung an. +channel-type.deconz.waterleakage.label = Wasseraustritt +channel-type.deconz.waterleakage.description = Zeigt an, ob ein Wasseraustritt erkannt wurde. diff --git a/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed_de.properties b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed_de.properties new file mode 100644 index 0000000000000..a5881ed7b7531 --- /dev/null +++ b/bundles/org.openhab.binding.feed/src/main/resources/OH-INF/i18n/feed_de.properties @@ -0,0 +1,41 @@ +# binding + +binding.feed.name = Feed Binding +binding.feed.description = Das Feed Binding ermöglicht es einen RSS-Feed einer Webseite zu abonnieren. Durch ein solches Abonnement wird man automatisch informiert, wenn die Inhalte dieser Webseite aktualisiert werden. + +# thing types + +thing-type.feed.feed.label = RSS-Feed +thing-type.feed.feed.description = Ermöglicht das Abbonieren eines RSS-Feed und zeigt die angerufenen Informationen an. + +# thing types config + +thing-type.config.feed.feed.URL.label = URL +thing-type.config.feed.feed.URL.description = URL des RSS-Feed. +thing-type.config.feed.feed.refresh.label = Abfrageintervall +thing-type.config.feed.feed.refresh.description = Intervall zur Abfrage des RSS-Feed (in Minuten). + +# channel types + +channel-type.feed.author.label = Autor +channel-type.feed.author.description = Zeigt den Autor des RSS-Feed an. +channel-type.feed.description.label = Beschreibung +channel-type.feed.description.description = Zeigt die Beschreibung des RSS-Feed an. +channel-type.feed.last-update.label = Letzte Aktualisierung +channel-type.feed.last-update.description = Zeigt die Zeit an, zu der dieser RSS-Feed zuletzt aktualisiert wurde. +channel-type.feed.last-update.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.feed.latest-date.label = Letztes Veröffentlichungsdatum +channel-type.feed.latest-date.description = Zeigt die Zeit an, zu der dieser RSS-Feed zuletzt veröffentlicht wurde. +channel-type.feed.latest-date.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.feed.latest-description.label = Neueste Beschreibung +channel-type.feed.latest-description.description = Zeigt die Beschreibung des neuesten Eintrages des RSS-Feed an. +channel-type.feed.latest-enclosure.label = Neuester Enclosure +channel-type.feed.latest-enclosure.description = Zeigt den Enclosure des neuesten Eintrages des RSS-Feed an. +channel-type.feed.latest-link.label = Neuester Link +channel-type.feed.latest-link.description = Zeigt den Link des neuesten Eintrages des RSS-Feed an. +channel-type.feed.latest-title.label = Neuester Titel +channel-type.feed.latest-title.description = Zeigt den Titel des neuesten Eintrages des RSS-Feed an. +channel-type.feed.number-of-entries.label = Anzahl der Einträge +channel-type.feed.number-of-entries.description = Zeigt die Anzahl der Einträge des RSS-Feed an. +channel-type.feed.title.label = Titel +channel-type.feed.title.description = Zeigt den Titel des RSS-Feed an. diff --git a/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties b/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties index d3235da0f3b5a..94f747e8981c2 100644 --- a/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties +++ b/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties @@ -26,17 +26,17 @@ channel-group-type.gce.relays.label = Sorties numériques # channel types -channel-type.gce.analog.label = Entrée analogique -channel-type.gce.analogAdvanced.label = Entrée analogique -channel-type.gce.contact-trigger.label = Canal d'évènement de bouton Push -channel-type.gce.contact-triggerAdvanced.label = Canal d'évènement de bouton Push -channel-type.gce.contact.label = Entrée numérique -channel-type.gce.contactAdvanced.label = Entrée numérique +channel-type.gce.analog.label = Entrée Analogique +channel-type.gce.analogAdvanced.label = Entrée Analogique +channel-type.gce.contact-trigger.label = Canal Évènement Bouton Push +channel-type.gce.contact-triggerAdvanced.label = Canal Évènement Bouton Push +channel-type.gce.contact.label = Entrée Numérique +channel-type.gce.contactAdvanced.label = Entrée Numérique channel-type.gce.counter.label = Compteur -channel-type.gce.duration.label = Durée de l'état précédent +channel-type.gce.duration.label = Durée État Précédent channel-type.gce.duration.description = Durée de l'état précédent avant le changement d'état. -channel-type.gce.relay.label = Sortie numérique -channel-type.gce.relayAdvanced.label = Sortie numérique +channel-type.gce.relay.label = Sortie Numérique +channel-type.gce.relayAdvanced.label = Sortie Numérique channel-type.gce.voltage.label = Voltage channel-type.gce.voltage.description = Voltage diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties index 87e642f24e8d5..03536be4ab6e0 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties @@ -3,73 +3,178 @@ binding.hue.name = Extension hue binding.hue.description = L'extension hue intègre le système Philips hue et permet de contrôler des ampoules hue. +# binding config + +binding.config.hue.removalGracePeriod.label = Période de grâce pour la suppression +binding.config.hue.removalGracePeriod.description = Période de grâce supplémentaire (en secondes) que la découverte UPnP doit attendre avant de retirer un pont disparu de la boîte de réception. La valeur par défaut est de 50 secondes. + # thing types -thing-type.hue.0000.label = Ampoule sans variation +thing-type.hue.0000.label = Ampoule Sans Variation thing-type.hue.0000.description = Une ampoule sans réglage de l'intensité lumineuse. -thing-type.hue.0010.label = Prise commandée sans variation +thing-type.hue.0010.label = Prise Sans Variation thing-type.hue.0010.description = Une prise commandée sans réglage de l'intensité de sortie. -thing-type.hue.0100.label = Ampoule à variation +thing-type.hue.0100.label = Ampoule Avec Variation thing-type.hue.0100.description = Une ampoule avec réglage de l'intensité lumineuse. -thing-type.hue.0110.label = Prise commandée à variation +thing-type.hue.0106.label = Capteur Luminosité +thing-type.hue.0106.description = Un capteur fournissant le niveau de lumière. +thing-type.hue.0107.label = Capteur Présence +thing-type.hue.0107.description = Un capteur de mouvement permettant une détection de présence. +thing-type.hue.0110.label = Prise Avec Variation thing-type.hue.0110.description = Une prise commandée avec réglage de l'intensité de sortie. -thing-type.hue.0200.label = Ampoule couleur +thing-type.hue.0200.label = Ampoule Couleur thing-type.hue.0200.description = Une ampoule avec réglages de l'intensité lumineuse et de la couleur. -thing-type.hue.0210.label = Ampoule couleur +thing-type.hue.0210.label = Ampoule Couleur thing-type.hue.0210.description = Une ampoule avec réglages de l'intensité lumineuse, de la couleur et de la température de couleur -thing-type.hue.0220.label = Ampoule couleur +thing-type.hue.0220.label = Ampoule Température Couleur thing-type.hue.0220.description = Une ampoule avec réglages de l'intensité lumineuse et de la température de couleur. -thing-type.hue.bridge.label = Pont de connexion hue +thing-type.hue.0302.label = Capteur Température +thing-type.hue.0302.description = Un capteur fournissant des valeurs de température. +thing-type.hue.0820.label = Interrupteur Hue +thing-type.hue.0820.description = Un interrupteur télécommande Hue sans fil capable de faire varier l'intensité lumineuse. +thing-type.hue.0830.label = Interrupteur Hue Tap +thing-type.hue.0830.description = Un interrupteur télécommande Hue sans fil et sans pile personnalisable. +thing-type.hue.0840.label = Capteur État Générique CLIP +thing-type.hue.0840.description = Un objet capteur générique pour l'utilisation d'un capteur via IP. +thing-type.hue.0850.label = Capteur Drapeau Générique CLIP +thing-type.hue.0850.description = Un objet capteur générique pour l'utilisation d'un capteur via IP. +thing-type.hue.bridge.label = Pont Hue thing-type.hue.bridge.description = Le pont de connexion Philips Hue. -thing-type.hue.group.label = Groupe hue +thing-type.hue.geofencesensor.label = Capteur Géorepérage +thing-type.hue.geofencesensor.description = Un capteur fournissant une détection de présence basée sur le géorepérage. +thing-type.hue.group.label = Groupe Hue thing-type.hue.group.description = Un groupe d'ampoules ou une pièce pouvant être allumé et éteint. -# thing type configuration +# thing types config thing-type.config.hue.bridge.ipAddress.label = Adresse réseau thing-type.config.hue.bridge.ipAddress.description = L'adresse réseau du pont de connexion hue. thing-type.config.hue.bridge.pollingInterval.label = Intervalle d'interrogation thing-type.config.hue.bridge.pollingInterval.description = Le nombre de secondes entre chaque récupération des valeurs du pont. +thing-type.config.hue.bridge.port.label = Port +thing-type.config.hue.bridge.port.description = Port du pont de connexion hue. +thing-type.config.hue.bridge.sensorPollingInterval.label = Intervalle d'interrogation du capteur +thing-type.config.hue.bridge.sensorPollingInterval.description = Millisecondes entre chaque récupération des valeurs de capteur depuis le pont de connexion Hue. Une valeur plus élevée signifie plus de délai pour les valeurs de capteur, mais une valeur trop faible peut causer une congestion sur le pont de connexion Hue. Utilisez 0 pour désactiver l'interrogation des capteurs. La valeur par défaut est 500. thing-type.config.hue.bridge.userName.label = Nom d'utilisateur thing-type.config.hue.bridge.userName.description = Le nom d'un utilisateur enregistré sur le pont de connexion hue, autorisant un accès à l'API. -thing-type.config.hue.group.groupId.label = ID group +thing-type.config.hue.group.groupId.label = ID du groupe thing-type.config.hue.group.groupId.description = L'identifiant de groupe identifie l'un des groupes d'ampoules hue ou une pièce. - -config.lightId.label = ID ampoule -config.lightId.description = L'identifiant d'ampoule qui est utilis dans le pont de connexion Hue. -config.plugId.label = ID prise commande -config.plugId.description = L'identifiant de prise commande qui est utilis dans le pont de connexion Hue. -config.sensorId.label = ID du capteur -config.sensorId.description = identifiant de capteur qui est utilis dans le pont de connexion Hue. -config.on.label = tat du capteur -config.on.description = Active ou dsactive le capteur. +thing-type.config.hue.lightlevelsensor.tholddark.label = Seuil d'obscurité +thing-type.config.hue.lightlevelsensor.tholddark.description = Seuil configuré par l'utilisateur utilisé dans les règles pour déterminer le niveau insuffisant de lumière (c'est-à-dire en dessous du seuil). Valeur par défaut 16000. +thing-type.config.hue.lightlevelsensor.tholdoffset.label = Décalage de seuil +thing-type.config.hue.lightlevelsensor.tholdoffset.description = Seuil configuré par l'utilisateur utilisé dans les règles pour déterminer le niveau suffisant de lumière (c'est-à-dire au-dessus du seuil). Spécifié en relatif par rapport au seuil d'obscurité. Doit être >\=1. Valeur par défaut 7000. +thing-type.config.hue.presencesensor.sensitivity.label = Sensibilité +thing-type.config.hue.presencesensor.sensitivity.description = La sensibilité du capteur de présence. Ne peut pas dépasser la sensibilité maximale. +thing-type.config.hue.presencesensor.sensitivitymax.label = Sensibilité maximale +thing-type.config.hue.presencesensor.sensitivitymax.description = La sensibilité maximale du capteur de présence. # channel types -channel-type.hue.alert.label = Mode alerte +channel-type.hue.alert.label = Mode Alerte channel-type.hue.alert.description = Permet un changement temporaire de l'état de l'ampoule. channel-type.hue.alert.state.option.NONE = Sans alerte channel-type.hue.alert.state.option.SELECT = Alerte courte channel-type.hue.alert.state.option.LSELECT = Alerte longue -channel-type.hue.effect.label = Mode boucle de couleur +channel-type.hue.dark.label = Obscurité +channel-type.hue.dark.description = Le niveau de lumière est en dessous du seuil d'obscurité. +channel-type.hue.daylight.label = Lumière du Jour +channel-type.hue.daylight.description = Le niveau de lumière est supérieur au seuil de lumière du jour. +channel-type.hue.dimmer_switch.label = État Interrupteur +channel-type.hue.dimmer_switch.description = Le dernier bouton enfoncé de l'interrupteur télécommande. +channel-type.hue.dimmer_switch.state.option.1000 = Allumé (appui initial) +channel-type.hue.dimmer_switch.state.option.1001 = Allumé (appui maintenu) +channel-type.hue.dimmer_switch.state.option.1002 = Allumé (appui court relâché) +channel-type.hue.dimmer_switch.state.option.1003 = Allumé (appui long relâché) +channel-type.hue.dimmer_switch.state.option.2000 = Plus lumineux (appui initial) +channel-type.hue.dimmer_switch.state.option.2001 = Plus lumineux (appui maintenu) +channel-type.hue.dimmer_switch.state.option.2002 = Plus lumineux (appui court relâché) +channel-type.hue.dimmer_switch.state.option.2003 = Plus lumineux (appui long relâché) +channel-type.hue.dimmer_switch.state.option.3000 = Moins lumineux (appui initial) +channel-type.hue.dimmer_switch.state.option.3001 = Moins lumineux (appui maintenu) +channel-type.hue.dimmer_switch.state.option.3002 = Moins lumineux (appui court relâché) +channel-type.hue.dimmer_switch.state.option.3003 = Moins lumineux (appui long relâché) +channel-type.hue.dimmer_switch.state.option.4000 = Éteint (appui initial) +channel-type.hue.dimmer_switch.state.option.4001 = Éteint (appui maintenu) +channel-type.hue.dimmer_switch.state.option.4002 = Éteint (appui court relâché) +channel-type.hue.dimmer_switch.state.option.4003 = Éteint (appui long relâché) +channel-type.hue.dimmer_switch_event.label = Événement Interrupteur +channel-type.hue.dimmer_switch_event.description = Déclenché lorsqu'un bouton est enfoncé sur l'interrupteur télécommande. +channel-type.hue.effect.label = Boucle Couleur channel-type.hue.effect.description = Permet de passer l'ampoule dans un mode boucle de couleur. +channel-type.hue.flag.label = Drapeau +channel-type.hue.flag.description = Drapeau du capteur CLIP. +channel-type.hue.illuminance.label = Éclairement +channel-type.hue.illuminance.description = Éclairement actuel. +channel-type.hue.last_updated.label = Dernière Mise à Jour +channel-type.hue.last_updated.description = La date et l'heure de la dernière mise à jour du capteur. +channel-type.hue.last_updated.state.pattern = %1$tY-%1$tm-%1$td %1$tH\:%1$tM\:%1$tS +channel-type.hue.light_level.label = Niveau Lumière +channel-type.hue.light_level.description = Niveau de lumière actuel. +channel-type.hue.scene.label = Scénario +channel-type.hue.scene.description = Permet de ré-exécuter un scénario pour toutes les lumières appartenant au scénario. +channel-type.hue.status.label = État +channel-type.hue.status.description = État du capteur CLIP. +channel-type.hue.tap_switch.label = État Interrupteur Tap +channel-type.hue.tap_switch.description = Le dernier bouton enfoncé de l'interrupteur télécommande Tap. +channel-type.hue.tap_switch.state.option.34 = Bouton 1 +channel-type.hue.tap_switch.state.option.16 = Bouton 2 +channel-type.hue.tap_switch.state.option.17 = Bouton 3 +channel-type.hue.tap_switch.state.option.18 = Bouton 4 +channel-type.hue.tap_switch_event.label = Évènement Interrupteur Tap +channel-type.hue.tap_switch_event.description = Déclenché lorsqu'un bouton est enfoncé sur l'interrupteur télécommande Tap. +channel-type.hue.temperature.label = Température +channel-type.hue.temperature.description = Température actuelle. + +# thing types config + +config.fadetime.label = Durée de fondu +config.fadetime.description = La durée de fondu en millisecondes lors du changement de valeur. +config.ledindication.label = Témoin LED +config.ledindication.description = Active ou désactive la LED de l'appareil pendant le fonctionnement normal. Les appareils peuvent toujours indiquer un fonctionnement exceptionnel (réinitialisation, mise à jour du logiciel, batterie faible). +config.lightId.label = ID de l'ampoule +config.lightId.description = L'identifiant d'ampoule qui est utilisé dans le pont de connexion Hue. +config.plugId.label = ID de la prise +config.plugId.description = L'identifiant de prise commandée qui est utilisé dans le pont de connexion Hue. +config.sensorId.label = ID du capteur +config.sensorId.description = L'identifiant de capteur qui est utilisé dans le pont de connexion Hue. +config.on.label = État du capteur +config.on.description = Active ou désactive le capteur. # config status messages -config-status.error.missing-ip-address-configuration=Aucune adresse IP fournie pour le pont de connexion hue. +config-status.error.missing-ip-address-configuration = Aucune adresse IP fournie pour le pont de connexion hue. # thing status descriptions -offline.conf-error-no-ip-address = Echec de la connexion au pont hue. Adresse IP non renseignée dans la configuration. -offline.conf-error-no-username = Echec de la connexion au pont hue. Nom d''utilisateur pour l''autentification non renseigné dans la configuration. -offline.conf-error-invalid-username = Echec de l''autentification. Supprimer le nom d''utilisateur de la configuration pour en générer un nouveau. -offline.conf-error-press-pairing-button = Non autentifié. Appuyer sur le bouton d'appairage du pont de connexion hue ou définir un nom valide d''utilisateur dans la configuration. -offline.conf-error-creation-username = Echec de la créatiion du nouvel utilisateur sur le pont de connexion hue. +offline.conf-error-no-ip-address = Échec de la connexion au pont hue. Adresse IP non renseignée dans la configuration. +offline.conf-error-no-username = Échec de la connexion au pont hue. Nom d'utilisateur pour l’authentification non renseigné dans la configuration. +offline.conf-error-invalid-username = Échec de l’authentification. Supprimer le nom d'utilisateur de la configuration pour en générer un nouveau. +offline.conf-error-press-pairing-button = Non authentifié. Appuyer sur le bouton d'appairage du pont de connexion hue ou définir un nom valide d'utilisateur dans la configuration. +offline.conf-error-creation-username = Échec de la création du nouvel utilisateur sur le pont de connexion hue. offline.bridge-connection-lost = Perte de la connexion au pont hue. offline.conf-error-no-light-id = ID ampoule non renseigné dans la configuration. +offline.conf-error-no-sensor-id = ID capteur non renseigné dans la configuration. offline.conf-error-no-group-id = ID groupe non renseigné dans la configuration. -offline.conf-error-wrong-light-id = Pas d''ampoule avec cet ID dans le pont de connexion hue. +offline.conf-error-wrong-light-id = Pas d'ampoule avec cet ID dans le pont de connexion hue. +offline.conf-error-wrong-sensor-id = Pas de capteur avec cet ID dans le pont de connexion hue. offline.conf-error-wrong-group-id = Pas de groupe avec cet ID dans le pont de connexion hue. -offline.light-not-reachable = Le pont de connexion hue signale l''ampoule comme inaccessible. -offline.light-removed = Le pont de connexion hue signale l''ampoule comme supprimée. +offline.light-not-reachable = Le pont de connexion hue signale l'ampoule comme inaccessible. +offline.sensor-not-reachable = Le pont de connexion hue signale le capteur comme inaccessible. +offline.light-removed = Le pont de connexion hue signale l'ampoule comme supprimée. +offline.sensor-removed = Le pont de connexion hue signale le capteur comme supprimé. offline.group-removed = Le pont de connexion hue signale le groupe comme supprimé. + +# lightactions + +actionInputChannelLabel = Canal +actionInputChannelDesc = Le canal vers lequel envoyer la commande. +actionInputCommandLabel = Commande +actionInputCommandDesc = La commande pour la lumière. +actionInputFadeTimeLabel = Durée de fondu +actionInputFadeTimeDesc = La durée de fondu en millisecondes à utiliser pour la commande de lumière. +actionLabel = envoyer une commande de lumière avec un temps de fondu personnalisé +actionDesc = Envoie une commande de lumière avec un temps de fondu personnalisé. + +# discovery results + +discovery.group.all_lights.label = Toutes Les Lumières diff --git a/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties b/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties index 06c4134cb36b8..a23a56ff9214d 100644 --- a/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties +++ b/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties @@ -25,7 +25,7 @@ channel-type.lgwebos.channelType.label = Chaîne channel-type.lgwebos.channelType.description = Chaîne actuelle channel-type.lgwebos.mediaStopType.label = Arrêt channel-type.lgwebos.mediaStopType.description = Arrête la lecture -channel-type.lgwebos.rcButtonType.label = Bouton télécommande +channel-type.lgwebos.rcButtonType.label = Bouton Télécommande channel-type.lgwebos.rcButtonType.description = Simule l'appui sur un bouton de la télécommande channel-type.lgwebos.toastType.label = Notification channel-type.lgwebos.toastType.description = Envoie un message de notification à afficher sur l'écran du téléviseur. @@ -71,7 +71,7 @@ actionShowToastInputIconDesc = L'URL de l'icône à afficher # Thing status descriptions -offline.config-error-unknown-host = Paramètre "host" manquant +offline.config-error-unknown-host = Paramètre "hôte" manquant offline.comm-error-connexion-failed = Échec de la connexion \: {0} offline.tv-off = La TV est éteinte online.registering = En cours d'appairage - Vous devrez peut-être confirmer l'appairage au niveau du téléviseur. diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_de.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_de.properties index 558637b427a59..aad1f9cc402da 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_de.properties +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_de.properties @@ -33,7 +33,7 @@ config.username.label = Benutzername # channel types -channel-type.mail.mailcount.label = Mail-Anzahl +channel-type.mail.mailcount.label = Anzahl der E-Mails channel-type.mail.mailcount.description = Zeigt die Anzahl der E-Mails im Ordner an. # channel types config diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/actions_de.properties b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/actions_de.properties index 3a2ae2c9cf72e..cd3ec872299d1 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/actions_de.properties +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/actions_de.properties @@ -18,8 +18,6 @@ action.setBypassFrom.inputParams.month.label = Bypass von Monat action.setBypassFrom.inputParams.month.description = Das Monat ab wann der Bypass aktiv sein soll action.setBypassTo.label = Bypass bis Tag und Monat setzen action.setBypassTo.description = Setzt den Tag und das Monat bis wann der Bypass aktiv sein soll -action.setBypassTo.inputParams.day.label = Bypass bis Tag -action.setBypassTo.inputParams.day.description = Der Tag bis wann der Bypass aktiv sein soll action.setBypassTo.inputParams.day.label = Bypass bis Monat action.setBypassTo.inputParams.day.description = Das Monat bis wann der Bypass aktiv sein soll action.getErrorMessages.label = Liste der Fehlermeldungen erhalten diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/errors_de.properties b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/errors_de.properties index 9bf6225839c61..e07e9d8cecadd 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/errors_de.properties +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/errors_de.properties @@ -1,33 +1,33 @@ # Helios easyControls errors according to bit encoding (the number represents the bit encoding the error) error.0 = Drehzahlfehler Lüfter Zuluft (Außenluft) error.1 = Drehzahlfehler Lüfter Abluft (Fortluft) -error.2 = n/a +error.2 = k.A. error.3 = SD-Karten-Fehler beim Schreiben der EEPROM Daten (Flash Ringpuffer voll) error.4 = Bus Überstrom -error.5 = n/a -error.6 = Basis: Fehler VHZ EH (Null-Durchgangserkennung) -error.7 = Erw. Modul (VHZ): Fehler VZH EH (Null-Durchgangserkennung) -error.8 = Erw. Modul (NHZ): Fehler NZH EH (Null-Durchgangserkennung) -error.9 = Basis: Interner Temp-Sensorfehler (T1) - Außenluft (fehlt oder Kabelbruch) -error.10 = Basis: Interner Temp-Sensorfehler (T2) - Zuluft (fehlt oder Kabelbruch) -error.11 = Basis: Interner Temp-Sensorfehler (T3) - Abluft (fehlt oder Kabelbruch) -error.12 = Basis: Interner Temp-Sensorfehler (T4) - Fortluft (fehlt oder Kabelbruch) -error.13 = Basis: Interner Temp-Sensorfehler (T1) - Außenluft (Kurzschluss) -error.14 = Basis: Interner Temp-Sensorfehler (T2) - Zuluft (Kurzschluss) -error.15 = Basis: Interner Temp-Sensorfehler (T3) - Abluft (Kurzschluss) -error.16 = Basis: Interner Temp-Sensorfehler (T4) - Fortluft (Kurzschluss) +error.5 = k.A. +error.6 = Basis\: Fehler VHZ EH (Null-Durchgangserkennung) +error.7 = Erw. Modul (VHZ)\: Fehler VZH EH (Null-Durchgangserkennung) +error.8 = Erw. Modul (NHZ)\: Fehler NZH EH (Null-Durchgangserkennung) +error.9 = Basis\: Interner Temp-Sensorfehler (T1) - Außenluft (fehlt oder Kabelbruch) +error.10 = Basis\: Interner Temp-Sensorfehler (T2) - Zuluft (fehlt oder Kabelbruch) +error.11 = Basis\: Interner Temp-Sensorfehler (T3) - Abluft (fehlt oder Kabelbruch) +error.12 = Basis\: Interner Temp-Sensorfehler (T4) - Fortluft (fehlt oder Kabelbruch) +error.13 = Basis\: Interner Temp-Sensorfehler (T1) - Außenluft (Kurzschluss) +error.14 = Basis\: Interner Temp-Sensorfehler (T2) - Zuluft (Kurzschluss) +error.15 = Basis\: Interner Temp-Sensorfehler (T3) - Abluft (Kurzschluss) +error.16 = Basis\: Interner Temp-Sensorfehler (T4) - Fortluft (Kurzschluss) error.17 = Erw. Modul als VHZ konfiguriert, aber nicht vorh. oder ausgefallen error.18 = Erw. Modul als NHZ konfiguriert, aber nicht vorh. oder ausgefallen -error.19 = Erw. Modul (VHZ): Kanalfühler (T5) - Außenluft (fehlt oder Kabelbruch) -error.20 = Erw. Modul (NHZ): Kanalfühler (T6) - Zuluft (fehlt oder Kabelbruch) -error.21 = Erw. Modul (NHZ): Kanalfühler (T7) - Rücklauf WW-Register (fehlt oder Kabelbruch) -error.22 = Erw. Modul (VHZ): Kanalfühler (T5) - Außenluft (Kurzschluss) -error.23 = Erw. Modul (NHZ): Kanalfühler (T6) - Zuluft (Kurzschluss) -error.24 = Erw. Modul (NHZ): Kanalfühler (T7) - Rücklauf WW-Register (Kurzschluss) -error.25 = Erw. Modul (VHZ): Sicherheitsbegrenzer automatisch -error.26 = Erw. Modul (VHZ): Sicherheitsbegrenzer manuell -error.27 = Erw. Modul (NHZ): Sicherheitsbegrenzer automatisch -error.28 = Erw. Modul (NHZ): Sicherheitsbegrenzer manuell -error.29 = Erw. Modul (NHZ): Frostschutz WW-Reg. gemessen über WW-Rücklauf (T7) (Schaltschwelle per Variablenliste einstellbar z.B. <7°C) -error.30 = Erw. Modul (NHZ): Frostschutz WW-Reg. gemessen über Zuluft-Fühler (T6) (Schaltschwelle per Variablenliste einstellbar z.B. <7°C) -error.31 = Frostschutz externes WW Reg.: (fest <5°C nur PHI), gemessen über Zuluftkanal-Fühler (Erw. Modul (NHZ) od. Basis) +error.19 = Erw. Modul (VHZ)\: Kanalfühler (T5) - Außenluft (fehlt oder Kabelbruch) +error.20 = Erw. Modul (NHZ)\: Kanalfühler (T6) - Zuluft (fehlt oder Kabelbruch) +error.21 = Erw. Modul (NHZ)\: Kanalfühler (T7) - Rücklauf WW-Register (fehlt oder Kabelbruch) +error.22 = Erw. Modul (VHZ)\: Kanalfühler (T5) - Außenluft (Kurzschluss) +error.23 = Erw. Modul (NHZ)\: Kanalfühler (T6) - Zuluft (Kurzschluss) +error.24 = Erw. Modul (NHZ)\: Kanalfühler (T7) - Rücklauf WW-Register (Kurzschluss) +error.25 = Erw. Modul (VHZ)\: Sicherheitsbegrenzer automatisch +error.26 = Erw. Modul (VHZ)\: Sicherheitsbegrenzer manuell +error.27 = Erw. Modul (NHZ)\: Sicherheitsbegrenzer automatisch +error.28 = Erw. Modul (NHZ)\: Sicherheitsbegrenzer manuell +error.29 = Erw. Modul (NHZ)\: Frostschutz WW-Reg. gemessen über WW-Rücklauf (T7) (Schaltschwelle per Variablenliste einstellbar z.B. <7°C) +error.30 = Erw. Modul (NHZ)\: Frostschutz WW-Reg. gemessen über Zuluft-Fühler (T6) (Schaltschwelle per Variablenliste einstellbar z.B. <7°C) +error.31 = Frostschutz externes WW Reg.\: (fest <5°C nur PHI), gemessen über Zuluftkanal-Fühler (Erw. Modul (NHZ) od. Basis) diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/stateflags_de.properties b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/stateflags_de.properties index bcc6089c2f32c..fe1d3114a9140 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/stateflags_de.properties +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/src/main/resources/OH-INF/i18n/stateflags_de.properties @@ -1,7 +1,7 @@ # Helios easyControls status flags according to bit encoding (the first number represents the bit encoding the status flag, # the second number indicates the possible bit states) -stateflag.0.1 = System fertig initialisiert (Anzeige im BT bis dahin: SYSTEM BOOTING) -stateflag.1.1 = System Softwareupdate aktiv (Anzeige im BT bis dahin: SYSTEM LOADING) +stateflag.0.1 = System fertig initialisiert (Anzeige im BT bis dahin\: SYSTEM BOOTING) +stateflag.1.1 = System Softwareupdate aktiv (Anzeige im BT bis dahin\: SYSTEM LOADING) stateflag.2.1 = Firwareupdate wird aktiviert stateflag.3.1 = INBA ist aktiv stateflag.4.1 = Partybetrieb @@ -9,19 +9,19 @@ stateflag.5.1 = Ruhebetrieb stateflag.6.1 = Urlaubsbetrieb stateflag.7.1 = VHZ ist auf Basis-Modul konfiguriert stateflag.8.1 = VHZ ist auf ErwModul konfiguriert -stateflag.9.1 = ErwModul VHZ aktiv (z.B. BT-Anzeige: Menüpunkt VHZ einblenden) +stateflag.9.1 = ErwModul VHZ aktiv (z.B. BT-Anzeige\: Menüpunkt VHZ einblenden) stateflag.10.1 = VHZ konfiguriert -stateflag.11.0 = VHZ: Heizungstyp elektrisch -stateflag.11.1 = VHZ: Heizungstyp Sole (Erde oder Luft) +stateflag.11.0 = VHZ\: Heizungstyp elektrisch +stateflag.11.1 = VHZ\: Heizungstyp Sole (Erde oder Luft) stateflag.12.1 = NHZ konfiguriert (Temperatur eingestellt ungl. HEIZUNG AUS) -stateflag.13.1 = ErwModul NHZ aktiv (z.B. BT-Anzeige: Menüpunkt NHZ einblenden) +stateflag.13.1 = ErwModul NHZ aktiv (z.B. BT-Anzeige\: Menüpunkt NHZ einblenden) stateflag.14.1 = NHZ aktiv (Regelung, Fehler, identisch mit "Nachheizung.Ein") -stateflag.15.0 = NHZ: Heizungstyp elektrisch -stateflag.15.1 = NHZ: Heizungstyp Warmwasser +stateflag.15.0 = NHZ\: Heizungstyp elektrisch +stateflag.15.1 = NHZ\: Heizungstyp Warmwasser stateflag.16.1 = CO2 Regelung ein stateflag.17.1 = Humi Regelung ein stateflag.18.1 = VOC Regelung ein -stateflag.19.1 = n/a +stateflag.19.1 = k.A. stateflag.20.1 = min. ein externer Kontakt angeschlossen (EM oder ES) stateflag.21.1 = Externe Kontaktfunktion aktiv stateflag.22.1 = Externen Zugriff zulassen diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/resources/OH-INF/i18n/nanoleaf_de.properties b/bundles/org.openhab.binding.nanoleaf/src/main/resources/OH-INF/i18n/nanoleaf_de.properties index d798da8831c67..3612a5858b4bc 100644 --- a/bundles/org.openhab.binding.nanoleaf/src/main/resources/OH-INF/i18n/nanoleaf_de.properties +++ b/bundles/org.openhab.binding.nanoleaf/src/main/resources/OH-INF/i18n/nanoleaf_de.properties @@ -8,7 +8,7 @@ thing-type.nanoleaf.lightpanel.name = Nanoleaf Paneel thing-type.nanoleaf.lightpanel.description = Ein mit dem Controller verbundenes Paneel # config -thing-type.config.nanoleaf.controller.address.label = IP Adresse oder Hostname +thing-type.config.nanoleaf.controller.address.label = IP-Adresse thing-type.config.nanoleaf.controller.address.description = IP Adresse oder Hostname des Nanoleaf Controllers, z. B. 192.168.0.10 thing-type.config.nanoleaf.controller.port.label = Port thing-type.config.nanoleaf.controller.port.description = Portnummer des Controllers, z. B. 16021 @@ -36,8 +36,8 @@ channel-type.nanoleaf.panelColor.label = Paneelfarbe channel-type.nanoleaf.panelColor.description = Farbe des einzelnen Paneels channel-type.nanoleaf.tap.label = Taster channel-type.nanoleaf.tap.description = Tastevents des Panels -channel-type.nanoleaf.swipe.label = Wischen (Swipe) -channel-type.nanoleaf.swipe.description = Wischen (Swipe) über die Panels +channel-type.nanoleaf.swipe.label = Wischen +channel-type.nanoleaf.swipe.description = Über die Panels wischen # error messages error.nanoleaf.controller.noIp = IP/Host-Adresse und/oder Port sind für den Controller nicht konfiguriert. diff --git a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_fr.properties b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_fr.properties index 48ce1d8bfb2c2..3788087284a63 100644 --- a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_fr.properties +++ b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_fr.properties @@ -19,9 +19,9 @@ thing-type.config.ntp.ntp.timeZone.label = Fuseau horaire thing-type.config.ntp.ntp.timeZone.description = Le fuseau horaire sélectionné. # channel types -channel-type.ntp.dateTime-channel.label = Date heure +channel-type.ntp.dateTime-channel.label = Date Heure channel-type.ntp.dateTime-channel.description = Date et heure mises à jour à partir du serveur NTP. -channel-type.ntp.string-channel.label = Date heure +channel-type.ntp.string-channel.label = Date Heure channel-type.ntp.string-channel.description = Date et heure mises à jour à partir du serveur NTP. # channel type configuration @@ -33,4 +33,4 @@ offline.comm-error-unknown-host = Le nom d''hôte {0} du serveur de temps est in offline.comm-error-connection = La connexion réseau avec le serveur de temps {0} ne peut pas être établie -> renvoi de l''heure courante système à la place. # Discovery result -discovery.ntp.ntp.local.label = Heure locale +discovery.ntp.ntp.local.label = Heure Locale diff --git a/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties b/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties index aec29fcaf8ed5..6ee434a02c32e 100644 --- a/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties +++ b/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties @@ -7,11 +7,11 @@ binding.powermax.description = Cette extension s'interface avec les centrales d' thing-type.powermax.ip.label = Connexion IP thing-type.powermax.ip.description = Représente la connexion IP au système d'alarme. -thing-type.powermax.serial.label = Connexion série +thing-type.powermax.serial.label = Connexion Série thing-type.powermax.serial.description = Représente la connexion série au système d'alarme. thing-type.powermax.x10.label = Appareil X10 thing-type.powermax.x10.description = Représente un appareil X10. -thing-type.powermax.zone.label = Zone d'alarme +thing-type.powermax.zone.label = Zone Alarme thing-type.powermax.zone.description = Représente un appareil physique comme une porte, une fenêtre ou un capteur de mouvement. # thing types config @@ -44,15 +44,15 @@ config.pinCode.description = Le code PIN à utiliser pour armer ou désarmer le # channel types -channel-type.powermax.active_alerts.label = Alarmes et alertes actives +channel-type.powermax.active_alerts.label = Alarmes et Alertes Actives channel-type.powermax.active_alerts.description = Liste des alarmes et alertes actives -channel-type.powermax.alarm_active.label = Alarme active +channel-type.powermax.alarm_active.label = Alarme Active channel-type.powermax.alarm_active.description = Si une alarme est active ou non. -channel-type.powermax.alarmed.label = Zone en alarme +channel-type.powermax.alarmed.label = Zone en Alarme channel-type.powermax.alarmed.description = Si la zone a ou non une condition d'alarme en cours, ou si elle a été en alarme depuis le dernier vidage de la mémoire. -channel-type.powermax.alert_in_memory.label = Alerte en mémoire +channel-type.powermax.alert_in_memory.label = Alerte en Mémoire channel-type.powermax.alert_in_memory.description = Si une alerte est enregistrée ou non dans la mémoire système. -channel-type.powermax.arm_mode.label = Mode d'armement du système +channel-type.powermax.arm_mode.label = Mode Armement Système channel-type.powermax.arm_mode.state.option.Disarmed = Désarmement channel-type.powermax.arm_mode.state.option.Stay = Armement partiel channel-type.powermax.arm_mode.state.option.Armed = Armement total @@ -66,55 +66,55 @@ channel-type.powermax.arm_mode.state.option.NotReady = Pas prêt channel-type.powermax.arm_mode.state.option.Ready = Prêt channel-type.powermax.arm_mode.state.option.UserTest = Test en cours channel-type.powermax.arm_mode.state.option.Force = Armement forcé -channel-type.powermax.armed.label = Zone armée (Switch) +channel-type.powermax.armed.label = Zone Armée (Switch) channel-type.powermax.armed.description = Si la zone est armée ou non. -channel-type.powermax.bypassed.label = Zone isolée +channel-type.powermax.bypassed.label = Zone Isolée channel-type.powermax.bypassed.description = Si la zone est isolée (hors surveillance) ou non. -channel-type.powermax.download_setup.label = Télécharger la configuration +channel-type.powermax.download_setup.label = Télécharger Configuration channel-type.powermax.download_setup.description = Déclencher le téléchargement de la configuration du système. -channel-type.powermax.event_log.label = Entrée du journal des événements -channel-type.powermax.inactive.label = Zone inactive +channel-type.powermax.event_log.label = Entrée Journal Événements +channel-type.powermax.inactive.label = Zone Inactive channel-type.powermax.inactive.description = Si le capteur de la zone est inactif (pas de signal reçu par la centrale) ou non. -channel-type.powermax.last_message_time.label = Heure du dernier message +channel-type.powermax.last_message_time.label = Heure Dernier Message channel-type.powermax.last_message_time.description = Horodatage du message le plus récent reçu du système d'alarme. -channel-type.powermax.last_trip.label = Dernier déclenchement de la zone +channel-type.powermax.last_trip.label = Dernier Déclenchement Zone channel-type.powermax.last_trip.description = Horodatage de la dernière fois où la zone a été déclenchée. -channel-type.powermax.locked.label = Zone armée (Contact) +channel-type.powermax.locked.label = Zone Armée (Contact) channel-type.powermax.locked.description = Si la zone est armée ou non (CLOSED lorsqu'elle est armée). -channel-type.powermax.mode.label = Mode système +channel-type.powermax.mode.label = Mode Système channel-type.powermax.mode.description = Le mode actuel peut être Standard, Powerlink ou Téléchargement. channel-type.powermax.mode.state.option.Download = Téléchargement channel-type.powermax.mode.state.option.Powerlink = Powerlink channel-type.powermax.mode.state.option.Standard = Standard channel-type.powermax.pgm_status.label = État PGM -channel-type.powermax.ready.label = Système prêt +channel-type.powermax.ready.label = Système Prêt channel-type.powermax.ready.description = Si le système est prêt ou non pour être armé. -channel-type.powermax.ringing.label = Sonnerie en cours +channel-type.powermax.ringing.label = Sonnerie channel-type.powermax.ringing.description = Si la sirène d'alarme sonne ou non. -channel-type.powermax.system_armed.label = Système armé +channel-type.powermax.system_armed.label = Système Armé channel-type.powermax.system_armed.description = Si la système est armé ou non. -channel-type.powermax.system_status.label = État du système +channel-type.powermax.system_status.label = État Système channel-type.powermax.system_status.description = Un bref résumé de l'état du système. -channel-type.powermax.tamper_alarm.label = Alarme de sabotage de la zone +channel-type.powermax.tamper_alarm.label = Alarme Sabotage Zone channel-type.powermax.tamper_alarm.description = Si le capteur de la zone a ou non une condition de sabotage en cours, ou s'il a eu un sabotage depuis le dernier vidage de la mémoire. -channel-type.powermax.tampered.label = Zone sabotée +channel-type.powermax.tampered.label = Zone Sabotée channel-type.powermax.tampered.description = Si le capteur de la zone signale une condition de sabotage ou non. -channel-type.powermax.tripped.label = Zone déclenchée +channel-type.powermax.tripped.label = Zone Déclenchée channel-type.powermax.tripped.description = Si la zone est déclenchée ou non. -channel-type.powermax.trouble.label = Panne détectée +channel-type.powermax.trouble.label = Panne Détectée channel-type.powermax.trouble.description = Si une panne est détectée ou non. -channel-type.powermax.update_event_logs.label = Mettre à jour le journal d'événements +channel-type.powermax.update_event_logs.label = Mettre à Jour Journal Événements channel-type.powermax.update_event_logs.description = Déclencher la mise à jour le journal des événements. -channel-type.powermax.with_zones_bypassed.label = Avec zones isolées +channel-type.powermax.with_zones_bypassed.label = Avec Zones Isolées channel-type.powermax.with_zones_bypassed.description = Si au moins une zone est isolée. -channel-type.powermax.x10_status.label = État de l'appareil X10 +channel-type.powermax.x10_status.label = État Appareil X10 channel-type.powermax.x10_status.state.option.ON = Allumer channel-type.powermax.x10_status.state.option.OFF = Éteindre channel-type.powermax.x10_status.state.option.DIM = Réduire l'intensité channel-type.powermax.x10_status.state.option.BRIGHT = Accentuer l'intensité -channel-type.powermax.zone_last_message.label = Dernier message d'état de la zone +channel-type.powermax.zone_last_message.label = Dernier Message État Zone channel-type.powermax.zone_last_message.description = Le message d'état le plus récent signalé par la zone. -channel-type.powermax.zone_last_message_time.label = Heure du dernier message d'état de la zone +channel-type.powermax.zone_last_message_time.label = Heure Dernier Message État Zone channel-type.powermax.zone_last_message_time.description = Horodatage de réception du dernier message d'état de la zone. # Thing status descriptions diff --git a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel_fr.properties b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel_fr.properties index 43d6d3ffa48e2..61037478d31e8 100644 --- a/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel_fr.properties +++ b/bundles/org.openhab.binding.rotel/src/main/resources/OH-INF/i18n/rotel_fr.properties @@ -5,13 +5,13 @@ binding.rotel.description = L'extension Rotel permet de contrôler des appareils # thing types -thing-type.rotel.a11.label = Ampli Hi-Fi A11 +thing-type.rotel.a11.label = Ampli A11 thing-type.rotel.a11.description = Connexion à un ampli Hi-Fi stéréo Rotel A11 -thing-type.rotel.a12.label = Ampli Hi-Fi A12 +thing-type.rotel.a12.label = Ampli A12 thing-type.rotel.a12.description = Connexion à un ampli Hi-Fi stéréo Rotel A12 -thing-type.rotel.a14.label = Ampli Hi-Fi A14 +thing-type.rotel.a14.label = Ampli A14 thing-type.rotel.a14.description = Connexion à un ampli Hi-Fi stéréo Rotel A14 thing-type.rotel.cd11.label = Lecteur CD CD11 @@ -20,31 +20,31 @@ thing-type.rotel.cd11.description = Connexion à un lecteur CD Rotel CD11 thing-type.rotel.cd14.label = Lecteur CD CD14 thing-type.rotel.cd14.description = Connexion à un lecteur CD Rotel CD14 -thing-type.rotel.ra11.label = Ampli Hi-Fi RA-11 +thing-type.rotel.ra11.label = Ampli RA-11 thing-type.rotel.ra11.description = Connexion à un ampli Hi-Fi stéréo Rotel RA-11 -thing-type.rotel.ra12.label = Ampli Hi-Fi RA-12 +thing-type.rotel.ra12.label = Ampli RA-12 thing-type.rotel.ra12.description = Connexion à un ampli Hi-Fi stéréo Rotel RA-12 -thing-type.rotel.ra1570.label = Ampli Hi-Fi RA-1570 +thing-type.rotel.ra1570.label = Ampli RA-1570 thing-type.rotel.ra1570.description = Connexion à un ampli Hi-Fi stéréo Rotel RA-1570 -thing-type.rotel.ra1572.label = Ampli Hi-Fi RA-1572 +thing-type.rotel.ra1572.label = Ampli RA-1572 thing-type.rotel.ra1572.description = Connexion à un ampli Hi-Fi stéréo Rotel RA-1572 -thing-type.rotel.ra1592.label = Ampli Hi-Fi RA-1592 +thing-type.rotel.ra1592.label = Ampli RA-1592 thing-type.rotel.ra1592.description = Connexion à un ampli Hi-Fi stéréo Rotel RA-1592 -thing-type.rotel.rap1580.label = Ampli Home-Cinéma RAP-1580 +thing-type.rotel.rap1580.label = Ampli RAP-1580 thing-type.rotel.rap1580.description = Connexion à un ampli Home-Cinéma Rotel RAP-1580 -thing-type.rotel.rc1570.label = Préampli Hi-Fi RC-1570 +thing-type.rotel.rc1570.label = Préampli RC-1570 thing-type.rotel.rc1570.description = Connexion à un préampli Hi-Fi stéréo Rotel RC-1570 -thing-type.rotel.rc1572.label = Préampli Hi-Fi RC-1572 +thing-type.rotel.rc1572.label = Préampli RC-1572 thing-type.rotel.rc1572.description = Connexion à un préampli Hi-Fi stéréo Rotel RC-1572 -thing-type.rotel.rc1590.label = Préampli Hi-Fi RC-1590 +thing-type.rotel.rc1590.label = Préampli RC-1590 thing-type.rotel.rc1590.description = Connexion à un préampli Hi-Fi stéréo Rotel RC-1590 thing-type.rotel.rcd1570.label = Lecteur CD RCD-1570 @@ -53,64 +53,64 @@ thing-type.rotel.rcd1570.description = Connexion à un lecteur CD Rotel RCD-1570 thing-type.rotel.rcd1572.label = Lecteur CD RCD-1572 thing-type.rotel.rcd1572.description = Connexion à un lecteur CD Rotel RCD-1572 -thing-type.rotel.rcx1500.label = Ampli Home-Cinéma RCX-1500 +thing-type.rotel.rcx1500.label = Ampli RCX-1500 thing-type.rotel.rcx1500.description = Connexion à un ampli Home-Cinéma Rotel RCX-1500 -thing-type.rotel.rdd1580.label = DAC Hi-Fi RDD-1580 +thing-type.rotel.rdd1580.label = DAC RDD-1580 thing-type.rotel.rdd1580.description = Connexion à un DAC Hi-Fi stéréo Rotel RDD-1580 thing-type.rotel.rdg1520.label = Tuner RDG-1520 thing-type.rotel.rdg1520.description = Connexion à un tuner Rotel RDG-1520 -thing-type.rotel.rsp1066.label = Préampli Home-Cinéma RSP-1066 +thing-type.rotel.rsp1066.label = Préampli RSP-1066 thing-type.rotel.rsp1066.description = Connexion à un préampli Home-Cinéma Rotel RSP-1066 -thing-type.rotel.rsp1068.label = Préampli Home-Cinéma RSP-1068 +thing-type.rotel.rsp1068.label = Préampli RSP-1068 thing-type.rotel.rsp1068.description = Connexion à un préampli Home-Cinéma Rotel RSP-1068 -thing-type.rotel.rsp1069.label = Préampli Home-Cinéma RSP-1069 +thing-type.rotel.rsp1069.label = Préampli RSP-1069 thing-type.rotel.rsp1069.description = Connexion à un préampli Home-Cinéma Rotel RSP-1069 -thing-type.rotel.rsp1098.label = Préampli Home-Cinéma RSP-1098 +thing-type.rotel.rsp1098.label = Préampli RSP-1098 thing-type.rotel.rsp1098.description = Connexion à un préampli Home-Cinéma Rotel RSP-1098 -thing-type.rotel.rsp1570.label = Préampli Home-Cinéma RSP-1570 +thing-type.rotel.rsp1570.label = Préampli RSP-1570 thing-type.rotel.rsp1570.description = Connexion à un préampli Home-Cinéma Rotel RSP-1570 -thing-type.rotel.rsp1572.label = Préampli Home-Cinéma RSP-1572 +thing-type.rotel.rsp1572.label = Préampli RSP-1572 thing-type.rotel.rsp1572.description = Connexion à un préampli Home-Cinéma Rotel RSP-1572 -thing-type.rotel.rsp1576.label = Préampli Home-Cinéma RSP-1576 +thing-type.rotel.rsp1576.label = Préampli RSP-1576 thing-type.rotel.rsp1576.description = Connexion à un préampli Home-Cinéma Rotel RSP-1576 -thing-type.rotel.rsp1582.label = Préampli Home-Cinéma RSP-1582 +thing-type.rotel.rsp1582.label = Préampli RSP-1582 thing-type.rotel.rsp1582.description = Connexion à un préampli Home-Cinéma Rotel RSP-1582 -thing-type.rotel.rsx1055.label = Ampli Home-Cinéma RSX-1055 +thing-type.rotel.rsx1055.label = Ampli RSX-1055 thing-type.rotel.rsx1055.description = Connexion à un ampli Home-Cinéma Rotel RSX-1055 -thing-type.rotel.rsx1056.label = Ampli Home-Cinéma RSX-1056 +thing-type.rotel.rsx1056.label = Ampli RSX-1056 thing-type.rotel.rsx1056.description = Connexion à un ampli Home-Cinéma Rotel RSX-1056 -thing-type.rotel.rsx1057.label = Ampli Home-Cinéma RSX-1057 +thing-type.rotel.rsx1057.label = Ampli RSX-1057 thing-type.rotel.rsx1057.description = Connexion à un ampli Home-Cinéma Rotel RSX-1057 -thing-type.rotel.rsx1058.label = Ampli Home-Cinéma RSX-1058 +thing-type.rotel.rsx1058.label = Ampli RSX-1058 thing-type.rotel.rsx1058.description = Connexion à un ampli Home-Cinéma Rotel RSX-1058 -thing-type.rotel.rsx1065.label = Ampli Home-Cinéma RSX-1065 +thing-type.rotel.rsx1065.label = Ampli RSX-1065 thing-type.rotel.rsx1065.description = Connexion à un ampli Home-Cinéma Rotel RSX-1065 -thing-type.rotel.rsx1067.label = Ampli Home-Cinéma RSX-1067 +thing-type.rotel.rsx1067.label = Ampli RSX-1067 thing-type.rotel.rsx1067.description = Connexion à un ampli Home-Cinéma Rotel RSX-1067 -thing-type.rotel.rsx1550.label = Ampli Home-Cinéma RSX-1550 +thing-type.rotel.rsx1550.label = Ampli RSX-1550 thing-type.rotel.rsx1550.description = Connexion à un ampli Home-Cinéma Rotel RSX-1550 -thing-type.rotel.rsx1560.label = Ampli Home-Cinéma RSX-1560 +thing-type.rotel.rsx1560.label = Ampli RSX-1560 thing-type.rotel.rsx1560.description = Connexion à un ampli Home-Cinéma Rotel RSX-1560 -thing-type.rotel.rsx1562.label = Ampli Home-Cinéma RSX-1562 +thing-type.rotel.rsx1562.label = Ampli RSX-1562 thing-type.rotel.rsx1562.description = Connexion à un ampli Home-Cinéma Rotel RSX-1562 thing-type.rotel.rt09.label = Tuner RT-09 @@ -185,7 +185,7 @@ config.inputLabelMulti.description = Label affiché par l'appareil pour la sourc # channel group types -channel-group.mainZone.label = Zone principale +channel-group.mainZone.label = Zone Principale channel-group.mainZone.description = Les commandes de la zone principale channel-group.zone2.label = Zone 2 @@ -199,10 +199,10 @@ channel-group.zone4.description = Les commandes de la zone 4 # channel types -channel-type.rotel.source.label = Entrée source +channel-type.rotel.source.label = Entrée Source channel-type.rotel.source.description = Permet de sélectionner la source d'entrée -channel-type.rotel.recordSource.label = Source de l'enregistrement +channel-type.rotel.recordSource.label = Source Enregistrement channel-type.rotel.recordSource.description = Permet de sélectionner la source à enregistrer channel-type.rotel.dsp.label = Mode DSP @@ -238,22 +238,22 @@ channel-type.rotel.dsp.state.option.NEURALX = dts Neural\:X channel-type.rotel.volumeUpDown.label = Volume channel-type.rotel.volumeUpDown.description = Permet d'augmenter ou diminuer le volume -channel-type.rotel.bass.label = Ajustement des graves +channel-type.rotel.bass.label = Ajustement Graves channel-type.rotel.bass.description = Permet d'ajuster les graves -channel-type.rotel.treble.label = Ajustement des aigus +channel-type.rotel.treble.label = Ajustement Aigus channel-type.rotel.treble.description = Permet d'ajuster les aigus -channel-type.rotel.track.label = Piste actuelle +channel-type.rotel.track.label = Piste Actuelle channel-type.rotel.track.description = Le numéro actuel de piste CD -channel-type.rotel.frequency.label = Fréquence actuelle +channel-type.rotel.frequency.label = Fréquence Actuelle channel-type.rotel.frequency.description = La fréquence actuelle (en kHz) sur l'entrée numérique -channel-type.rotel.frontPanelLine.label = Ligne sur l'afficheur en façade +channel-type.rotel.frontPanelLine.label = Ligne Afficheur Façade channel-type.rotel.frontPanelLine.description = Le contenu d'une ligne affichée en façade de l'appareil -channel-type.rotel.brightness.label = Luminosité de l'afficheur en façade +channel-type.rotel.brightness.label = Luminosité Afficheur Façade channel-type.rotel.brightness.description = Le niveau de luminosité (en %) de l'afficheur en façade de l'appareil # Thing status descriptions diff --git a/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/i18n/sonyprojector_fr.properties b/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/i18n/sonyprojector_fr.properties index 31128bc0c4db1..0b886d7a064ee 100644 --- a/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/i18n/sonyprojector_fr.properties +++ b/bundles/org.openhab.binding.sonyprojector/src/main/resources/OH-INF/i18n/sonyprojector_fr.properties @@ -8,10 +8,10 @@ binding.sonyprojector.description = L'extension Projecteur Sony permet de contr thing-type.sonyprojector.ethernetconnection.label = Connexion Ethernet Sony thing-type.sonyprojector.ethernetconnection.description = Connexion Ethernet au projecteur Sony en utilisant PJ Talk. -thing-type.sonyprojector.serialconnection.label = Connexion série Sony +thing-type.sonyprojector.serialconnection.label = Connexion Série Sony thing-type.sonyprojector.serialconnection.description = Connexion série au projecteur Sony. -thing-type.sonyprojector.serialoveripconnection.label = Connexion série sur IP Sony +thing-type.sonyprojector.serialoveripconnection.label = Connexion Série sur IP Sony thing-type.sonyprojector.serialoveripconnection.description = Connexion série sur IP au projecteur Sony. # thing type configuration @@ -46,10 +46,10 @@ thing-type.config.sonyprojector.serialoveripconnection.model.description = Modè # channel types -channel-type.sonyprojector.power.label = Mise sous tension +channel-type.sonyprojector.power.label = Mise Sous Tension channel-type.sonyprojector.power.description = Allume ou éteint le projecteur. -channel-type.sonyprojector.powerstate.label = Etat alimentation +channel-type.sonyprojector.powerstate.label = État Alimentation channel-type.sonyprojector.powerstate.description = État actuel d'alimentation du projecteur. channel-type.sonyprojector.powerstate.state.option.STANDBY = En veille channel-type.sonyprojector.powerstate.state.option.START_UP = Démarrage @@ -57,11 +57,11 @@ channel-type.sonyprojector.powerstate.state.option.STARTUP_LAMP = Démarrage lam channel-type.sonyprojector.powerstate.state.option.POWER_ON = Allumé channel-type.sonyprojector.powerstate.state.option.COOLING1 = Refroidissement 1 channel-type.sonyprojector.powerstate.state.option.COOLING2 = Refroidissement 2 -channel-type.sonyprojector.powerstate.state.option.SAVING_COOLING1 = Economie refroidissement 1 -channel-type.sonyprojector.powerstate.state.option.SAVING_COOLING2 = Economie refroidissement 2 -channel-type.sonyprojector.powerstate.state.option.SAVING_STANDBY = Economie de veille +channel-type.sonyprojector.powerstate.state.option.SAVING_COOLING1 = Économie refroidissement 1 +channel-type.sonyprojector.powerstate.state.option.SAVING_COOLING2 = Économie refroidissement 2 +channel-type.sonyprojector.powerstate.state.option.SAVING_STANDBY = Économie de veille -channel-type.sonyprojector.input.label = Entrée +channel-type.sonyprojector.input.label = Entrée Vidéo channel-type.sonyprojector.input.description = Sélectionne le périphérique à partir duquel les images seront affichées. channel-type.sonyprojector.input.state.option.HDMI = HDMI channel-type.sonyprojector.input.state.option.HDMI1 = HDMI 1 @@ -72,8 +72,8 @@ channel-type.sonyprojector.input.state.option.SVideo = S-Vidéo channel-type.sonyprojector.input.state.option.InputA = Entrée A channel-type.sonyprojector.input.state.option.Component = Composante -channel-type.sonyprojector.calibrationpreset.label = Préréglage étalon -channel-type.sonyprojector.calibrationpreset.description = Sélectionne le mode de visualisation de l'image en sélectionnant l'un des préréglages étalon. +channel-type.sonyprojector.calibrationpreset.label = Préréglage Étalonné +channel-type.sonyprojector.calibrationpreset.description = Sélectionne le mode de visualisation de l'image en sélectionnant l'un des préréglages. channel-type.sonyprojector.calibrationpreset.state.option.Film1 = Cinéma Film 1 channel-type.sonyprojector.calibrationpreset.state.option.Film2 = Cinéma Film 2 channel-type.sonyprojector.calibrationpreset.state.option.Reference = Référence @@ -95,7 +95,7 @@ channel-type.sonyprojector.calibrationpreset.state.option.User3 = Utilisateur 3 channel-type.sonyprojector.calibrationpreset.state.option.Digital = Numérique channel-type.sonyprojector.contrast.label = Contraste -channel-type.sonyprojector.contrast.description = Règle le contraste de l'ìmage. +channel-type.sonyprojector.contrast.description = Règle le contraste de l’mage. channel-type.sonyprojector.brightness.label = Luminosité channel-type.sonyprojector.brightness.description = Règle la luminosité de l'image. @@ -109,7 +109,7 @@ channel-type.sonyprojector.hue.description = Règle la tonalité de couleur. channel-type.sonyprojector.sharpness.label = Netteté channel-type.sonyprojector.sharpness.description = Rend les contours de l'image plus nets ou réduit les parasites. -channel-type.sonyprojector.colortemperature.label = Température couleur +channel-type.sonyprojector.colortemperature.label = Température Couleur channel-type.sonyprojector.colortemperature.description = Règle la température de couleur. channel-type.sonyprojector.colortemperature.state.option.D93 = D93 channel-type.sonyprojector.colortemperature.state.option.D75 = D75 @@ -128,8 +128,8 @@ channel-type.sonyprojector.colortemperature.state.option.Custom3 = Personnalisé channel-type.sonyprojector.colortemperature.state.option.Custom4 = Personnalisé 4 channel-type.sonyprojector.colortemperature.state.option.Custom5 = Personnalisé 5 -channel-type.sonyprojector.irismode.label = Diaphragme avancé -channel-type.sonyprojector.irismode.description = Slélectionne la fonction du diaphragme. +channel-type.sonyprojector.irismode.label = Diaphragme Avancé +channel-type.sonyprojector.irismode.description = Sélectionne la fonction du diaphragme. channel-type.sonyprojector.irismode.state.option.Full = Auto complète channel-type.sonyprojector.irismode.state.option.Limited = Auto limitée channel-type.sonyprojector.irismode.state.option.AutoFull = Auto complète @@ -141,21 +141,21 @@ channel-type.sonyprojector.irismode.state.option.Manual = Manuel channel-type.sonyprojector.irismode.state.option.On = Activé channel-type.sonyprojector.irismode.state.option.Off = Désactivé -channel-type.sonyprojector.irismanual.label = Diaphragme manuel +channel-type.sonyprojector.irismanual.label = Diaphragme Manuel channel-type.sonyprojector.irismanual.description = Règle manuellement le diaphragme à une valeur fixe. -channel-type.sonyprojector.irissensitivity.label = Sensibilité diaphragme +channel-type.sonyprojector.irissensitivity.label = Sensibilité Diaphragme channel-type.sonyprojector.irissensitivity.description = Règle la sensibilité du diaphragme. channel-type.sonyprojector.irissensitivity.state.option.Recommend = Recommandé channel-type.sonyprojector.irissensitivity.state.option.Fast = Rapide channel-type.sonyprojector.irissensitivity.state.option.Slow = Lent -channel-type.sonyprojector.lampcontrol.label = Commande lampe +channel-type.sonyprojector.lampcontrol.label = Commande Lampe channel-type.sonyprojector.lampcontrol.description = Règle le niveau de sortie de la lampe. channel-type.sonyprojector.lampcontrol.state.option.High = Haut channel-type.sonyprojector.lampcontrol.state.option.Low = Bas -channel-type.sonyprojector.filmprojection.label = Projection +channel-type.sonyprojector.filmprojection.label = Projection Film channel-type.sonyprojector.filmprojection.description = Reproduit une image similaire à celle d'un film projeté. channel-type.sonyprojector.filmprojection.state.option.Mode1 = Mode 1 channel-type.sonyprojector.filmprojection.state.option.Mode2 = Mode 2 @@ -163,7 +163,7 @@ channel-type.sonyprojector.filmprojection.state.option.Mode3 = Mode 3 channel-type.sonyprojector.filmprojection.state.option.On = Activé channel-type.sonyprojector.filmprojection.state.option.Off = Désactivé -channel-type.sonyprojector.motionenhancer.label = Meilleur mouvement +channel-type.sonyprojector.motionenhancer.label = Meilleur Mouvement channel-type.sonyprojector.motionenhancer.description = Reproduit des images en mouvement rapide sans rémanence. channel-type.sonyprojector.motionenhancer.state.option.High = Haut channel-type.sonyprojector.motionenhancer.state.option.Low = Bas @@ -174,21 +174,21 @@ channel-type.sonyprojector.motionenhancer.state.option.Impulse = Impulsion channel-type.sonyprojector.motionenhancer.state.option.Combination = Combinaison channel-type.sonyprojector.motionenhancer.state.option.Off = Désactivé -channel-type.sonyprojector.contrastenhancer.label = Accentuation contraste +channel-type.sonyprojector.contrastenhancer.label = Accentuation Contraste channel-type.sonyprojector.contrastenhancer.description = Ajuste automatiquement le niveau des zones lumineuses et des zones sombres pour améliorer le contraste en fonction de la scène. channel-type.sonyprojector.contrastenhancer.state.option.High = Haut channel-type.sonyprojector.contrastenhancer.state.option.Middle = Moyen channel-type.sonyprojector.contrastenhancer.state.option.Low = Bas channel-type.sonyprojector.contrastenhancer.state.option.Off = Désactivé -channel-type.sonyprojector.filmmode.label = Mode film +channel-type.sonyprojector.filmmode.label = Mode Film channel-type.sonyprojector.filmmode.description = Sélectionne le mode de lecture pour une source film. channel-type.sonyprojector.filmmode.state.option.Auto = Auto channel-type.sonyprojector.filmmode.state.option.Auto1 = Auto 1 channel-type.sonyprojector.filmmode.state.option.Auto2 = Auto 2 channel-type.sonyprojector.filmmode.state.option.Off = Désactivé -channel-type.sonyprojector.gammacorrection.label = Correction gamma +channel-type.sonyprojector.gammacorrection.label = Correction Gamma channel-type.sonyprojector.gammacorrection.description = Règle les caractéristiques de transfert de la tonalité d'image. channel-type.sonyprojector.gammacorrection.state.option.Gamma1 = Gamma 1 channel-type.sonyprojector.gammacorrection.state.option.Gamma2 = Gamma 2 @@ -202,7 +202,7 @@ channel-type.sonyprojector.gammacorrection.state.option.Gamma9 = Gamma 9 channel-type.sonyprojector.gammacorrection.state.option.Gamma10 = Gamma 10 channel-type.sonyprojector.gammacorrection.state.option.Off = Désactivé -channel-type.sonyprojector.colorspace.label = Espace couleur +channel-type.sonyprojector.colorspace.label = Espace Couleur channel-type.sonyprojector.colorspace.description = Convertit l'espace colorimétrique. channel-type.sonyprojector.colorspace.state.option.BT709 = BT.709 channel-type.sonyprojector.colorspace.state.option.BT2020 = BT.2020 @@ -218,7 +218,7 @@ channel-type.sonyprojector.colorspace.state.option.Wide3 = Large 3 channel-type.sonyprojector.colorspace.state.option.DCI = DCI channel-type.sonyprojector.colorspace.state.option.AdobeRGB = Adobe RGB -channel-type.sonyprojector.nr.label = Réduction du bruit +channel-type.sonyprojector.nr.label = Réduction Bruit channel-type.sonyprojector.nr.description = Réduit le flou ou les parasites de l'image. channel-type.sonyprojector.nr.state.option.Auto = Automatique channel-type.sonyprojector.nr.state.option.High = Haut @@ -226,21 +226,21 @@ channel-type.sonyprojector.nr.state.option.Middle = Moyen channel-type.sonyprojector.nr.state.option.Low = Bas channel-type.sonyprojector.nr.state.option.Off = Désactivé -channel-type.sonyprojector.blocknr.label = Réduction du bruit de bloc +channel-type.sonyprojector.blocknr.label = Réduction Bruit Bloc channel-type.sonyprojector.blocknr.description = Réduit le bruit de bloc, tout particulièrement sur les signaux numériques. channel-type.sonyprojector.blocknr.state.option.High = Haut channel-type.sonyprojector.blocknr.state.option.Middle = Moyen channel-type.sonyprojector.blocknr.state.option.Low = Bas channel-type.sonyprojector.blocknr.state.option.Off = Désactivé -channel-type.sonyprojector.mosquitonr.label = Réduction du bruit mosquito +channel-type.sonyprojector.mosquitonr.label = Réduction Bruit Mosquito channel-type.sonyprojector.mosquitonr.description = Réduit le bruit mosquito, tout particulièrement sur les signaux numériques. channel-type.sonyprojector.mosquitonr.state.option.High = Haut channel-type.sonyprojector.mosquitonr.state.option.Middle = Moyen channel-type.sonyprojector.mosquitonr.state.option.Low = Bas channel-type.sonyprojector.mosquitonr.state.option.Off = Désactivé -channel-type.sonyprojector.mpegnr.label = Réduction du bruit MPEG +channel-type.sonyprojector.mpegnr.label = Réduction Bruit MPEG channel-type.sonyprojector.mpegnr.description = Réduit le bruit de bloc et le bruit mosquito, tout particulièrement sur les signaux numériques. channel-type.sonyprojector.mpegnr.state.option.Auto = Automatique channel-type.sonyprojector.mpegnr.state.option.High = Haut @@ -251,16 +251,16 @@ channel-type.sonyprojector.mpegnr.state.option.Off = Désactivé channel-type.sonyprojector.xvcolor.label = x.v.Color channel-type.sonyprojector.xvcolor.description = Activer cette option lors de la visualisation d'un signal vidéo x.v.Color. -channel-type.sonyprojector.picturemuting.label = Coupure affichage +channel-type.sonyprojector.picturemuting.label = Coupure Affichage channel-type.sonyprojector.picturemuting.description = Coupe ou restaure l'affichage de l'image. channel-type.sonyprojector.aspect.label = Aspect channel-type.sonyprojector.aspect.description = Définit le rapport de format de l'image à afficher. channel-type.sonyprojector.aspect.state.option.Normal = Normal -channel-type.sonyprojector.aspect.state.option.VStretch = Etirement vertical +channel-type.sonyprojector.aspect.state.option.VStretch = Étirement vertical channel-type.sonyprojector.aspect.state.option.185 = Zoom 1.85\:1 channel-type.sonyprojector.aspect.state.option.235 = Zoom 2.35\:1 -channel-type.sonyprojector.aspect.state.option.Stretch = Etirer +channel-type.sonyprojector.aspect.state.option.Stretch = Étirer channel-type.sonyprojector.aspect.state.option.Squeeze = Serrer channel-type.sonyprojector.aspect.state.option.Full = Plein channel-type.sonyprojector.aspect.state.option.Full1 = Plein 1 @@ -273,7 +273,7 @@ channel-type.sonyprojector.aspect.state.option.Subtitle = Sous-titre channel-type.sonyprojector.overscan.label = Surscannage channel-type.sonyprojector.overscan.description = Cache ou non les contours de l'image. -channel-type.sonyprojector.pictureposition.label = Position image +channel-type.sonyprojector.pictureposition.label = Position Image channel-type.sonyprojector.pictureposition.description = Règle la position de l'image. channel-type.sonyprojector.pictureposition.state.option.185 = 1.85\:1 channel-type.sonyprojector.pictureposition.state.option.235 = 2.35\:1 @@ -286,7 +286,7 @@ channel-type.sonyprojector.pictureposition.state.option.Position3 = Position 3 channel-type.sonyprojector.pictureposition.state.option.Position4 = Position 4 channel-type.sonyprojector.pictureposition.state.option.Position5 = Position 5 -channel-type.sonyprojector.lampusetime.label = Durée de lampe +channel-type.sonyprojector.lampusetime.label = Durée Utilisation Lampe channel-type.sonyprojector.lampusetime.description = Indique la durée en heures pendant laquelle la lampe a été allumée (temps total d'utilisation). # Thing status descriptions diff --git a/bundles/org.openhab.binding.surepetcare/src/main/resources/OH-INF/i18n/surepetcare_de.properties b/bundles/org.openhab.binding.surepetcare/src/main/resources/OH-INF/i18n/surepetcare_de.properties index b78c4fc436e19..68512c7d0ef5f 100644 --- a/bundles/org.openhab.binding.surepetcare/src/main/resources/OH-INF/i18n/surepetcare_de.properties +++ b/bundles/org.openhab.binding.surepetcare/src/main/resources/OH-INF/i18n/surepetcare_de.properties @@ -12,10 +12,10 @@ thing-type.config.surepetcare.bridge.username.description = Sure Petcare Benutze thing-type.config.surepetcare.bridge.password.label = Sure Petcare Passwort thing-type.config.surepetcare.bridge.password.description = Sure Petcare Passwort. -thing-type.config.surepetcare.bridge.refreshIntervalStatus.label = Abfrageintervall Haustier Status +thing-type.config.surepetcare.bridge.refreshIntervalStatus.label = Aktualisierungsintervall Haustier Status thing-type.config.surepetcare.bridge.refreshIntervalStatus.description = Intervall zur Abfrage des Haustier Status (in Sekunden) (mind. 300 / standard 36000). -thing-type.config.surepetcare.bridge.refreshIntervalTopology.label = Abfrageintervall Topology +thing-type.config.surepetcare.bridge.refreshIntervalTopology.label = Aktualisierungsintervall Topology thing-type.config.surepetcare.bridge.refreshIntervalTopology.description = Intervall zur Abfrage der Geräte und Haustier Daten (in Sekunden) (mind. 300 / standard 300). # thing-types @@ -51,7 +51,7 @@ channel-type.surepetcare.timezoneIdType.label = Zeitzone ID channel-type.surepetcare.timezoneIdType.description = Zeigt die ID der Zeitzone an. channel-type.surepetcare.productType.label = Produkt Typ -channel-type.surepetcare.productType.description = Zeigt den Produkt Namen an. #(0=unbekannt, 1=Hub, 3=Haustierklappe, 4=Futterautomat, 6=Katzenklappe) +channel-type.surepetcare.productType.description = Zeigt den Produkt Namen an. \#(0\=unbekannt, 1\=Hub, 3\=Haustierklappe, 4\=Futterautomat, 6\=Katzenklappe) channel-type.surepetcare.productType.state.option.0 = unbekannt channel-type.surepetcare.productType.state.option.1 = Hub channel-type.surepetcare.productType.state.option.3 = Haustierklappe @@ -260,7 +260,7 @@ channel-type.surepetcare.bowlsTrainingModeType.state.option.3 = Halb geschlossen channel-type.surepetcare.bowlsTrainingModeType.state.option.4 = Fast geschlossen # Thing status description -offline.conf-error-invalid-refresh-intervals = Ungültiger Aktualisierungs-Intervall. -offline.conf-error-missing-username-or-password = Benutzername oder Passowrt fehlt. +offline.conf-error-invalid-refresh-intervals = Ungültiges Aktualisierungsintervall. +offline.conf-error-missing-username-or-password = Benutzername oder Passwort fehlt. offline.conf-error-authentication = Authentifizierungs-Fehler. diff --git a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064_de.properties b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064_de.properties index cb3d82e42498e..c2b722acea61d 100644 --- a/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064_de.properties +++ b/bundles/org.openhab.binding.tr064/src/main/resources/OH-INF/i18n/tr064_de.properties @@ -3,7 +3,7 @@ profile.config.transform.PHONEBOOK.phonebook.label = Telefonbuch profile.config.transform.PHONEBOOK.phonebook.description = Der Name des Telefonbuches. profile.config.transform.PHONEBOOK.matchCount.label = Übereinstimmungen profile.config.transform.PHONEBOOK.matchCount.description = Die Anzahl der Ziffern, die mit dem eingehenden Wert übereinstimmen, von rechts gezählt (Vorgabe ist 0 \= alle müssen übereinstimmen). -profile.config.transform.PHONEBOOK.phoneNumberIndex.label = Telefonnummern-Index +profile.config.transform.PHONEBOOK.phoneNumberIndex.label = Telefonnummer-Index profile.config.transform.PHONEBOOK.phoneNumberIndex.description = Der Index der Telefonnummer, die aus einem CallItem-State (StringListType) aufgelöst werden soll, 0 oder 1 (Vorgabe ist 0). # actions diff --git a/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties index 9c5dae830cba4..8fb124aa0d3c0 100644 --- a/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties +++ b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/i18n/tradfri_fr.properties @@ -7,21 +7,21 @@ binding.tradfri.description = Cette extension apporte le support des appareils I thing-type.tradfri.0010.label = Prise On/Off thing-type.tradfri.0010.description = Une prise qui peut être allumée et éteinte. -thing-type.tradfri.0100.label = Ampoule à intensité lumineuse réglable +thing-type.tradfri.0100.label = Ampoule Avec Variation thing-type.tradfri.0100.description = Une ampoule avec contrôle de la l'intensité lumineuse. -thing-type.tradfri.0107.label = Capteur de présence +thing-type.tradfri.0107.label = Capteur Présence thing-type.tradfri.0107.description = Un détecteur de mouvement capable aussi de signaler le niveau de la batterie. -thing-type.tradfri.0202.label = Store ou rideau +thing-type.tradfri.0202.label = Store thing-type.tradfri.0202.description = Un store ou un rideau qui peut être déplacé vers le haut ou vers le bas. Fournit également le niveau actuel de la batterie. -thing-type.tradfri.0203.label = Télécommande pour store ou rideau +thing-type.tradfri.0203.label = Télécommande Store thing-type.tradfri.0203.description = Une télécommande sans fil pour ouvrir ou fermer le store ou le rideau, capable aussi de signaler le niveau de la batterie. -thing-type.tradfri.0210.label = Ampoule couleur +thing-type.tradfri.0210.label = Ampoule Couleur thing-type.tradfri.0210.description = Une ampoule à intensité variable et avec réglage de la couleur et de la température de couleur. -thing-type.tradfri.0220.label = Ampoule avec température de couleur réglable +thing-type.tradfri.0220.label = Ampoule Température Couleur thing-type.tradfri.0220.description = Une ampoule à intensité variable et avec réglage de la température de couleur. thing-type.tradfri.0820.label = Variateur thing-type.tradfri.0820.description = Un variateur sans fil capable aussi de signaler le niveau de la batterie. -thing-type.tradfri.0830.label = Télécommande de scénario +thing-type.tradfri.0830.label = Télécommande Scénario thing-type.tradfri.0830.description = Une télécommande capable de signaler le niveau de la batterie. thing-type.tradfri.gateway.label = Passerelle TRÅDFRI thing-type.tradfri.gateway.description = Passerelle IP IKEA TRÅDFRI diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties index 6903c0aec6b44..e492b56048a9b 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties @@ -4,8 +4,8 @@ service.io.openhabcloud.label = openHAB Cloud # bundle config -io.config.openhabcloud.baseURL.label = Basis-URL -io.config.openhabcloud.baseURL.description = Basis-URL des openHAB Cloud-Servers. +io.config.openhabcloud.baseURL.label = URL +io.config.openhabcloud.baseURL.description = URL des openHAB Cloud-Servers. io.config.openhabcloud.expose.label = Veröffentlichte Items io.config.openhabcloud.expose.description = Liste der Items, die für IFTTT und ähnliche Dienste veröffentlicht werden. io.config.openhabcloud.mode.label = Funktionen diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties new file mode 100644 index 0000000000000..dd708656a2642 --- /dev/null +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties @@ -0,0 +1,14 @@ +# service + +service.io.openhabcloud.label = Cloud openHAB + +# bundle config + +io.config.openhabcloud.baseURL.label = URL de base +io.config.openhabcloud.baseURL.description = URL de base pour le serveur Cloud openHAB. +io.config.openhabcloud.expose.label = Éléments à exposer +io.config.openhabcloud.expose.description = Liste des éléments ('"items") qui sont rendus accessibles à IFTTT et services similaires. +io.config.openhabcloud.mode.label = Mode +io.config.openhabcloud.mode.description = Les fonctionnalités du service Cloud openHAB à utiliser. +io.config.openhabcloud.mode.option.notification = Notifications +io.config.openhabcloud.mode.option.remote = Notifications et accès à distance diff --git a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties new file mode 100644 index 0000000000000..c0ae16aaa281d --- /dev/null +++ b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties @@ -0,0 +1,6 @@ +# bundle config + +profile.config.transform.function.label = Nom du fichier +profile.config.transform.function.description = Nom du fichier contenant les informations de mappage. +profile.config.transform.sourceFormat.label = Formatage de l'état +profile.config.transform.sourceFormat.description = Comment formater l'état du canal avant de le transformer, par exemple %s ou %.1f °C (par défaut %s) diff --git a/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_fr.properties b/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_fr.properties new file mode 100644 index 0000000000000..a8ad0ec2ee6d8 --- /dev/null +++ b/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_fr.properties @@ -0,0 +1,8 @@ +# service + +service.voice.voicerss.label = Synthèse vocale VoiceRSS + +# bundle config + +voice.config.voicerss.apiKey.label = Clé API VoiceRSS +voice.config.voicerss.apiKey.description = La clé API pour avoir accès à http\://www.voicerss.org. Vous devez vous enregistrer avec au moins un compte gratuit pour obtenir une clé API. From c4b0c298e11362bedca75e57849b0680be9786ac Mon Sep 17 00:00:00 2001 From: mlobstein Date: Tue, 23 Nov 2021 06:18:30 -0600 Subject: [PATCH 131/361] Fix setpoint parsing error (#11635) Signed-off-by: Michael Lobstein Signed-off-by: Michael Schmidt --- .../README.md | 10 +++++----- .../internal/dto/RadioThermostatTstatDTO.java | 16 ++++++++-------- .../internal/handler/RadioThermostatHandler.java | 11 ++++++----- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/bundles/org.openhab.binding.radiothermostat/README.md b/bundles/org.openhab.binding.radiothermostat/README.md index 0babb2ce3e39e..74f87b317a966 100644 --- a/bundles/org.openhab.binding.radiothermostat/README.md +++ b/bundles/org.openhab.binding.radiothermostat/README.md @@ -74,7 +74,7 @@ The thermostat information that is retrieved is available as these channels: radiotherm.map: -```text +``` UNDEF_stus=- NULL_stus=- -_stus=- @@ -117,14 +117,14 @@ NULL_over=- radiotherm.things: -```java +``` radiothermostat:rtherm:mytherm1 "My 1st floor thermostat" [ hostName="192.168.10.1", refresh=2, logRefresh=10, isCT80=false, disableLogs=false, setpointMode="temporary" ] radiothermostat:rtherm:mytherm2 "My 2nd floor thermostat" [ hostName="mythermhost2", refresh=1, logRefresh=20, isCT80=true, disableLogs=false, setpointMode="absolute" ] ``` radiotherm.items: -```java +``` Number:Temperature Therm_Temp "Current Temperature [%.1f °F] " { channel="radiothermostat:rtherm:mytherm1:temperature" } // Humidity only supported on CT80 Number Therm_Hum "Current Humidity [%d %%]" { channel="radiothermostat:rtherm:mytherm1:humidity" } @@ -158,7 +158,7 @@ Switch Therm_mysetting "Send my preferred setting" radiotherm.sitemap: -```perl +``` sitemap radiotherm label="My Thermostat" { Frame label="My 1st floor thermostat" { Text item=Therm_Temp icon="temperature" valuecolor=[>76="orange",>67.5="green",<=67.5="blue"] @@ -196,7 +196,7 @@ sitemap radiotherm label="My Thermostat" { radiotherm.rules: -```java +``` rule "Send my thermostat command" when Item Therm_mysetting received command diff --git a/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/dto/RadioThermostatTstatDTO.java b/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/dto/RadioThermostatTstatDTO.java index 35304cfd94688..02e495901c898 100644 --- a/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/dto/RadioThermostatTstatDTO.java +++ b/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/dto/RadioThermostatTstatDTO.java @@ -35,10 +35,10 @@ public class RadioThermostatTstatDTO { private Integer programMode; @SerializedName("t_heat") - private Integer heatTarget; + private Double heatTarget; @SerializedName("t_cool") - private Integer coolTarget; + private Double coolTarget; @SerializedName("override") private Integer override; @@ -86,19 +86,19 @@ public void setProgramMode(Integer programMode) { this.programMode = programMode; } - public Integer getHeatTarget() { + public Double getHeatTarget() { return heatTarget; } - public void setHeatTarget(Integer heatTarget) { + public void setHeatTarget(Double heatTarget) { this.heatTarget = heatTarget; } - public Integer getCoolTarget() { + public Double getCoolTarget() { return coolTarget; } - public void setCoolTarget(Integer coolTarget) { + public void setCoolTarget(Double coolTarget) { this.coolTarget = coolTarget; } @@ -129,9 +129,9 @@ public Integer getFanStatus() { */ public Integer getSetpoint() { if (mode == 1) { - return heatTarget; + return heatTarget.intValue(); } else if (mode == 2) { - return coolTarget; + return coolTarget.intValue(); } else { return 0; } diff --git a/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/handler/RadioThermostatHandler.java b/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/handler/RadioThermostatHandler.java index 698efe76ef8fc..af2b3f945fdef 100644 --- a/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/handler/RadioThermostatHandler.java +++ b/bundles/org.openhab.binding.radiothermostat/src/main/java/org/openhab/binding/radiothermostat/internal/handler/RadioThermostatHandler.java @@ -233,7 +233,8 @@ private void startAutomaticLogRefresh() { }; logRefreshJob = null; - this.logRefreshJob = scheduler.scheduleWithFixedDelay(runnable, 1, logRefreshPeriod, TimeUnit.MINUTES); + this.logRefreshJob = scheduler.scheduleWithFixedDelay(runnable, (!this.clockSync ? 1 : 2), logRefreshPeriod, + TimeUnit.MINUTES); } } @@ -289,8 +290,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { // set the new operating mode, reset everything else, // because refreshing the tstat data below is really slow. rthermData.getThermostatData().setMode(cmdInt); - rthermData.getThermostatData().setHeatTarget(0); - rthermData.getThermostatData().setCoolTarget(0); + rthermData.getThermostatData().setHeatTarget(Double.valueOf(0)); + rthermData.getThermostatData().setCoolTarget(Double.valueOf(0)); updateChannel(SET_POINT, rthermData); rthermData.getThermostatData().setHold(0); updateChannel(HOLD, rthermData); @@ -323,10 +324,10 @@ public void handleCommand(ChannelUID channelUID, Command command) { String cmdKey = null; if (rthermData.getThermostatData().getMode() == 1) { cmdKey = this.setpointCmdKeyPrefix + "heat"; - rthermData.getThermostatData().setHeatTarget(cmdInt); + rthermData.getThermostatData().setHeatTarget(Double.valueOf(cmdInt)); } else if (rthermData.getThermostatData().getMode() == 2) { cmdKey = this.setpointCmdKeyPrefix + "cool"; - rthermData.getThermostatData().setCoolTarget(cmdInt); + rthermData.getThermostatData().setCoolTarget(Double.valueOf(cmdInt)); } else { // don't do anything if we are not in heat or cool mode break; From 51e8d348d52d88137d3827bc21eeb4d20c932f34 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Tue, 23 Nov 2021 23:05:09 +0100 Subject: [PATCH 132/361] Resolve runbundles for JUnit and Mockito dependency upgrades (#11617) Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../itest.bndrun | 22 ++++++++--------- .../itest.bndrun | 20 ++++++++-------- .../itest.bndrun | 12 +++++----- .../itest.bndrun | 12 +++++----- .../itest.bndrun | 12 +++++----- .../itest.bndrun | 20 ++++++++-------- .../itest.bndrun | 24 +++++++++---------- .../itest.bndrun | 22 ++++++++--------- .../itest.bndrun | 20 ++++++++-------- .../itest.bndrun | 20 ++++++++-------- .../itest.bndrun | 22 ++++++++--------- .../itest.bndrun | 20 ++++++++-------- .../itest.bndrun | 12 +++++----- 13 files changed, 119 insertions(+), 119 deletions(-) diff --git a/itests/org.openhab.binding.astro.tests/itest.bndrun b/itests/org.openhab.binding.astro.tests/itest.bndrun index e265ddfc99a9e..0116b30104a05 100644 --- a/itests/org.openhab.binding.astro.tests/itest.bndrun +++ b/itests/org.openhab.binding.astro.tests/itest.bndrun @@ -15,16 +15,6 @@ Fragment-Host: org.openhab.binding.astro com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-jupiter-params;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -50,4 +40,14 @@ Fragment-Host: org.openhab.binding.astro org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-jupiter-params;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun index bb71acf13d6b3..a7670b4b6036e 100644 --- a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun +++ b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun @@ -22,15 +22,6 @@ Fragment-Host: org.openhab.binding.avmfritz jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -75,4 +66,13 @@ Fragment-Host: org.openhab.binding.avmfritz org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.feed.tests/itest.bndrun b/itests/org.openhab.binding.feed.tests/itest.bndrun index 91b4b727a2ed3..7a8e614b2a9f3 100644 --- a/itests/org.openhab.binding.feed.tests/itest.bndrun +++ b/itests/org.openhab.binding.feed.tests/itest.bndrun @@ -26,11 +26,6 @@ Fragment-Host: org.openhab.binding.feed com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -75,4 +70,9 @@ Fragment-Host: org.openhab.binding.feed org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)' diff --git a/itests/org.openhab.binding.hue.tests/itest.bndrun b/itests/org.openhab.binding.hue.tests/itest.bndrun index 130bd397a5155..cab24b5c3e6e2 100644 --- a/itests/org.openhab.binding.hue.tests/itest.bndrun +++ b/itests/org.openhab.binding.hue.tests/itest.bndrun @@ -26,11 +26,6 @@ Fragment-Host: org.openhab.binding.hue com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -79,4 +74,9 @@ Fragment-Host: org.openhab.binding.hue org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)' diff --git a/itests/org.openhab.binding.max.tests/itest.bndrun b/itests/org.openhab.binding.max.tests/itest.bndrun index 7c20ee86c83b8..d26cdf945fac0 100644 --- a/itests/org.openhab.binding.max.tests/itest.bndrun +++ b/itests/org.openhab.binding.max.tests/itest.bndrun @@ -24,11 +24,6 @@ Fragment-Host: org.openhab.binding.max com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ @@ -66,4 +61,9 @@ Fragment-Host: org.openhab.binding.max org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)' diff --git a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun index 83585371147c2..d57509e7e8320 100644 --- a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun +++ b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun @@ -24,16 +24,7 @@ Fragment-Host: org.openhab.binding.mielecloud jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.opentest4j;version='[1.2.0,1.2.1)',\ org.hamcrest;version='[2.2.0,2.2.1)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ @@ -85,4 +76,13 @@ Fragment-Host: org.openhab.binding.mielecloud org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.modbus.tests/itest.bndrun b/itests/org.openhab.binding.modbus.tests/itest.bndrun index 1743c9d196411..67013583741b6 100644 --- a/itests/org.openhab.binding.modbus.tests/itest.bndrun +++ b/itests/org.openhab.binding.modbus.tests/itest.bndrun @@ -26,17 +26,6 @@ Fragment-Host: org.openhab.binding.modbus com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ - org.mockito.junit-jupiter;version='[3.7.0,3.7.1)',\ - junit-jupiter-params;version='[5.7.0,5.7.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -75,4 +64,15 @@ Fragment-Host: org.openhab.binding.modbus org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-jupiter-params;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.nest.tests/itest.bndrun b/itests/org.openhab.binding.nest.tests/itest.bndrun index 747d200d2855d..68df43967f27b 100644 --- a/itests/org.openhab.binding.nest.tests/itest.bndrun +++ b/itests/org.openhab.binding.nest.tests/itest.bndrun @@ -26,16 +26,6 @@ Fragment-Host: org.openhab.binding.nest jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.junit-jupiter;version='[3.7.0,3.7.1)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.apache.aries.javax.jax.rs-api;version='[1.0.1,1.0.2)',\ @@ -104,4 +94,14 @@ Fragment-Host: org.openhab.binding.nest org.apache.cxf.cxf-rt-security;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-transports-http;version='[3.4.5,3.4.6)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.ntp.tests/itest.bndrun b/itests/org.openhab.binding.ntp.tests/itest.bndrun index 5f8338cbc24f1..745c4789664f6 100644 --- a/itests/org.openhab.binding.ntp.tests/itest.bndrun +++ b/itests/org.openhab.binding.ntp.tests/itest.bndrun @@ -25,15 +25,6 @@ Fragment-Host: org.openhab.binding.ntp com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -70,4 +61,13 @@ Fragment-Host: org.openhab.binding.ntp org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index fef7f3d9e1e04..6f15aaadeef8c 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -26,15 +26,6 @@ Fragment-Host: org.openhab.binding.systeminfo com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -73,4 +64,13 @@ Fragment-Host: org.openhab.binding.systeminfo com.sun.jna.platform;version='[5.9.0,5.9.1)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.tradfri.tests/itest.bndrun b/itests/org.openhab.binding.tradfri.tests/itest.bndrun index 62b4b0d96888d..2e2d0c6d110d1 100644 --- a/itests/org.openhab.binding.tradfri.tests/itest.bndrun +++ b/itests/org.openhab.binding.tradfri.tests/itest.bndrun @@ -28,16 +28,6 @@ Fragment-Host: org.openhab.binding.tradfri com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.junit-jupiter;version='[3.7.0,3.7.1)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -76,4 +66,14 @@ Fragment-Host: org.openhab.binding.tradfri org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.binding.wemo.tests/itest.bndrun b/itests/org.openhab.binding.wemo.tests/itest.bndrun index 7e73d49e08b4e..40cd8ce485885 100644 --- a/itests/org.openhab.binding.wemo.tests/itest.bndrun +++ b/itests/org.openhab.binding.wemo.tests/itest.bndrun @@ -25,15 +25,6 @@ Fragment-Host: org.openhab.binding.wemo com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ - net.bytebuddy.byte-buddy;version='[1.10.19,1.10.20)',\ - net.bytebuddy.byte-buddy-agent;version='[1.10.19,1.10.20)',\ - org.mockito.mockito-core;version='[3.7.0,3.7.1)',\ - org.objenesis;version='[3.1.0,3.1.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -83,4 +74,13 @@ Fragment-Host: org.openhab.binding.wemo org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ + net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ + org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ + org.objenesis;version='[3.2.0,3.2.1)' diff --git a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun index 1e54765adc071..3f01089e37192 100644 --- a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun +++ b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun @@ -24,11 +24,6 @@ Fragment-Host: org.openhab.persistence.mapdb com.sun.xml.bind.jaxb-osgi;version='[2.3.3,2.3.4)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ - junit-jupiter-api;version='[5.7.0,5.7.1)',\ - junit-jupiter-engine;version='[5.7.0,5.7.1)',\ - junit-platform-commons;version='[1.7.0,1.7.1)',\ - junit-platform-engine;version='[1.7.0,1.7.1)',\ - junit-platform-launcher;version='[1.7.0,1.7.1)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.osgi.util.function;version='[1.1.0,1.1.1)',\ @@ -57,4 +52,9 @@ Fragment-Host: org.openhab.persistence.mapdb org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ - si.uom.si-quantity;version='[2.1.0,2.1.1)' + si.uom.si-quantity;version='[2.1.0,2.1.1)',\ + junit-jupiter-api;version='[5.8.1,5.8.2)',\ + junit-jupiter-engine;version='[5.8.1,5.8.2)',\ + junit-platform-commons;version='[1.8.1,1.8.2)',\ + junit-platform-engine;version='[1.8.1,1.8.2)',\ + junit-platform-launcher;version='[1.8.1,1.8.2)' From 98e537856e972accdc517d4049240d6c63ea461e Mon Sep 17 00:00:00 2001 From: antroids <36043354+antroids@users.noreply.github.com> Date: Wed, 24 Nov 2021 21:26:23 +0100 Subject: [PATCH 133/361] [MQTT.Homeassistant] added myself to CODEOWNERS (#11612) Signed-off-by: Anton Kharuzhy Signed-off-by: Michael Schmidt --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 39c06fd675a12..b955ee54d392e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -192,7 +192,7 @@ /bundles/org.openhab.binding.mqtt/ @davidgraeff /bundles/org.openhab.binding.mqtt.espmilighthub/ @Skinah /bundles/org.openhab.binding.mqtt.generic/ @davidgraeff -/bundles/org.openhab.binding.mqtt.homeassistant/ @davidgraeff +/bundles/org.openhab.binding.mqtt.homeassistant/ @davidgraeff @antroids /bundles/org.openhab.binding.mqtt.homie/ @davidgraeff /bundles/org.openhab.binding.myq/ @digitaldan /bundles/org.openhab.binding.mystrom/ @pail23 From e18f2f39275c88e3d89d5841a3b2c9db2a263a04 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Fri, 26 Nov 2021 23:01:44 +0100 Subject: [PATCH 134/361] Added representation-property to thing type definitions (#11640) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../discovery/AVMFritzUpnpDiscoveryParticipant.java | 13 ++++--------- .../main/resources/OH-INF/thing/bridge-types.xml | 4 ++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java index b9c2e14069d33..fa42200ce5a0a 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java @@ -16,7 +16,6 @@ import static org.openhab.core.thing.Thing.PROPERTY_VENDOR; import java.util.Dictionary; -import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -28,6 +27,7 @@ import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant; +import org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; import org.osgi.service.component.ComponentContext; @@ -83,16 +83,11 @@ public Set getSupportedThingTypeUIDs() { if (uid != null) { logger.debug("discovered: {} ({}) at {}", device.getDisplayString(), device.getDetails().getFriendlyName(), device.getIdentity().getDescriptorURL().getHost()); - - Map properties = new HashMap<>(); - properties.put(CONFIG_IP_ADDRESS, device.getIdentity().getDescriptorURL().getHost()); - properties.put(PROPERTY_VENDOR, device.getDetails().getManufacturerDetails().getManufacturer()); - - DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties) + return DiscoveryResultBuilder.create(uid) + .withProperties(Map.of(CONFIG_IP_ADDRESS, device.getIdentity().getDescriptorURL().getHost(), + PROPERTY_VENDOR, device.getDetails().getManufacturerDetails().getManufacturer())) .withLabel(device.getDetails().getFriendlyName()).withRepresentationProperty(CONFIG_IP_ADDRESS) .build(); - - return result; } } return null; diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/bridge-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/bridge-types.xml index 8823f8c37967e..a3aa4405332bc 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/bridge-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/bridge-types.xml @@ -17,6 +17,8 @@ + ipAddress + @@ -34,6 +36,8 @@ + ipAddress + From 0533bf7e92bb6d3e1e014d74064035f5cdfc9e86 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sun, 28 Nov 2021 13:31:56 +0100 Subject: [PATCH 135/361] [linky] Few debug logs added (#11647) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../openhab/binding/linky/internal/api/EnedisHttpApi.java | 1 + .../openhab/binding/linky/internal/handler/LinkyHandler.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java index 47f964df666aa..025dc2e86fc29 100644 --- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java +++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/api/EnedisHttpApi.java @@ -120,6 +120,7 @@ public void initialize() throws LinkyException { if (authData == null || authData.callbacks.size() < 2 || authData.callbacks.get(0).input.isEmpty() || authData.callbacks.get(1).input.isEmpty() || !config.username .equals(Objects.requireNonNull(authData.callbacks.get(0).input.get(0)).valueAsString())) { + logger.debug("auth1 - invalid template for auth data: {}", result.getContentAsString()); throw new LinkyException("Authentication error, the authentication_cookie is probably wrong"); } diff --git a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java index 6b325f0370432..2e16205ad053c 100644 --- a/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java +++ b/bundles/org.openhab.binding.linky/src/main/java/org/openhab/binding/linky/internal/handler/LinkyHandler.java @@ -369,6 +369,7 @@ private List buildReport(LocalDate startDay, LocalDate endDay, @Nullable updateStatus(ThingStatus.ONLINE); return consumption; } catch (LinkyException e) { + logger.debug("Exception when getting consumption data: {}", e.getMessage(), e); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage()); } } @@ -385,6 +386,7 @@ private List buildReport(LocalDate startDay, LocalDate endDay, @Nullable updateStatus(ThingStatus.ONLINE); return consumption; } catch (LinkyException e) { + logger.debug("Exception when getting power data: {}", e.getMessage(), e); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, e.getMessage()); } } @@ -401,7 +403,8 @@ private void disconnect() { if (api != null) { try { api.dispose(); - } catch (LinkyException ignore) { + } catch (LinkyException e) { + logger.debug("disconnect: {}", e.getMessage()); } } } From 6a1dd35d71daf53178ecb03c2fcf4b088c80b571 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sun, 28 Nov 2021 15:18:39 +0100 Subject: [PATCH 136/361] [map] Fixed wrong i18n properties and added label of Profile (#11646) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/i18n/transform.properties | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform.properties b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform.properties index 9903cf28f123a..7c22c32c38219 100644 --- a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform.properties +++ b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform.properties @@ -1,6 +1,7 @@ # bundle config -profile.config.transform.function.label = Filename -profile.config.transform.function.description = Filename containing the mapping information. -profile.config.transform.sourceFormat.label = State Formatter -profile.config.transform.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) +profile-type.transform.MAP.label = MAP +profile.config.transform.MAP.function.label = Filename +profile.config.transform.MAP.function.description = Filename containing the mapping information. +profile.config.transform.MAP.sourceFormat.label = State Formatter +profile.config.transform.MAP.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). From 5fcc60c10e45e5e8d774a041225f9b42f5bc4e99 Mon Sep 17 00:00:00 2001 From: Christian Wild <40909464+wildcs@users.noreply.github.com> Date: Sun, 28 Nov 2021 15:29:21 +0100 Subject: [PATCH 137/361] [Tapocontrol] Binding to control Tapo (by TP-Link) Devices (#11111) * [tapocontrol] New Source Upload Signed-off-by: Christian Wild * [tapocontrol] Delete bundles/org.openhab.binding.tapocontrol directory Signed-off-by: Christian Wild * [tapocontrol] Snapshot 3.2 Signed-off-by: Christian Wild * [tapocontrol] Update CODEOWNERS Fixed bindingname Signed-off-by: Christian Wild * [tapocontrol] Update README.md Signed-off-by: Christian Wild * [tapocontrol] new "Bridge-Version" Credentials (TapoCloud) where now set in a bridge device. Things now had to be attached to a bridge. Signed-off-by: Christian Wild * [tapocontrol] fixed device discovery bug fixed device discovery bug added bridge to thing-types.xml Signed-off-by: Christian Wild * [tapocontrol] Update bundles/org.openhab.binding.tapocontrol/README.md Co-authored-by: Fabian Wolter Signed-off-by: Christian Wild * [tapocontrol] code cleanup and optimization - general code cleanup and optimization - limited max connections and queued requests to 10 per destination - device error handling revised - review remarks of pull request processed Signed-off-by: Christian Wild * [tapocontrol] solved review requests Signed-off-by: Christian Wild * [tapocontrol] LightStrip L900 basicly supported Signed-off-by: Christian Wild * [tapocontrol] fixed review requests Signed-off-by: Christian Wild * [tapocontrol] fixed compiler warnings Signed-off-by: Christian Wild Co-authored-by: Fabian Wolter Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../org.openhab.binding.tapocontrol/NOTICE | 13 + .../org.openhab.binding.tapocontrol/README.md | 114 ++++ .../org.openhab.binding.tapocontrol/pom.xml | 15 + .../src/main/feature/feature.xml | 9 + .../internal/TapoControlHandlerFactory.java | 116 ++++ .../internal/TapoDiscoveryService.java | 230 +++++++ .../internal/api/TapoCloudConnector.java | 238 ++++++++ .../internal/api/TapoDeviceConnector.java | 384 ++++++++++++ .../internal/api/TapoDeviceHttpApi.java | 564 ++++++++++++++++++ .../constants/TapoBindingSettings.java | 56 ++ .../constants/TapoErrorConstants.java | 157 +++++ .../constants/TapoThingConstants.java | 153 +++++ .../internal/device/TapoBridgeHandler.java | 301 ++++++++++ .../internal/device/TapoDevice.java | 479 +++++++++++++++ .../internal/device/TapoLightStrip.java | 230 +++++++ .../internal/device/TapoSmartBulb.java | 169 ++++++ .../internal/device/TapoSmartPlug.java | 92 +++ .../internal/device/TapoUniversalDevice.java | 234 ++++++++ .../internal/helpers/MimeEncode.java | 42 ++ .../internal/helpers/PayloadBuilder.java | 90 +++ .../internal/helpers/TapoCipher.java | 144 +++++ .../internal/helpers/TapoCredentials.java | 220 +++++++ .../internal/helpers/TapoErrorHandler.java | 264 ++++++++ .../internal/helpers/TapoUtils.java | 348 +++++++++++ .../structures/TapoBridgeConfiguration.java | 76 +++ .../structures/TapoDeviceConfiguration.java | 63 ++ .../internal/structures/TapoDeviceInfo.java | 224 +++++++ .../internal/structures/TapoLightEffect.java | 141 +++++ .../main/resources/OH-INF/binding/binding.xml | 7 + .../main/resources/OH-INF/config/config.xml | 44 ++ .../resources/OH-INF/thing/L510_Series.xml | 23 + .../resources/OH-INF/thing/L530_Series.xml | 23 + .../src/main/resources/OH-INF/thing/L900.xml | 23 + .../src/main/resources/OH-INF/thing/P100.xml | 23 + .../src/main/resources/OH-INF/thing/P105.xml | 23 + .../main/resources/OH-INF/thing/bridge.xml | 12 + .../main/resources/OH-INF/thing/channels.xml | 197 ++++++ .../tapocontrol/internal/api/TapoUDP.java | 138 +++++ .../internal/device/TapoBridgeHandler.java | 317 ++++++++++ .../internal/device/TapoUniversalDevice.java | 234 ++++++++ .../structures/TapoBridgeConfiguration.java | 77 +++ .../internal/structures/TapoDeviceInfo.java | 242 ++++++++ .../internal/structures/TapoLightEffect.java | 149 +++++ .../test/resources/OH-INF/config/config.xml | 58 ++ .../resources/OH-INF/thing/testdevice.xml | 57 ++ bundles/pom.xml | 1 + 48 files changed, 6820 insertions(+) create mode 100644 bundles/org.openhab.binding.tapocontrol/NOTICE create mode 100644 bundles/org.openhab.binding.tapocontrol/README.md create mode 100644 bundles/org.openhab.binding.tapocontrol/pom.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoCloudConnector.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceConnector.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceHttpApi.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoBindingSettings.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoErrorConstants.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoDevice.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoLightStrip.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartPlug.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoUniversalDevice.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/MimeEncode.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/PayloadBuilder.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCipher.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCredentials.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoErrorHandler.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoUtils.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/structures/TapoBridgeConfiguration.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/structures/TapoDeviceConfiguration.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/structures/TapoDeviceInfo.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/structures/TapoLightEffect.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L510_Series.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L530_Series.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/L900.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/P100.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/P105.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/bridge.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/thing/channels.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/api/TapoUDP.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/device/TapoUniversalDevice.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/structures/TapoBridgeConfiguration.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/structures/TapoDeviceInfo.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/java/org/openhab/binding/tapocontrol/internal/structures/TapoLightEffect.java create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.binding.tapocontrol/src/test/resources/OH-INF/thing/testdevice.xml diff --git a/CODEOWNERS b/CODEOWNERS index b955ee54d392e..59ffc73604cf7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -296,6 +296,7 @@ /bundles/org.openhab.binding.tacmi/ @twendt @Wolfgang1966 @marvkis /bundles/org.openhab.binding.tado/ @dfrommi /bundles/org.openhab.binding.tankerkoenig/ @dolic @JueBag +/bundles/org.openhab.binding.tapocontrol/ @wildcs /bundles/org.openhab.binding.telegram/ @ZzetT /bundles/org.openhab.binding.teleinfo/ @Nokyyz @olivierkeke /bundles/org.openhab.binding.tellstick/ @openhab/add-ons-maintainers diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index b25165992cce6..463145b005096 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1471,6 +1471,11 @@ org.openhab.binding.tankerkoenig ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.tapocontrol + ${project.version} + org.openhab.addons.bundles org.openhab.binding.telegram diff --git a/bundles/org.openhab.binding.tapocontrol/NOTICE b/bundles/org.openhab.binding.tapocontrol/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/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/openhab-addons diff --git a/bundles/org.openhab.binding.tapocontrol/README.md b/bundles/org.openhab.binding.tapocontrol/README.md new file mode 100644 index 0000000000000..77074f476d8ab --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/README.md @@ -0,0 +1,114 @@ +# TapoControl Binding + +This binding adds support to control Tapo (Copyright © TP-Link Corporation Limited) Smart Home Devices from your local openHAB system. + +## Supported Things + +The following Tapo-Devices are supported + +### P100/P105 SmartPlug (WiFi) + +* Power On/Off +* Wi-Fi signal (SignalStrength) +* On-Time (Time in seconds device is switched on) + +### L510_Series dimmable SmartBulb (WiFi) + +* Light On/Off +* Brightnes (Dimmer) 0-100 % +* ColorTemperature (Number) 2500-6500 K +* Wi-Fi signal (SignalStrength) +* On-Time (Time in seconds device is switched on) + +### L530_Series MultiColor SmartBulb (WiFi) + +* Light On/Off +* Brightnes (Dimmer) 0-100 % +* ColorTemperature (Number) 2500-6500 K +* Color (Color) +* Wi-Fi signal (SignalStrength) +* On-Time (Time in seconds device is switched on) + +### L900 MultiColor LightStrip (WiFi) + +* Light On/Off +* Brightnes (Dimmer) 0-100 % +* ColorTemperature (Number) 2500-6500 K +* Color (Color) +* Wi-Fi signal (SignalStrength) +* On-Time (Time in seconds device is switched on) + + +## Prerequisites + +Before using Smart Plugs with openHAB the devices must be connected to the Wi-Fi network. +This can be done using the Tapo provided mobile app. +You need to setup a bridge (Cloud-Login) to commiunicate with your devices. + +## Discovery + +Discovery is done by connecting to the Tapo-Cloud Service. +All devices stored in your cloud account will be detected even if they are not in your network. +You need to know the IP-Adress of your device. This must be set manually in the thing configuration + +## Bridge Configuration + +The bridge needs to be configured with by `username` and `password` (Tapo-Cloud login) . +This is used for device discovery and to create a handshake (cookie) to act with your devices over the local network. + +The thing has the following configuration parameters: + +| Parameter | Description | +|--------------------|----------------------------------------------------------------------| +| username | Username (eMail) of your Tapo-Cloud | +| password | Password of your Tapo-Cloud | + +## Thing Configuration + +The thing needs to be configured with `ipAddress`. + +The thing has the following configuration parameters: + +| Parameter | Description | +|--------------------|----------------------------------------------------------------------| +| ipAddress | IP Address of the device. | +| pollingInterval | Refresh interval in seconds. Optional. The default is 30 seconds | + + +## Channels + +All devices support some of the following channels: + +| group | channel |type | description | things supporting this channel | +|-----------|----------------- |------------------------|------------------------------|---------------------------------| +| actuator | output | Switch | Power device on or off | P100, P105,L510, L530, L900 | +| | brightness | Dimmer | Brightness 0-100% | L510, L530, L900 | +| | colorTemperature | Number | White-Color-Temp 2500-6500K | L510, L530, L900 | +| | color | Color | Color | L530, L900 | +| device | wifiSignal | system.signal-strength | WiFi-quality-level | P100, P105, L510, L530, L900 | +| | onTime | Number:Time | seconds output is on | P100, P105, L510, L530, L900 | + + +## Channel Refresh + +When the thing receives a `RefreshType` command the thing will send a new refreshRequest over http. +To minimize network traffic the default refresh-rate is set to 30 seconds. This can be reduced down to 10 seconds in advanced settings of the device. If any command was sent to a channel, it will do an immediately refresh of the whole device. + + +## Full Example + +### tapocontrol.things: + +``` +tapocontrol:bridge:myTapoBridge "Cloud-Login" [ username="you@yourpovider.com", password="verysecret" ] +tapocontrol:P100:myTapoBridge:mySocket "My-Socket" [ ipAddress="192.168.178.150", pollingInterval=30 ] +tapocontrol:L510_Series:myTapoBridge:whiteBulb "white-light" [ ipAddress="192.168.178.151", pollingInterval=30 ] +tapocontrol:L530_Series:myTapoBridge:colorBulb "color-light" [ ipAddress="192.168.178.152", pollingInterval=30 ] +tapocontrol:L900:myTapoBridge:myLightStrip "light-strip" [ ipAddress="192.168.178.153", pollingInterval=30 ] +``` + +### tapocontrol.items: + +``` +Switch TAPO_SOCKET "socket" { channel="tapocontrol:P100:myTapoBridge:mySocket:actuator#output" } +``` diff --git a/bundles/org.openhab.binding.tapocontrol/pom.xml b/bundles/org.openhab.binding.tapocontrol/pom.xml new file mode 100644 index 0000000000000..2e71e41e4d675 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/pom.xml @@ -0,0 +1,15 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.tapocontrol + openHAB Add-ons :: Bundles :: TapoControl Binding + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/feature/feature.xml b/bundles/org.openhab.binding.tapocontrol/src/main/feature/feature.xml new file mode 100644 index 0000000000000..5cc25ab0614fe --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.tapocontrol/${project.version} + + diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java new file mode 100644 index 0000000000000..e24a5d5d796d8 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoControlHandlerFactory.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler; +import org.openhab.binding.tapocontrol.internal.device.TapoLightStrip; +import org.openhab.binding.tapocontrol.internal.device.TapoSmartBulb; +import org.openhab.binding.tapocontrol.internal.device.TapoSmartPlug; +import org.openhab.binding.tapocontrol.internal.device.TapoUniversalDevice; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link TapoControlHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Christian Wild - Initial contribution + */ +@Component(service = ThingHandlerFactory.class, configurationPid = "binding.tapocontrol") +@NonNullByDefault +public class TapoControlHandlerFactory extends BaseThingHandlerFactory { + private final Logger logger = LoggerFactory.getLogger(TapoControlHandlerFactory.class); + private final Set accountHandlers = new HashSet<>(); + private final HttpClient httpClient; + + @Activate + public TapoControlHandlerFactory() { + // create new httpClient + httpClient = new HttpClient(new SslContextFactory.Client()); + httpClient.setFollowRedirects(false); + httpClient.setMaxConnectionsPerDestination(HTTP_MAX_CONNECTIONS); + httpClient.setMaxRequestsQueuedPerDestination(HTTP_MAX_QUEUED_REQUESTS); + try { + httpClient.start(); + } catch (Exception e) { + logger.error("cannot start httpClient"); + } + } + + @Deactivate + @Override + protected void deactivate(ComponentContext componentContext) { + super.deactivate(componentContext); + try { + httpClient.stop(); + } catch (Exception e) { + logger.debug("unable to stop httpClient"); + } + } + + /** + * Provides the supported thing types + */ + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + if (thingTypeUID.equals(UNIVERSAL_THING_TYPE)) { + return true; + } + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + /** + * Create handler of things. + */ + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (SUPPORTED_BRIDGE_UIDS.contains(thingTypeUID)) { + TapoBridgeHandler bridgeHandler = new TapoBridgeHandler((Bridge) thing, httpClient); + accountHandlers.add(bridgeHandler); + return bridgeHandler; + } else if (SUPPORTED_SMART_PLUG_UIDS.contains(thingTypeUID)) { + return new TapoSmartPlug(thing); + } else if (SUPPORTED_WHITE_BULB_UIDS.contains(thingTypeUID)) { + return new TapoSmartBulb(thing); + } else if (SUPPORTED_COLOR_BULB_UIDS.contains(thingTypeUID)) { + return new TapoSmartBulb(thing); + } else if (SUPPORTED_LIGHT_STRIP_UIDS.contains(thingTypeUID)) { + return new TapoLightStrip(thing); + } else if (thingTypeUID.equals(UNIVERSAL_THING_TYPE)) { + return new TapoUniversalDevice(thing); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java new file mode 100644 index 0000000000000..12bd4ea07a4df --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/TapoDiscoveryService.java @@ -0,0 +1,230 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler; +import org.openhab.binding.tapocontrol.internal.structures.TapoBridgeConfiguration; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * Handler class for TAPO Smart Home thing discovery + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { + private final Logger logger = LoggerFactory.getLogger(TapoDiscoveryService.class); + protected @NonNullByDefault({}) TapoBridgeHandler bridge; + + /*********************************** + * + * INITIALIZATION + * + ************************************/ + + /** + * INIT CLASS + * + * @param bridgeHandler + */ + public TapoDiscoveryService() { + super(SUPPORTED_THING_TYPES_UIDS, TAPO_DISCOVERY_TIMEOUT_S, false); + } + + /** + * deactivate + */ + @Override + public void activate() { + TapoBridgeConfiguration config = bridge.getBridgeConfig(); + if (config.cloudDiscoveryEnabled || config.udpDiscoveryEnabled) { + startBackgroundDiscovery(); + } + } + + /** + * deactivate + */ + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + public void setThingHandler(@Nullable ThingHandler handler) { + if (handler instanceof TapoBridgeHandler) { + TapoBridgeHandler tapoBridge = (TapoBridgeHandler) handler; + tapoBridge.setDiscoveryService(this); + this.bridge = tapoBridge; + } + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return this.bridge; + } + + /*********************************** + * + * SCAN HANDLING + * + ************************************/ + + /** + * Start scan manually + */ + @Override + public void startScan() { + removeOlderResults(getTimestampOfLastScan()); + if (bridge != null) { + JsonArray jsonArray = bridge.getDeviceList(); + handleCloudDevices(jsonArray); + } + } + + /*********************************** + * + * handle Results + * + ************************************/ + + /** + * CREATE DISCOVERY RESULT + * creates discoveryResult (Thing) from JsonObject got from Cloud + * + * @param device JsonObject with device information + * @return DiscoveryResult-Object + */ + public DiscoveryResult createResult(JsonObject device) { + TapoBridgeHandler tapoBridge = this.bridge; + String deviceModel = getDeviceModel(device); + String label = getDeviceLabel(device); + String deviceMAC = device.get(CLOUD_PROPERTY_MAC).getAsString(); + ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel); + + /* create properties */ + Map properties = new HashMap<>(); + properties.put(Thing.PROPERTY_VENDOR, DEVICE_VENDOR); + properties.put(Thing.PROPERTY_MAC_ADDRESS, formatMac(deviceMAC, MAC_DIVISION_CHAR)); + properties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.get(CLOUD_PROPERTY_FW).getAsString()); + properties.put(Thing.PROPERTY_HARDWARE_VERSION, device.get(CLOUD_PROPERTY_HW).getAsString()); + properties.put(Thing.PROPERTY_MODEL_ID, deviceModel); + properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.get(CLOUD_PROPERTY_ID).getAsString()); + + logger.debug("device {} discovered", deviceModel); + if (tapoBridge != null) { + ThingUID bridgeUID = tapoBridge.getUID(); + ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, deviceMAC); + return DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withRepresentationProperty(DEVICE_REPRASENTATION_PROPERTY).withBridge(bridgeUID).withLabel(label) + .build(); + } else { + ThingUID thingUID = new ThingUID(BINDING_ID, deviceMAC); + return DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withRepresentationProperty(DEVICE_REPRASENTATION_PROPERTY).withLabel(label).build(); + } + } + + /** + * work with result from get devices from cloud devices + * + * @param deviceList + */ + protected void handleCloudDevices(JsonArray deviceList) { + try { + for (JsonElement deviceElement : deviceList) { + if (deviceElement.isJsonObject()) { + JsonObject device = deviceElement.getAsJsonObject(); + String deviceModel = getDeviceModel(device); + ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, deviceModel); + + /* create thing */ + if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) { + DiscoveryResult discoveryResult = createResult(device); + thingDiscovered(discoveryResult); + } + } + } + } catch (Exception e) { + logger.debug("error handlling CloudDevices", e); + } + } + + /** + * GET DEVICEMODEL + * + * @param device JsonObject with deviceData + * @return String with DeviceModel + */ + protected String getDeviceModel(JsonObject device) { + try { + String deviceModel = device.get(CLOUD_PROPERTY_MODEL).getAsString(); + deviceModel = deviceModel.replaceAll("\\(.*\\)", ""); // replace (DE) + deviceModel = deviceModel.replace("Tapo", ""); + deviceModel = deviceModel.trim(); + deviceModel = deviceModel.replace(" ", "_"); + return deviceModel; + } catch (Exception e) { + logger.debug("error getDeviceModel", e); + return ""; + } + } + + /** + * GET DEVICE LABEL + * + * @param device JsonObject with deviceData + * @return String with DeviceLabel + */ + protected String getDeviceLabel(JsonObject device) { + try { + String deviceLabel = ""; + String deviceModel = getDeviceModel(device); + ThingTypeUID deviceUID = new ThingTypeUID(BINDING_ID, deviceModel); + + if (SUPPORTED_SMART_PLUG_UIDS.contains(deviceUID)) { + deviceLabel = DEVICE_DESCRIPTION_SMART_PLUG; + } else if (SUPPORTED_WHITE_BULB_UIDS.contains(deviceUID)) { + deviceLabel = DEVICE_DESCRIPTION_WHITE_BULB; + } else if (SUPPORTED_COLOR_BULB_UIDS.contains(deviceUID)) { + deviceLabel = DEVICE_DESCRIPTION_COLOR_BULB; + } + return DEVICE_VENDOR + " " + deviceModel + " " + deviceLabel; + } catch (Exception e) { + logger.debug("error getDeviceLabel", e); + return ""; + } + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoCloudConnector.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoCloudConnector.java new file mode 100644 index 0000000000000..30e7bdc049eb2 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoCloudConnector.java @@ -0,0 +1,238 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.api; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants.*; + +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler; +import org.openhab.binding.tapocontrol.internal.helpers.PayloadBuilder; +import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +/** + * Handler class for TAPO-Cloud connections. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoCloudConnector { + private final Logger logger = LoggerFactory.getLogger(TapoCloudConnector.class); + private final TapoBridgeHandler bridge; + private final Gson gson = new Gson(); + private final HttpClient httpClient; + + private String token = ""; + private String url = TAPO_CLOUD_URL; + private String uid; + + /** + * INIT CLASS + * + */ + public TapoCloudConnector(TapoBridgeHandler bridge, HttpClient httpClient) { + this.bridge = bridge; + this.httpClient = httpClient; + this.uid = bridge.getUID().getAsString(); + } + + /** + * handle error + * + * @param tapoError TapoErrorHandler + */ + protected void handleError(TapoErrorHandler tapoError) { + this.bridge.setError(tapoError); + } + + /*********************************** + * + * HTTP (Cloud)-Actions + * + ************************************/ + + /** + * LOGIN TO CLOUD (get Token) + * + * @param username unencrypted username + * @param password unencrypted password + * @return true if login was successfull + */ + public Boolean login(String username, String password) { + this.token = getToken(username, password, TAPO_TERMINAL_UUID); + this.url = TAPO_CLOUD_URL + "?token=" + token; + return !this.token.isBlank(); + } + + /** + * logout + */ + public void logout() { + this.token = ""; + } + + /** + * GET TOKEN FROM TAPO-CLOUD + * + * @param email + * @param password + * @param terminalUUID + * @return + */ + private String getToken(String email, String password, String terminalUUID) { + String token = ""; + + /* create login payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = "login"; + plBuilder.addParameter("appType", TAPO_APP_TYPE); + plBuilder.addParameter("cloudUserName", email); + plBuilder.addParameter("cloudPassword", password); + plBuilder.addParameter("terminalUUID", terminalUUID); + String payload = plBuilder.getPayload(); + + ContentResponse response = sendCloudRequest(TAPO_CLOUD_URL, payload); + if (response != null) { + token = getTokenFromResponse(response); + } + return token; + } + + private String getTokenFromResponse(ContentResponse response) { + /* work with response */ + if (response.getStatus() == 200) { + String rBody = response.getContentAsString(); + JsonObject jsonObject = gson.fromJson(rBody, JsonObject.class); + if (jsonObject != null) { + Integer errorCode = jsonObject.get("error_code").getAsInt(); + if (errorCode == 0) { + token = jsonObject.getAsJsonObject("result").get("token").getAsString(); + } else { + /* return errorcode from device */ + String msg = jsonObject.get("msg").getAsString(); + handleError(new TapoErrorHandler(errorCode, msg)); + logger.trace("cloud returns error: '{}'", rBody); + } + } else { + handleError(new TapoErrorHandler(ERR_JSON_DECODE_FAIL)); + logger.trace("unexpected json-response '{}'", rBody); + } + } else { + handleError(new TapoErrorHandler(ERR_HTTP_RESPONSE, ERR_HTTP_RESPONSE_MSG)); + logger.warn("invalid response while login"); + token = ""; + } + return token; + } + + /** + * + * @return JsonArray with deviceList + */ + public JsonArray getDeviceList() { + /* create payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = "getDeviceList"; + String payload = plBuilder.getPayload(); + + ContentResponse response = sendCloudRequest(this.url, payload); + if (response != null) { + return getDeviceListFromResponse(response); + } + return new JsonArray(); + } + + /** + * get DeviceList from Contenresponse + * + * @param response + * @return + */ + private JsonArray getDeviceListFromResponse(ContentResponse response) { + /* work with response */ + if (response.getStatus() == 200) { + String rBody = response.getContentAsString(); + JsonObject jsonObject = gson.fromJson(rBody, JsonObject.class); + if (jsonObject != null) { + /* get errocode (0=success) */ + Integer errorCode = jsonObject.get("error_code").getAsInt(); + if (errorCode == 0) { + JsonObject result = jsonObject.getAsJsonObject("result"); + return result.getAsJsonArray("deviceList"); + } else { + /* return errorcode from device */ + handleError(new TapoErrorHandler(errorCode, "device answers with errorcode")); + logger.trace("cloud returns error: '{}'", rBody); + } + } else { + logger.trace("enexpected json-response '{}'", rBody); + } + } else { + logger.trace("response error '{}'", response.getContentAsString()); + } + return new JsonArray(); + } + + /*********************************** + * + * HTTP-ACTIONS + * + ************************************/ + /** + * SEND SYNCHRON HTTP-REQUEST + * + * @param url url request is sent to + * @param payload payload (String) to send + * @return ContentResponse of request + */ + @Nullable + protected ContentResponse sendCloudRequest(String url, String payload) { + Request httpRequest = httpClient.newRequest(url).method(HttpMethod.POST.toString()); + + /* set header */ + httpRequest.header("content-type", CONTENT_TYPE_JSON); + httpRequest.header("Accept", CONTENT_TYPE_JSON); + + /* add request body */ + httpRequest.content(new StringContentProvider(payload, CONTENT_CHARSET), CONTENT_TYPE_JSON); + + try { + ContentResponse httpResponse = httpRequest.send(); + return httpResponse; + } catch (InterruptedException e) { + logger.debug("({}) sending request interrupted: {}", uid, e.toString()); + handleError(new TapoErrorHandler(e)); + } catch (TimeoutException e) { + logger.debug("({}) sending request timeout: {}", uid, e.toString()); + handleError(new TapoErrorHandler(ERR_CONNECT_TIMEOUT, e.toString())); + } catch (Exception e) { + logger.debug("({}) sending request failed: {}", uid, e.toString()); + handleError(new TapoErrorHandler(e)); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceConnector.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceConnector.java new file mode 100644 index 0000000000000..bb0f5d9fce5ff --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceConnector.java @@ -0,0 +1,384 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.api; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.net.InetAddress; +import java.util.HashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler; +import org.openhab.binding.tapocontrol.internal.device.TapoDevice; +import org.openhab.binding.tapocontrol.internal.helpers.PayloadBuilder; +import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +/** + * Handler class for TAPO Smart Home device connections. + * This class uses asynchronous HttpClient-Requests + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoDeviceConnector extends TapoDeviceHttpApi { + private final Logger logger = LoggerFactory.getLogger(TapoDeviceConnector.class); + private final String uid; + private final TapoDevice device; + private TapoDeviceInfo deviceInfo; + private Gson gson; + private long lastQuery = 0L; + private long lastSent = 0L; + private long lastLogin = 0L; + + /** + * INIT CLASS + * + * @param config TapoControlConfiguration class + */ + public TapoDeviceConnector(TapoDevice device, TapoBridgeHandler bridgeThingHandler) { + super(device, bridgeThingHandler); + this.device = device; + this.gson = new Gson(); + this.deviceInfo = new TapoDeviceInfo(); + this.uid = device.getThingUID().getAsString(); + } + + /*********************************** + * + * LOGIN FUNCTIONS + * + ************************************/ + /** + * login + * + * @return true if success + */ + public boolean login() { + if (this.pingDevice()) { + logger.trace("({}) sending login to url '{}'", uid, deviceURL); + + long now = System.currentTimeMillis(); + if (now > this.lastLogin + TAPO_LOGIN_MIN_GAP_MS) { + this.lastLogin = now; + unsetToken(); + unsetCookie(); + + /* create ssl-handschake (cookie) */ + String cookie = createHandshake(); + if (!cookie.isBlank()) { + setCookie(cookie); + String token = queryToken(); + setToken(token); + } + } else { + logger.trace("({}) not done cause of min_gap '{}'", uid, TAPO_LOGIN_MIN_GAP_MS); + } + return this.loggedIn(); + } else { + logger.debug("({}) no ping while login '{}'", uid, this.ipAddress); + handleError(new TapoErrorHandler(ERR_DEVICE_OFFLINE, "no ping while login")); + return false; + } + } + + /*********************************** + * + * DEVICE ACTIONS + * + ************************************/ + + /** + * send custom command to device + * + * @param plBuilder Payloadbuilder with unencrypted payload + */ + public void sendCustomQuery(String queryMethod) { + /* create payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = queryMethod; + sendCustomPayload(plBuilder); + } + + /** + * send custom command to device + * + * @param plBuilder Payloadbuilder with unencrypted payload + */ + public void sendCustomPayload(PayloadBuilder plBuilder) { + long now = System.currentTimeMillis(); + if (now > this.lastSent + TAPO_SEND_MIN_GAP_MS) { + String payload = plBuilder.getPayload(); + sendSecurePasstrhroug(payload, DEVICE_CMD_CUSTOM); + } else { + logger.debug("({}) command not sent becauso of min_gap: {}", uid, now + " <- " + lastSent); + } + } + + /** + * send "set_device_info" command to device + * + * @param name Name of command to send + * @param value Value to send to control + */ + public void sendDeviceCommand(String name, Object value) { + long now = System.currentTimeMillis(); + if (now > this.lastSent + TAPO_SEND_MIN_GAP_MS) { + this.lastSent = now; + + /* create payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = DEVICE_CMD_SETINFO; + plBuilder.addParameter(name, value); + String payload = plBuilder.getPayload(); + + sendSecurePasstrhroug(payload, DEVICE_CMD_SETINFO); + } else { + logger.debug("({}) command not sent becauso of min_gap: {}", uid, now + " <- " + lastSent); + } + } + + /** + * send multiple "set_device_info" commands to device + * + * @param map HashMap (name, value of parameter) + */ + public void sendDeviceCommands(HashMap map) { + long now = System.currentTimeMillis(); + if (now > this.lastSent + TAPO_SEND_MIN_GAP_MS) { + this.lastSent = now; + + /* create payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = DEVICE_CMD_SETINFO; + for (HashMap.Entry entry : map.entrySet()) { + plBuilder.addParameter(entry.getKey(), entry.getValue()); + } + String payload = plBuilder.getPayload(); + + sendSecurePasstrhroug(payload, DEVICE_CMD_SETINFO); + } else { + logger.debug("({}) command not sent becauso of min_gap: {}", uid, now + " <- " + lastSent); + } + } + + /** + * Query Info from Device adn refresh deviceInfo + */ + public void queryInfo() { + queryInfo(false); + } + + /** + * Query Info from Device adn refresh deviceInfo + * + * @param ignoreGap ignore gap to last query. query anyway + */ + public void queryInfo(boolean ignoreGap) { + logger.trace("({}) DeviceConnetor_queryInfo from '{}'", uid, deviceURL); + long now = System.currentTimeMillis(); + if (ignoreGap || now > this.lastQuery + TAPO_SEND_MIN_GAP_MS) { + this.lastQuery = now; + + /* create payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = DEVICE_CMD_GETINFO; + String payload = plBuilder.getPayload(); + + sendSecurePasstrhroug(payload, DEVICE_CMD_GETINFO); + } else { + logger.debug("({}) command not sent becauso of min_gap: {}", uid, now + " <- " + lastQuery); + } + } + + /** + * SEND SECUREPASSTHROUGH + * encprypt payload and send to device + * + * @param payload payload sent to device + * @param command command executed - this will handle result + */ + protected void sendSecurePasstrhroug(String payload, String command) { + /* encrypt payload */ + String encryptedPayload = encryptPayload(payload); + + /* create secured payload */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = "securePassthrough"; + plBuilder.addParameter("request", encryptedPayload); + String securePassthroughPayload = plBuilder.getPayload(); + + sendAsyncRequest(deviceURL, securePassthroughPayload, command); + } + + /*********************************** + * + * HANDLE RESPONSES + * + ************************************/ + + /** + * Handle SuccessResponse (setDeviceInfo) + * + * @param responseBody String with responseBody from device + */ + @Override + protected void handleSuccessResponse(String responseBody) { + JsonObject jsnResult = getJsonFromResponse(responseBody); + Integer errorCode = jsonObjectToInt(jsnResult, "error_code", ERR_JSON_DECODE_FAIL); + if (errorCode != 0) { + logger.debug("({}) set deviceInfo not succesfull: {}", uid, jsnResult); + this.device.handleConnectionState(); + } + this.device.responsePasstrough(responseBody); + } + + /** + * handle JsonResponse (getDeviceInfo) + * + * @param responseBody String with responseBody from device + */ + @Override + protected void handleDeviceResult(String responseBody) { + JsonObject jsnResult = getJsonFromResponse(responseBody); + if (jsnResult.has("device_id")) { + this.deviceInfo = new TapoDeviceInfo(jsnResult); + this.device.setDeviceInfo(deviceInfo); + } else { + this.deviceInfo = new TapoDeviceInfo(); + this.device.handleConnectionState(); + } + this.device.responsePasstrough(responseBody); + } + + /** + * handle custom response + * + * @param responseBody String with responseBody from device + */ + @Override + protected void handleCustomResponse(String responseBody) { + this.device.responsePasstrough(responseBody); + } + + /** + * handle error + * + * @param te TapoErrorHandler + */ + @Override + protected void handleError(TapoErrorHandler tapoError) { + this.device.setError(tapoError); + } + + /** + * get Json from response + * + * @param responseBody + * @return JsonObject with result + */ + private JsonObject getJsonFromResponse(String responseBody) { + JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class); + /* get errocode (0=success) */ + if (jsonObject != null) { + Integer errorCode = jsonObjectToInt(jsonObject, "error_code"); + if (errorCode == 0) { + /* decrypt response */ + jsonObject = gson.fromJson(responseBody, JsonObject.class); + logger.trace("({}) received result: {}", uid, responseBody); + if (jsonObject != null) { + /* return result if set / else request was successfull */ + if (jsonObject.has("result")) { + return jsonObject.getAsJsonObject("result"); + } else { + return jsonObject; + } + } + } else { + /* return errorcode from device */ + TapoErrorHandler te = new TapoErrorHandler(errorCode, "device answers with errorcode"); + logger.debug("({}) device answers with errorcode {} - {}", uid, errorCode, te.getMessage()); + handleError(te); + return jsonObject; + } + } + logger.debug("({}) sendPayload exception {}", uid, responseBody); + handleError(new TapoErrorHandler(ERR_HTTP_RESPONSE)); + return new JsonObject(); + } + + /*********************************** + * + * GET RESULTS + * + ************************************/ + + /** + * Check if device is online + * + * @return true if device is online + */ + public Boolean isOnline() { + return isOnline(false); + } + + /** + * Check if device is online + * + * @param raiseError if true + * @return true if device is online + */ + public Boolean isOnline(Boolean raiseError) { + if (pingDevice()) { + return true; + } else { + logger.trace("({}) device is offline (no ping)", uid); + if (raiseError) { + handleError(new TapoErrorHandler(ERR_DEVICE_OFFLINE)); + } + logout(); + return false; + } + } + + /** + * IP-Adress + * + * @return String ipAdress + */ + public String getIP() { + return this.ipAddress; + } + + /** + * PING IP Adress + * + * @return true if ping successfull + */ + public Boolean pingDevice() { + try { + InetAddress address = InetAddress.getByName(this.ipAddress); + return address.isReachable(TAPO_PING_TIMEOUT_MS); + } catch (Exception e) { + logger.debug("({}) InetAdress throws: {}", uid, e.getMessage()); + return false; + } + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceHttpApi.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceHttpApi.java new file mode 100644 index 0000000000000..59bb9b55498c1 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/api/TapoDeviceHttpApi.java @@ -0,0 +1,564 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.api; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpResponse; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.util.BufferingResponseListener; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.openhab.binding.tapocontrol.internal.device.TapoBridgeHandler; +import org.openhab.binding.tapocontrol.internal.device.TapoDevice; +import org.openhab.binding.tapocontrol.internal.helpers.PayloadBuilder; +import org.openhab.binding.tapocontrol.internal.helpers.TapoCipher; +import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +/** + * Handler class for TAPO Smart Home device connections. + * This class uses synchronous HttpClient-Requests for login to device + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoDeviceHttpApi { + private final Logger logger = LoggerFactory.getLogger(TapoDeviceHttpApi.class); + private final String uid; + private final TapoCipher tapoCipher; + private final TapoBridgeHandler bridge; + private Gson gson; + private String token = ""; + private String cookie = ""; + protected String deviceURL = ""; + protected String ipAddress = ""; + + /** + * INIT CLASS + * + * @param config TapoControlConfiguration class + */ + public TapoDeviceHttpApi(TapoDevice device, TapoBridgeHandler bridgeThingHandler) { + this.bridge = bridgeThingHandler; + this.tapoCipher = new TapoCipher(); + this.gson = new Gson(); + this.uid = device.getThingUID().getAsString(); + String ipAddress = device.getIpAddress(); + setDeviceURL(ipAddress); + } + + /*********************************** + * + * DELEGATING FUNCTIONS + * will normaly be delegated to extension-classes(TapoDeviceConnector) + * + ************************************/ + /** + * handle SuccessResponse (setDeviceInfo) + * + * @param responseBody String with responseBody from device + */ + protected void handleSuccessResponse(String responseBody) { + } + + /** + * handle JsonResponse (getDeviceInfo) + * + * @param responseBody String with responseBody from device + */ + protected void handleDeviceResult(String responseBody) { + } + + /** + * handle custom response + * + * @param responseBody String with responseBody from device + */ + protected void handleCustomResponse(String responseBody) { + } + + /** + * handle error + * + * @param te TapoErrorHandler + */ + protected void handleError(TapoErrorHandler tapoError) { + } + + /*********************************** + * + * LOGIN FUNCTIONS + * + ************************************/ + + /** + * Create Handshake and set cookie + * + * @return true if handshake (cookie) was created + */ + protected String createHandshake() { + String cookie = ""; + try { + /* create payload for handshake */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = "handshake"; + plBuilder.addParameter("key", bridge.getCredentials().getPublicKey()); // ?.decode("UTF-8") + String payload = plBuilder.getPayload(); + + /* send request (create ) */ + logger.trace("({}) create handhsake with payload: {}", uid, payload.toString()); + ContentResponse response = sendRequest(this.deviceURL, payload); + if (response != null && getErrorCode(response) == 0) { + String encryptedKey = getKeyFromResponse(response); + this.tapoCipher.setKey(encryptedKey, bridge.getCredentials()); + cookie = getCookieFromResponse(response); + } + } catch (Exception e) { + logger.debug("({}) could not createHandshake: {}", uid, e.toString()); + handleError(new TapoErrorHandler(ERR_HAND_SHAKE_FAILED, "could not createHandshake")); + } + return cookie; + } + + /** + * return encrypted key from 'handshake' request + * + * @param response ContentResponse from "handshake" method + * @return + */ + private String getKeyFromResponse(ContentResponse response) { + String rBody = response.getContentAsString(); + JsonObject jsonObj = gson.fromJson(rBody, JsonObject.class); + if (jsonObj != null) { + logger.trace("({}) received awnser: {}", uid, rBody); + return jsonObjectToString(jsonObj.getAsJsonObject("result"), "key"); + } else { + logger.warn("({}) could not getKeyFromResponse '{}'", uid, rBody); + handleError(new TapoErrorHandler(ERR_HAND_SHAKE_FAILED, "could not getKeyFromResponse")); + } + return ""; + } + + /** + * return cookie from 'handshake' request + * + * @param response ContentResponse from "handshake" metho + * @return + */ + private String getCookieFromResponse(ContentResponse response) { + String cookie = ""; + try { + cookie = response.getHeaders().get("Set-Cookie").split(";")[0]; + logger.trace("({}) got cookie: '{}'", uid, cookie); + } catch (Exception e) { + logger.warn("({}) could not getCookieFromResponse", uid); + handleError(new TapoErrorHandler(ERR_HAND_SHAKE_FAILED, "could not getCookieFromResponse")); + } + return cookie; + } + + /** + * Query Token from device + * + * @return String with token returned from device + */ + protected String queryToken() { + String token = ""; + try { + /* encrypt login credentials */ + PayloadBuilder plBuilder = new PayloadBuilder(); + plBuilder.method = "login_device"; + plBuilder.addParameter("username", bridge.getCredentials().getEncodedEmail()); + plBuilder.addParameter("password", bridge.getCredentials().getEncodedPassword()); + String payload = plBuilder.getPayload(); + String encryptedPayload = this.encryptPayload(payload); + + /* create secured login informations */ + plBuilder = new PayloadBuilder(); + plBuilder.method = "securePassthrough"; + plBuilder.addParameter("request", encryptedPayload); + String securePassthroughPayload = plBuilder.getPayload(); + + /* sendRequest and get Token */ + ContentResponse response = sendRequest(deviceURL, securePassthroughPayload); + token = getTokenFromResponse(response); + } catch (Exception e) { + logger.debug("({}) error building login payload: {}", uid, e.toString()); + handleError(new TapoErrorHandler(e, "error building login payload")); + } + return token; + } + + /** + * get Token from "login"-request + * + * @param response + * @return + */ + private String getTokenFromResponse(@Nullable ContentResponse response) { + String result = ""; + TapoErrorHandler tapoError = new TapoErrorHandler(); + if (response != null && response.getStatus() == 200) { + String rBody = response.getContentAsString(); + String decryptedResponse = this.decryptResponse(rBody); + logger.trace("({}) received result: {}", uid, decryptedResponse); + + /* get errocode (0=success) */ + JsonObject jsonObject = gson.fromJson(decryptedResponse, JsonObject.class); + if (jsonObject != null) { + Integer errorCode = jsonObjectToInt(jsonObject, "error_code", ERR_JSON_DECODE_FAIL); + if (errorCode == 0) { + /* return result if set / else request was successfull */ + result = jsonObjectToString(jsonObject.getAsJsonObject("result"), "token"); + } else { + /* return errorcode from device */ + tapoError.raiseError(errorCode, "could not get token"); + logger.debug("({}) login recieved errorCode {} - {}", uid, errorCode, tapoError.getMessage()); + } + } else { + logger.debug("({}) unexpected json-response '{}'", uid, decryptedResponse); + tapoError.raiseError(ERR_JSON_ENCODE_FAIL, "could not get token"); + } + } else { + logger.debug("({}) invalid response while login", uid); + tapoError.raiseError(ERR_HTTP_RESPONSE, "invalid response while login"); + } + /* handle error */ + if (tapoError.hasError()) { + handleError(tapoError); + } + return result; + } + + /*********************************** + * + * HTTP-ACTIONS + * + ************************************/ + /** + * SEND SYNCHRON HTTP-REQUEST + * + * @param url url request is sent to + * @param payload payload (String) to send + * @return ContentResponse of request + */ + @Nullable + protected ContentResponse sendRequest(String url, String payload) { + logger.trace("({}) sendRequest to '{}' with cookie '{}'", uid, url, this.cookie); + + Request httpRequest = bridge.getHttpClient().newRequest(url).method(HttpMethod.POST.toString()); + + /* set header */ + httpRequest = setHeaders(httpRequest); + httpRequest.timeout(TAPO_HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS); + + /* add request body */ + httpRequest.content(new StringContentProvider(payload, CONTENT_CHARSET), CONTENT_TYPE_JSON); + + try { + ContentResponse httpResponse = httpRequest.send(); + return httpResponse; + } catch (InterruptedException e) { + logger.debug("({}) sending request interrupted: {}", uid, e.toString()); + handleError(new TapoErrorHandler(e)); + } catch (TimeoutException e) { + logger.debug("({}) sending request timeout: {}", uid, e.toString()); + handleError(new TapoErrorHandler(ERR_CONNECT_TIMEOUT, e.toString())); + } catch (Exception e) { + logger.debug("({}) sending request failed: {}", uid, e.toString()); + handleError(new TapoErrorHandler(e)); + } + return null; + } + + /** + * SEND ASYNCHRONOUS HTTP-REQUEST + * (don't wait for awnser with programm code) + * + * @param url string url request is sent to + * @param payload data-payload + * @param command command executed - this will handle RepsonseType + */ + protected void sendAsyncRequest(String url, String payload, String command) { + logger.trace("({}) sendAsncRequest to '{}' with cookie '{}'", uid, url, this.cookie); + try { + Request httpRequest = bridge.getHttpClient().newRequest(url).method(HttpMethod.POST.toString()); + + /* set header */ + httpRequest = setHeaders(httpRequest); + + /* add request body */ + httpRequest.content(new StringContentProvider(payload, CONTENT_CHARSET), CONTENT_TYPE_JSON); + + httpRequest.timeout(TAPO_HTTP_TIMEOUT_MS, TimeUnit.MILLISECONDS).send(new BufferingResponseListener() { + @NonNullByDefault({}) + @Override + public void onComplete(Result result) { + final HttpResponse response = (HttpResponse) result.getResponse(); + if (result.getFailure() != null) { + /* handle result errors */ + Throwable e = result.getFailure(); + String errorMessage = getValueOrDefault(e.getMessage(), ""); + if (e instanceof TimeoutException) { + logger.debug("({}) sendAsyncRequest timeout'{}'", uid, errorMessage); + handleError(new TapoErrorHandler(ERR_CONNECT_TIMEOUT, errorMessage)); + } else { + logger.debug("({}) sendAsyncRequest failed'{}'", uid, errorMessage); + handleError(new TapoErrorHandler(new Exception(e), errorMessage)); + } + } else if (response.getStatus() != 200) { + logger.debug("({}) sendAsyncRequest response error'{}'", uid, response.getStatus()); + handleError(new TapoErrorHandler(ERR_HTTP_RESPONSE, getContentAsString())); + } else { + /* request succesfull */ + String rBody = getContentAsString(); + rBody = decryptResponse(rBody); + logger.trace("({}) requestCompleted '{}'", uid, rBody); + /* handle result */ + switch (command) { + case DEVICE_CMD_SETINFO: + handleSuccessResponse(rBody); + break; + case DEVICE_CMD_GETINFO: + handleDeviceResult(rBody); + break; + case DEVICE_CMD_CUSTOM: + handleCustomResponse(rBody); + break; + } + } + } + }); + } catch (Exception e) { + handleError(new TapoErrorHandler(e)); + } + } + + /** + * return error code from response + * + * @param response + * @return 0 if request was successfull + */ + protected Integer getErrorCode(@Nullable ContentResponse response) { + try { + if (response != null) { + String responseBody = response.getContentAsString(); + return getErrorCode(responseBody); + } else { + return ERR_HTTP_RESPONSE; + } + } catch (Exception e) { + return ERR_HTTP_RESPONSE; + } + } + + /** + * return error code from responseBody + * + * @param responseBody + * @return 0 if request was successfull + */ + protected Integer getErrorCode(String responseBody) { + try { + JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class); + /* get errocode (0=success) */ + Integer errorCode = jsonObjectToInt(jsonObject, "error_code", ERR_JSON_DECODE_FAIL); + if (errorCode == 0) { + return 0; + } else { + logger.debug("({}) device returns errorcode '{}'", uid, errorCode); + handleError(new TapoErrorHandler(errorCode)); + return errorCode; + } + } catch (Exception e) { + return ERR_HTTP_RESPONSE; + } + } + + /** + * SET HTTP-HEADERS + */ + private Request setHeaders(Request httpRequest) { + /* set header */ + httpRequest.header("content-type", CONTENT_TYPE_JSON); + httpRequest.header("Accept", CONTENT_TYPE_JSON); + if (!this.cookie.isEmpty()) { + httpRequest.header(HTTP_AUTH_TYPE_COOKIE, this.cookie); + } + return httpRequest; + } + + /*********************************** + * + * ENCRYPTION / CODING + * + ************************************/ + + /** + * Decrypt Response + * + * @param responseBody encrypted string from response-body + * @return String decrypted responseBody + */ + protected String decryptResponse(String responseBody) { + try { + JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class); + if (jsonObject != null) { + String encryptedResponse = jsonObjectToString(jsonObject.getAsJsonObject("result"), "response"); + return tapoCipher.decode(encryptedResponse); + } else { + handleError(new TapoErrorHandler(ERR_JSON_DECODE_FAIL)); + } + } catch (Exception ex) { + logger.debug("({}) exception '{}' decryptingResponse: '{}'", uid, ex.toString(), responseBody); + } + return responseBody; + } + + /** + * encrypt payload + * + * @param payload + * @return encrypted payload + */ + protected String encryptPayload(String payload) { + try { + return tapoCipher.encode(payload); + } catch (Exception ex) { + logger.debug("({}) exception encoding Payload '{}'", uid, ex.toString()); + return ""; + } + } + + /** + * perform logout (dispose cookie) + */ + public void logout() { + logger.trace("DeviceHttpApi_logout"); + unsetToken(); + unsetCookie(); + } + + /*********************************** + * + * GET RESULTS + * + ************************************/ + /** + * Logged In + * + * @return true if logged in + */ + public Boolean loggedIn() { + return loggedIn(false); + } + + /** + * Logged In + * + * @param raiseError if true + * @return true if logged in + */ + public Boolean loggedIn(Boolean raiseError) { + if (!this.token.isBlank() && !this.cookie.isBlank()) { + return true; + } else { + logger.trace("({}) not logged in", uid); + if (raiseError) { + handleError(new TapoErrorHandler(ERR_LOGIN)); + } + return false; + } + } + + /*********************************** + * + * SET VALUES + * + ************************************/ + + /** + * Set new ipAddress + * + * @param new ipAdress + */ + public void setDeviceURL(String ipAddress) { + this.ipAddress = ipAddress; + this.deviceURL = String.format(TAPO_DEVICE_URL, ipAddress); + } + + /** + * Set new ipAdresss with token + * + * @param ipAddress ipAddres of device + * @param token token from login-ressult + */ + public void setDeviceURL(String ipAddress, String token) { + this.ipAddress = ipAddress; + this.deviceURL = String.format(TAPO_DEVICE_URL, ipAddress); + } + + /** + * Set new token + * + * @param deviceURL + * @param token + */ + protected void setToken(String token) { + if (!token.isBlank()) { + String url = this.deviceURL.replaceAll("\\?token=\\w*", ""); + this.deviceURL = url + "?token=" + token; + } + this.token = token; + } + + /** + * Unset Token (device logout) + */ + protected void unsetToken() { + this.deviceURL = this.deviceURL.replaceAll("\\?token=\\w*", ""); + this.token = ""; + } + + /** + * Set new cookie + * + * @param cookie + */ + protected void setCookie(String cookie) { + this.cookie = cookie; + } + + /** + * Unset Cookie (device logout) + */ + protected void unsetCookie() { + bridge.getHttpClient().getCookieStore().removeAll(); + this.cookie = ""; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoBindingSettings.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoBindingSettings.java new file mode 100644 index 0000000000000..dd4ff8f1ac7b4 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoBindingSettings.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.constants; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link TapoBindingSettings} class defines common constants, which are + * used across the whole binding. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoBindingSettings { + public static final String BINDING_ID = "tapocontrol"; + + // List of all constant configurations + public static final String HTTP_HEADER_AUTH = "Authorization"; + public static final String HTTP_AUTH_TYPE_BASIC = "Basic"; + public static final String HTTP_AUTH_TYPE_COOKIE = "cookie"; + public static final String CONTENT_CHARSET = "UTF-8"; + public static final String CONTENT_TYPE_JSON = "application/json"; + public static final String TAPO_CLOUD_URL = "https://eu-wap.tplinkcloud.com"; + public static final String TAPO_APP_TYPE = "Tapo_Ios"; + public static final String TAPO_TERMINAL_UUID = "0A950402-7224-46EB-A450-7362CDB902A2"; + public static final String TAPO_DEVICE_URL = "http://%s/app"; + public static final Integer HTTP_MAX_CONNECTIONS = 10; // setMaxConnectionsPerDestination for HTTP-Client + public static final Integer HTTP_MAX_QUEUED_REQUESTS = 10; // setMaxRequestsQueuedPerDestination for HTTP-Client + public static final Integer TAPO_HTTP_TIMEOUT_MS = 5000; // http request timeout + public static final Integer TAPO_PING_TIMEOUT_MS = 2000; // ping timeout + public static final Integer TAPO_REFRESH_MIN_GAP_MS = 5000; // min gap between sending refresh request + public static final Integer TAPO_SEND_MIN_GAP_MS = 1000; // min gap between sending command request + public static final Integer TAPO_LOGIN_MIN_GAP_MS = 5000; // min gap between sending login request + public static final Integer TAPO_LOGIN_MAX_GAP_M = 1440; // max minutes to relogin to device + public static final Integer TAPO_DISCOVERY_TIMEOUT_S = 6; // timout device discovery in seconds + public static final Integer POLLING_MIN_INTERVAL_S = 10; // min polling interval (settings) + + // FORMATING CONSTANTS + public static final String IPV4_REGEX = "(([0-1]?[0-9]{1,2}\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))"; + public static final char MAC_DIVISION_CHAR = '-'; + + // LIST OF DEVICE-COMMANDS + public static final String DEVICE_CMD_GETINFO = "get_device_info"; + public static final String DEVICE_CMD_SETINFO = "set_device_info"; + public static final String DEVICE_CMD_CUSTOM = "custom_command"; +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoErrorConstants.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoErrorConstants.java new file mode 100644 index 0000000000000..d2e8d8839bf58 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoErrorConstants.java @@ -0,0 +1,157 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.constants; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link TapoErrorConstants} class defines error-message constants + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoErrorConstants { + /**************************************** + * LIST OF ERROR CODES + ****************************************/ + // List of API-ErrorCodes + public static final Integer ERR_COMMON_FAILED = -1; + public static final Integer ERR_SESSION_TIMEOUT = 9999; + public static final Integer ERR_NULL_TRANSPORT = 1000; + public static final Integer ERR_REQUEST = 1002; + public static final Integer ERR_HAND_SHAKE_FAILED = 1100; + public static final Integer ERR_LOGIN_FAILED = 1111; + public static final Integer ERR_HTTP_TRANSPORT_FAILED = 1112; + public static final Integer ERR_MULTI_REQUEST_FAILED = 1200; + public static final Integer ERR_JSON_DECODE_FAIL = -1003; + public static final Integer ERR_JSON_ENCODE_FAIL = -1004; + public static final Integer ERR_AES_DECODE_FAIL = -1005; + public static final Integer ERR_REQUEST_LEN_ERROR = -1006; + public static final Integer ERR_CLOUD_FAILED = -1007; + public static final Integer ERR_PARAMS = -1008; + public static final Integer ERR_RSA_KEY_LENGTH = -1010; + public static final Integer ERR_SESSION_PARAM = -1101; + public static final Integer ERR_QUICK_SETUP = -1201; + public static final Integer ERR_DEVICE = -1301; + public static final Integer ERR_DEVICE_NEXT_EVENT = -1302; + public static final Integer ERR_FIRMWARE = -1401; + public static final Integer ERR_FIRMWARE_VER_ERROR = -1402; + public static final Integer ERR_LOGIN = -1501; + public static final Integer ERR_TIME = -1601; + public static final Integer ERR_TIME_SYS = -1602; + public static final Integer ERR_TIME_SAVE = -1603; + public static final Integer ERR_WIRELESS = -1701; + public static final Integer ERR_WIRELESS_UNSUPPORTED = -1702; + public static final Integer ERR_SCHEDULE = -1801; + public static final Integer ERR_SCHEDULE_FULL = -1802; + public static final Integer ERR_SCHEDULE_CONFLICT = -1803; + public static final Integer ERR_SCHEDULE_SAVE = -1804; + public static final Integer ERR_SCHEDULE_INDEX = -1805; + public static final Integer ERR_COUNTDOWN = -1901; + public static final Integer ERR_COUNTDOWN_CONFLICT = -1902; + public static final Integer ERR_COUNTDOWN_SAVE = -1903; + public static final Integer ERR_ANTITHEFT = -2001; + public static final Integer ERR_ANTITHEFT_CONFLICT = -2002; + public static final Integer ERR_ANTITHEFT_SAVE = -2003; + public static final Integer ERR_ACCOUNT = -2101; + public static final Integer ERR_STAT = -2201; + public static final Integer ERR_STAT_SAVE = -2202; + public static final Integer ERR_DST = -2301; + public static final Integer ERR_DST_SAVE = -2302; + // -20661 + + // List of Binding-ErrorCodes + public static final Integer ERR_HTTP_RESPONSE = 9001; + public static final Integer ERR_COOKIE = 9002; + public static final Integer ERR_CREDENTIALS = 9003; + public static final Integer ERR_DEVICE_OFFLINE = 9009; + public static final Integer ERR_CONNECT_TIMEOUT = 9010; + + // List of Config-ErrorCodes + public static final Integer ERR_CONF_IP = 10001; // ip not set + public static final Integer ERR_CONF_CREDENTIALS = 10002; // credentials not set + public static final Integer ERR_NO_BRIDGE = 10003; // no bridge configured + + /**************************************** + * LIST OF ERROR MESSAGES + ****************************************/ + // List of CLOUD-Error-Messages + public static final String ERR_COMMON_FAILED_MSG = ""; // -1; + public static final String ERR_SESSION_TIMEOUT_MSG = "Session Timeout"; // 9999; + public static final String ERR_NULL_TRANSPORT_MSG = ""; // 1000; + public static final String ERR_REQUEST_MSG = "Invalid request or command"; // 1002; + public static final String ERR_HAND_SHAKE_FAILED_MSG = "Can't create handshake"; // 1100; + public static final String ERR_LOGIN_FAILED_MSG = ""; // 1111; + public static final String ERR_HTTP_TRANSPORT_FAILED_MSG = ""; // 1112; + public static final String ERR_MULTI_REQUEST_FAILED_MSG = ""; // 1200; + public static final String ERR_JSON_DECODE_FAIL_MSG = "json decode failed"; // -1003; + public static final String ERR_JSON_ENCODE_FAIL_MSG = "json encode failed"; // -1004; + public static final String ERR_AES_DECODE_FAIL_MSG = ""; // -1005; + public static final String ERR_REQUEST_LEN_ERROR_MSG = ""; // -1006; + public static final String ERR_CLOUD_FAILED_MSG = ""; // -1007; + public static final String ERR_PARAMS_MSG = "received invalid parameter"; // -1008; + public static final String ERR_RSA_KEY_LENGTH_MSG = "Invalid Public Key Length"; // -1010; + public static final String ERR_SESSION_PARAM_MSG = ""; // -1101; + public static final String ERR_QUICK_SETUP_MSG = ""; // -1201; + public static final String ERR_DEVICE_MSG = ""; // -1301; + public static final String ERR_DEVICE_NEXT_EVENT_MSG = ""; // -1302; + public static final String ERR_FIRMWARE_MSG = ""; // -1401; + public static final String ERR_FIRMWARE_VER_ERROR_MSG = ""; // -1402; + public static final String ERR_LOGIN_MSG = "Login Error"; // -1501; + public static final String ERR_TIME_MSG = ""; // -1601; + public static final String ERR_TIME_SYS_MSG = ""; // -1602; + public static final String ERR_TIME_SAVE_MSG = ""; // -1603; + public static final String ERR_WIRELESS_MSG = ""; // -1701; + public static final String ERR_WIRELESS_UNSUPPORTED_MSG = ""; // -1702; + public static final String ERR_SCHEDULE_MSG = ""; // -1801; + public static final String ERR_SCHEDULE_FULL_MSG = ""; // -1802; + public static final String ERR_SCHEDULE_CONFLICT_MSG = ""; // -1803; + public static final String ERR_SCHEDULE_SAVE_MSG = ""; // -1804; + public static final String ERR_SCHEDULE_INDEX_MSG = ""; // -1805; + public static final String ERR_COUNTDOWN_MSG = ""; // -1901; + public static final String ERR_COUNTDOWN_CONFLICT_MSG = ""; // -1902; + public static final String ERR_COUNTDOWN_SAVE_MSG = ""; // -1903; + public static final String ERR_ANTITHEFT_MSG = ""; // -2001; + public static final String ERR_ANTITHEFT_CONFLICT_MSG = ""; // -2002; + public static final String ERR_ANTITHEFT_SAVE_MSG = ""; // -2003; + public static final String ERR_ACCOUNT_MSG = ""; // -2101; + public static final String ERR_STAT_MSG = ""; // -2201; + public static final String ERR_STAT_SAVE_MSG = ""; // -2202; + public static final String ERR_DST_MSG = ""; // -2301; + public static final String ERR_DST_SAVE_MSG = ""; // -2302; + + // List of Binding-Error-Messages + public static final String ERR_HTTP_RESPONSE_MSG = "Invalid HTTP-Response"; // 9001 + public static final String ERR_COOKIE_MSG = "Cookie Error"; // 9002 + public static final String ERR_DEVICE_OFFLINE_MSG = "Device Offline"; // 9009 + public static final String ERR_CREDENTIALS_MSG = "Invalid Request or Credentials"; + public static final String ERR_CONNECT_TIMEOUT_MSG = "Connection Timeout - device not reachable"; + + // List of Config-Error-Messages + public static final String ERR_CONF_IP_MSG = "IP-Address not valid"; // 10001; + public static final String ERR_CONF_CREDENTIALS_MSG = "credentials not set (bridge)"; // 10002; + public static final String ERR_NO_BRIDGE_MSG = "no brigde configured"; // 10003; + + /**************************************** + * ErrorTypes + ****************************************/ + // communication errors - set device to offline (retry connect) + public static final Set LIST_COMMUNICATION_ERRORS = Set.of(ERR_HTTP_RESPONSE, ERR_COOKIE, + ERR_DEVICE_OFFLINE, ERR_CONNECT_TIMEOUT); + // configuration errors - set device to state configuration error (don't retry) + public static final Set LIST_CONFIGURATION_ERRORS = Set.of(ERR_CREDENTIALS); + // reauthenticate errors (trying login immediatly) + public static final Set LIST_REAUTH_ERRORS = Set.of(ERR_SESSION_TIMEOUT, ERR_HAND_SHAKE_FAILED); +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java new file mode 100644 index 0000000000000..faa22611a2f93 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/constants/TapoThingConstants.java @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 +***/ +package org.openhab.binding.tapocontrol.internal.constants; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; + +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link TapoBindingSettings} class defines common constants, which are + * used across the whole binding. + * + * @author Christian Wild - Initial contribution + ***/ +@NonNullByDefault +public class TapoThingConstants { + public static final String DEVICE_VENDOR = "Tapo"; + + /*** LIST OF SUPPORTED DEVICE NAMES ***/ + public static final String DEVICE_BRIDGE = "bridge"; + public static final String DEVICE_P100 = "P100"; + public static final String DEVICE_P105 = "P105"; + public static final String DEVICE_L510E = "L510_Series"; + public static final String DEVICE_L530E = "L530_Series"; + public static final String DEVICE_L900 = "L900"; + public static final String DEVICE_UNIVERSAL = "Test_Device"; + + /*** LIST OF SUPPORTED DEVICE DESCRIPTIONS ***/ + public static final String DEVICE_DESCRIPTION_BRIDGE = "TapoControl Cloud-Login"; + public static final String DEVICE_DESCRIPTION_SMART_PLUG = "SmartPlug"; + public static final String DEVICE_DESCRIPTION_WHITE_BULB = "White-Light-Bulb"; + public static final String DEVICE_DESCRIPTION_COLOR_BULB = "Color-Light-Bulb"; + public static final String DEVICE_DESCRIPTION_LIGHTSTRIP = "LightStrip"; + + /*** LIST OF SUPPORTED THING UIDS ***/ + public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_BRIDGE); + public static final ThingTypeUID P100_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_P100); + public static final ThingTypeUID P105_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_P105); + public static final ThingTypeUID L510E_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L510E); + public static final ThingTypeUID L530E_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L530E); + public static final ThingTypeUID L900_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_L900); + public static final ThingTypeUID UNIVERSAL_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_UNIVERSAL); + + /*** SET OF SUPPORTED UIDS ***/ + public static final Set SUPPORTED_BRIDGE_UIDS = Set.of(BRIDGE_THING_TYPE); + public static final Set SUPPORTED_SMART_PLUG_UIDS = Set.of(P100_THING_TYPE, P105_THING_TYPE); + public static final Set SUPPORTED_WHITE_BULB_UIDS = Set.of(L510E_THING_TYPE); + public static final Set SUPPORTED_COLOR_BULB_UIDS = Set.of(L530E_THING_TYPE); + public static final Set SUPPORTED_LIGHT_STRIP_UIDS = Set.of(L900_THING_TYPE); + public static final Set SUPPORTED_THING_TYPES_UIDS = Collections + .unmodifiableSet(Stream + .of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_SMART_PLUG_UIDS, SUPPORTED_WHITE_BULB_UIDS, + SUPPORTED_COLOR_BULB_UIDS, SUPPORTED_LIGHT_STRIP_UIDS) + .flatMap(Set::stream).collect(Collectors.toSet())); + + /*** THINGS WITH CHANNEL GROUPS ***/ + public static final Set CHANNEL_GROUP_THING_SET = Collections + .unmodifiableSet(Stream + .of(SUPPORTED_BRIDGE_UIDS, SUPPORTED_SMART_PLUG_UIDS, SUPPORTED_WHITE_BULB_UIDS, + SUPPORTED_COLOR_BULB_UIDS, SUPPORTED_LIGHT_STRIP_UIDS) + .flatMap(Set::stream).collect(Collectors.toSet())); + + /*** DEVICE PROPERTY STRINGS (CLOUD) ***/ + public static final String CLOUD_PROPERTY_ALIAS = "alias"; + public static final String CLOUD_PROPERTY_FW = "fwVer"; + public static final String CLOUD_PROPERTY_HW = "deviceHwVer"; + public static final String CLOUD_PROPERTY_ID = "deviceId"; + public static final String CLOUD_PROPERTY_MAC = "deviceMac"; + public static final String CLOUD_PROPERTY_MODEL = "deviceName"; // use name cause modell returns different values + public static final String CLOUD_PROPERTY_NAME = "deviceName"; + public static final String CLOUD_PROPERTY_REGION = "deviceRegion"; + public static final String CLOUD_PROPERTY_SERVER_URL = "appServerUrl"; + public static final String CLOUD_PROPERTY_TYPE = "deviceType"; + + /*** DEVICE PROPERTY STRINGS (DEVICE) ***/ + public static final String DEVICE_PROPERTY_BRIGHTNES = "brightness"; + public static final String DEVICE_PROPERTY_COLORTEMP = "color_temp"; + public static final String DEVICE_PROPERTY_FW = "fw_ver"; + public static final String DEVICE_PROPERTY_HUE = "hue"; + public static final String DEVICE_PROPERTY_HW = "hw_ver"; + public static final String DEVICE_PROPERTY_ID = "device_id"; + public static final String DEVICE_PROPERTY_IP = "ip"; + public static final String DEVICE_PROPERTY_MAC = "mac"; + public static final String DEVICE_PROPERTY_MODEL = "model"; + public static final String DEVICE_PROPERTY_NICKNAME = "nickname"; + public static final String DEVICE_PROPERTY_ON = "device_on"; + public static final String DEVICE_PROPERTY_ONTIME = "on_time"; + public static final String DEVICE_PROPERTY_OVERHEAT = "overheated"; + public static final String DEVICE_PROPERTY_REGION = "region"; + public static final String DEVICE_PROPERTY_SATURATION = "saturation"; + public static final String DEVICE_PROPERTY_SIGNAL = "signal_level"; + public static final String DEVICE_PROPERTY_SIGNAL_RSSI = "rssi"; + public static final String DEVICE_PROPERTY_TYPE = "type"; + public static final String DEVICE_PROPERTY_USAGE_7 = "time_usage_past7"; + public static final String DEVICE_PROPERTY_USAGE_30 = "time_usage_past30"; + public static final String DEVICE_PROPERTY_USAGE_TODAY = "time_usage_today"; + public static final String DEVICE_REPRASENTATION_PROPERTY = "macAddress"; + // lightning effects + public static final String DEVICE_PROPERTY_EFFECT = "lighting_effect"; + public static final String PROPERTY_LIGHTNING_EFFECT_BRIGHNTESS = "brightness"; + public static final String PROPERTY_LIGHTNING_EFFECT_COLORTEMPRANGE = "color_temp_range"; + public static final String PROPERTY_LIGHTNING_EFFECT_CUSTOM = "custom"; + public static final String PROPERTY_LIGHTNING_EFFECT_DISPLAYCOLORS = "displayColors"; + public static final String PROPERTY_LIGHTNING_EFFECT_ENABLE = "enable"; + public static final String PROPERTY_LIGHTNING_EFFECT_ID = "id"; + public static final String PROPERTY_LIGHTNING_EFFECT_NAME = "name"; + + /*** DEVICE SETTINGS ***/ + public static final Integer BULB_MIN_COLORTEMP = 2500; + public static final Integer BULB_MAX_COLORTEMP = 6500; + + /*** CHANNEL LISTS ***/ + // channel group actuator + public static final String CHANNEL_GROUP_ACTUATOR = "actuator"; + public static final String CHANNEL_BRIGHTNESS = "brightness"; + public static final String CHANNEL_COLOR = "color"; + public static final String CHANNEL_COLOR_TEMP = "colorTemperature"; + public static final String CHANNEL_OUTPUT = "output"; + public static final String CHANNEL_SWITCH = "switch"; + // channel group device + public static final String CHANNEL_GROUP_DEVICE = "device"; + public static final String CHANNEL_ONTIME = "onTime"; + public static final String CHANNEL_OVERHEAT = "overheated"; + public static final String CHANNEL_WIFI_STRENGTH = "wifiSignal"; + // channel group effect + public static final String CHANNEL_GROUP_EFFECTS = "effect"; + public static final String CHANNEL_FX_BRIGHTNESS = "brightness"; + public static final String CHANNEL_FX_COLORS = "displayColors"; + public static final String CHANNEL_FX_CUSTOM = "custom"; + public static final String CHANNEL_FX_ENABLE = "enable"; + public static final String CHANNEL_FX_NAME = "name"; + + /*** LIST OF PROPERTY NAMES ***/ + public static final String PROPERTY_FAMILY = "deviceFamily"; + public static final String PROPERTY_LOCATION = "location"; + public static final String PROPERTY_WIFI_LEVEL = "signal-strength"; +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java new file mode 100644 index 0000000000000..7feb214fe25c7 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoBridgeHandler.java @@ -0,0 +1,301 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.tapocontrol.internal.TapoDiscoveryService; +import org.openhab.binding.tapocontrol.internal.api.TapoCloudConnector; +import org.openhab.binding.tapocontrol.internal.helpers.TapoCredentials; +import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler; +import org.openhab.binding.tapocontrol.internal.structures.TapoBridgeConfiguration; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; + +/** + * The {@link TapoBridgeHandler} is responsible for handling commands, which are + * sent to one of the channels with a bridge. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoBridgeHandler extends BaseBridgeHandler { + private final Logger logger = LoggerFactory.getLogger(TapoBridgeHandler.class); + private final TapoErrorHandler bridgeError = new TapoErrorHandler(); + private final TapoBridgeConfiguration config; + private final HttpClient httpClient; + private @Nullable ScheduledFuture startupJob; + private @Nullable ScheduledFuture pollingJob; + private @Nullable ScheduledFuture discoveryJob; + private @NonNullByDefault({}) TapoCloudConnector cloudConnector; + private @NonNullByDefault({}) TapoDiscoveryService discoveryService; + private TapoCredentials credentials; + + private String uid; + + public TapoBridgeHandler(Bridge bridge, HttpClient httpClient) { + super(bridge); + Thing thing = getThing(); + this.cloudConnector = new TapoCloudConnector(this, httpClient); + this.config = new TapoBridgeConfiguration(thing); + this.credentials = new TapoCredentials(); + this.uid = thing.getUID().toString(); + this.httpClient = httpClient; + } + + /*********************************** + * + * BRIDGE INITIALIZATION + * + ************************************/ + @Override + /** + * INIT BRIDGE + * set credentials and login cloud + */ + public void initialize() { + this.config.loadSettings(); + this.credentials = new TapoCredentials(config.username, config.password); + activateBridge(); + } + + /** + * ACTIVATE BRIDGE + */ + private void activateBridge() { + // set the thing status to UNKNOWN temporarily and let the background task decide for the real status. + updateStatus(ThingStatus.UNKNOWN); + + // background initialization (delay it a little bit): + this.startupJob = scheduler.schedule(this::delayedStartUp, 1000, TimeUnit.MILLISECONDS); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.debug("{} Bridge doesn't handle command: {}", this.uid, command); + } + + @Override + public void dispose() { + stopScheduler(this.startupJob); + stopScheduler(this.pollingJob); + stopScheduler(this.discoveryJob); + super.dispose(); + } + + /** + * ACTIVATE DISCOVERY SERVICE + */ + @Override + public Collection> getServices() { + return Collections.singleton(TapoDiscoveryService.class); + } + + /** + * Set DiscoveryService + * + * @param discoveryService + */ + public void setDiscoveryService(TapoDiscoveryService discoveryService) { + this.discoveryService = discoveryService; + } + + /*********************************** + * + * SCHEDULER + * + ************************************/ + + /** + * delayed OneTime StartupJob + */ + private void delayedStartUp() { + loginCloud(); + startCloudScheduler(); + startDiscoveryScheduler(); + } + + /** + * Start CloudLogin Scheduler + */ + protected void startCloudScheduler() { + Integer pollingInterval = config.cloudReconnectIntervalM; + if (pollingInterval > 0) { + logger.trace("{} starting bridge cloud sheduler", this.uid); + + this.pollingJob = scheduler.scheduleWithFixedDelay(this::loginCloud, pollingInterval, pollingInterval, + TimeUnit.MINUTES); + } else { + stopScheduler(this.pollingJob); + } + } + + /** + * Start DeviceDiscovery Scheduler + */ + protected void startDiscoveryScheduler() { + Integer pollingInterval = config.discoveryIntervalM; + if (config.cloudDiscoveryEnabled && pollingInterval > 0) { + logger.trace("{} starting bridge discovery sheduler", this.uid); + + this.discoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, 0, pollingInterval, + TimeUnit.MINUTES); + } else { + stopScheduler(this.discoveryJob); + } + } + + /** + * Stop scheduler + * + * @param scheduler ScheduledFeature which schould be stopped + */ + protected void stopScheduler(@Nullable ScheduledFuture scheduler) { + if (scheduler != null) { + scheduler.cancel(true); + scheduler = null; + } + } + + /*********************************** + * + * ERROR HANDLER + * + ************************************/ + /** + * return device Error + * + * @return + */ + public TapoErrorHandler getError() { + return this.bridgeError; + } + + /** + * set device error + * + * @param tapoError TapoErrorHandler-Object + */ + public void setError(TapoErrorHandler tapoError) { + this.bridgeError.set(tapoError); + } + + /*********************************** + * + * BRIDGE COMMUNICATIONS + * + ************************************/ + + /** + * Login to Cloud + * + * @return + */ + public boolean loginCloud() { + bridgeError.reset(); // reset ErrorHandler + if (!config.username.isBlank() && !config.password.isBlank()) { + logger.debug("{} login with user {}", this.uid, config.username); + if (cloudConnector.login(config.username, config.password)) { + updateStatus(ThingStatus.ONLINE); + return true; + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, bridgeError.getMessage()); + } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "credentials not set"); + } + return false; + } + + /*********************************** + * + * DEVICE DISCOVERY + * + ************************************/ + + /** + * START DEVICE DISCOVERY + */ + public void discoverDevices() { + this.discoveryService.startScan(); + } + + /** + * GET DEVICELIST CONNECTED TO BRIDGE + * + * @return devicelist + */ + public JsonArray getDeviceList() { + JsonArray deviceList = new JsonArray(); + if (config.cloudDiscoveryEnabled) { + logger.trace("{} discover devicelist from cloud", this.uid); + deviceList = getDeviceListCloud(); + } + return deviceList; + } + + /** + * GET DEVICELIST FROM CLOUD + * returns all devices stored in cloud + * + * @return deviceList from cloud + */ + private JsonArray getDeviceListCloud() { + logger.trace("{} getDeviceList from cloud", this.uid); + bridgeError.reset(); // reset ErrorHandler + JsonArray deviceList = new JsonArray(); + if (loginCloud()) { + deviceList = this.cloudConnector.getDeviceList(); + } + return deviceList; + } + + /*********************************** + * + * BRIDGE GETTERS + * + ************************************/ + + public TapoCredentials getCredentials() { + return this.credentials; + } + + public HttpClient getHttpClient() { + return this.httpClient; + } + + public ThingUID getUID() { + return getThing().getUID(); + } + + public TapoBridgeConfiguration getBridgeConfig() { + return this.config; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoDevice.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoDevice.java new file mode 100644 index 0000000000000..7c63ed9ae31e5 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoDevice.java @@ -0,0 +1,479 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoBindingSettings.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants.*; +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.tapocontrol.internal.api.TapoDeviceConnector; +import org.openhab.binding.tapocontrol.internal.helpers.TapoErrorHandler; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceConfiguration; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.BridgeHandler; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract class as base for TAPO-Device device implementations. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public abstract class TapoDevice extends BaseThingHandler { + private final Logger logger = LoggerFactory.getLogger(TapoDevice.class); + protected final TapoErrorHandler deviceError = new TapoErrorHandler(); + protected final String uid; + protected TapoDeviceConfiguration config; + protected TapoDeviceInfo deviceInfo; + protected @Nullable ScheduledFuture startupJob; + protected @Nullable ScheduledFuture pollingJob; + protected @NonNullByDefault({}) TapoDeviceConnector connector; + protected @NonNullByDefault({}) TapoBridgeHandler bridge; + + /** + * Constructor + * + * @param thing Thing object representing device + */ + protected TapoDevice(Thing thing) { + super(thing); + this.config = new TapoDeviceConfiguration(thing); + this.deviceInfo = new TapoDeviceInfo(); + this.uid = getThing().getUID().getAsString(); + } + + /*********************************** + * + * INIT AND SETTINGS + * + ************************************/ + + /** + * INITIALIZE DEVICE + */ + @Override + public void initialize() { + try { + this.config.loadSettings(); + Bridge bridgeThing = getBridge(); + if (bridgeThing != null) { + BridgeHandler bridgeHandler = bridgeThing.getHandler(); + if (bridgeHandler != null) { + this.bridge = (TapoBridgeHandler) bridgeHandler; + this.connector = new TapoDeviceConnector(this, bridge); + } + } + } catch (Exception e) { + logger.debug("({}) configuration error : {}", uid, e.getMessage()); + } + TapoErrorHandler configError = checkSettings(); + if (!configError.hasError()) { + activateDevice(); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, configError.getMessage()); + } + } + + /** + * DISPOSE + */ + @Override + public void dispose() { + try { + stopScheduler(this.startupJob); + stopScheduler(this.pollingJob); + connector.logout(); + } catch (Exception e) { + // handle exception + } + super.dispose(); + } + + /** + * ACTIVATE DEVICE + */ + private void activateDevice() { + // set the thing status to UNKNOWN temporarily and let the background task decide for the real status. + updateStatus(ThingStatus.UNKNOWN); + + // background initialization (delay it a little bit): + this.startupJob = scheduler.schedule(this::delayedStartUp, 2000, TimeUnit.MILLISECONDS); + startScheduler(); + } + + /** + * CHECK SETTINGS + * + * @return TapoErrorHandler with configuration-errors + */ + protected TapoErrorHandler checkSettings() { + TapoErrorHandler configErr = new TapoErrorHandler(); + + /* check bridge */ + if (bridge == null || !(bridge instanceof TapoBridgeHandler)) { + configErr.raiseError(ERR_NO_BRIDGE); + return configErr; + } + /* check ip-address */ + if (!config.ipAddress.matches(IPV4_REGEX)) { + configErr.raiseError(ERR_CONF_IP); + return configErr; + } + /* check credentials */ + if (!bridge.getCredentials().areSet()) { + configErr.raiseError(ERR_CONF_CREDENTIALS); + return configErr; + } + return configErr; + } + + /** + * Checks if the response object contains errors and if so throws an {@link IOException} when an error code was set. + * + * @throws IOException if an error code was set in the response object + */ + protected void checkErrors() throws IOException { + final Integer errorCode = deviceError.getCode(); + + if (errorCode != 0) { + throw new IOException("Error (" + errorCode + "): " + deviceError.getMessage()); + } + } + + /*********************************** + * + * SCHEDULER + * + ************************************/ + /** + * delayed OneTime StartupJob + */ + private void delayedStartUp() { + connect(); + } + + /** + * Start scheduler + */ + protected void startScheduler() { + Integer pollingInterval = this.config.pollingInterval; + + if (pollingInterval > 0) { + if (pollingInterval < POLLING_MIN_INTERVAL_S) { + pollingInterval = POLLING_MIN_INTERVAL_S; + } + logger.trace("({}) starScheduler: create job with interval : {}", uid, pollingInterval); + this.pollingJob = scheduler.scheduleWithFixedDelay(this::schedulerAction, pollingInterval, pollingInterval, + TimeUnit.SECONDS); + } else { + stopScheduler(this.pollingJob); + } + } + + /** + * Stop scheduler + * + * @param scheduler ScheduledFeature which schould be stopped + */ + protected void stopScheduler(@Nullable ScheduledFuture scheduler) { + if (scheduler != null) { + scheduler.cancel(true); + scheduler = null; + } + } + + /** + * Scheduler Action + */ + protected void schedulerAction() { + logger.trace("({}) schedulerAction", uid); + queryDeviceInfo(); + } + + /*********************************** + * + * ERROR HANDLER + * + ************************************/ + /** + * return device Error + * + * @return + */ + public TapoErrorHandler getError() { + return this.deviceError; + } + + /** + * set device error + * + * @param tapoError TapoErrorHandler-Object + */ + public void setError(TapoErrorHandler tapoError) { + this.deviceError.set(tapoError); + handleConnectionState(); + } + + /*********************************** + * + * THING + * + ************************************/ + + /*** + * Check if ThingType is model + * + * @param model + * @return + */ + protected Boolean isThingModel(String model) { + try { + ThingTypeUID foundType = new ThingTypeUID(BINDING_ID, model); + ThingTypeUID expectedType = getThing().getThingTypeUID(); + return expectedType.equals(foundType); + } catch (Exception e) { + logger.warn("({}) verify thing model throws : {}", uid, e.getMessage()); + return false; + } + } + + /** + * CHECK IF RECEIVED DATA ARE FROM THE EXPECTED DEVICE + * Compare MAC-Adress + * + * @param deviceInfo + * @return true if is the expected device + */ + protected Boolean isExpectedThing(TapoDeviceInfo deviceInfo) { + try { + String expectedThingUID = getThing().getProperties().get(DEVICE_REPRASENTATION_PROPERTY); + String foundThingUID = deviceInfo.getRepresentationProperty(); + String foundModel = deviceInfo.getModel(); + if (expectedThingUID == null || expectedThingUID.isBlank()) { + return isThingModel(foundModel); + } + /* sometimes received mac was with and sometimes without "-" from device */ + expectedThingUID = unformatMac(expectedThingUID); + foundThingUID = unformatMac(foundThingUID); + return expectedThingUID.equals(foundThingUID); + } catch (Exception e) { + logger.warn("({}) verify thing model throws : {}", uid, e.getMessage()); + return false; + } + } + + /** + * Return ThingUID + */ + public ThingUID getThingUID() { + return getThing().getUID(); + } + + /*********************************** + * + * DEVICE PROPERTIES + * + ************************************/ + + /** + * query device Properties + */ + public void queryDeviceInfo() { + queryDeviceInfo(false); + } + + /** + * query device Properties + * + * @param ignoreGap ignore gap to last query. query anyway (force) + */ + public void queryDeviceInfo(boolean ignoreGap) { + deviceError.reset(); + if (connector.loggedIn()) { + connector.queryInfo(ignoreGap); + } else { + logger.debug("({}) tried to query DeviceInfo but not loggedIn", uid); + connect(); + } + } + + /** + * SET DEVICE INFOs to device + * + * @param deviceInfo + */ + public void setDeviceInfo(TapoDeviceInfo deviceInfo) { + this.deviceInfo = deviceInfo; + if (isExpectedThing(deviceInfo)) { + devicePropertiesChanged(deviceInfo); + handleConnectionState(); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "found type:'" + deviceInfo.getModel() + "' with mac:'" + deviceInfo.getRepresentationProperty() + + "'. Check IP-Address"); + } + } + + /** + * Handle full responsebody received from connector + * + * @param responseBody + */ + public void responsePasstrough(String responseBody) { + } + + /** + * UPDATE PROPERTIES + * + * If only one property must be changed, there is also a convenient method + * updateProperty(String name, String value). + * + * @param TapoDeviceInfo + */ + protected void devicePropertiesChanged(TapoDeviceInfo deviceInfo) { + /* device properties */ + Map properties = editProperties(); + properties.put(Thing.PROPERTY_MAC_ADDRESS, deviceInfo.getMAC()); + properties.put(Thing.PROPERTY_FIRMWARE_VERSION, deviceInfo.getFirmwareVersion()); + properties.put(Thing.PROPERTY_HARDWARE_VERSION, deviceInfo.getHardwareVersion()); + properties.put(Thing.PROPERTY_MODEL_ID, deviceInfo.getModel()); + properties.put(Thing.PROPERTY_SERIAL_NUMBER, deviceInfo.getSerial()); + updateProperties(properties); + } + + /** + * update channel state + * + * @param channelID + * @param value + */ + public void publishState(String channelID, State value) { + updateState(channelID, value); + } + + /*********************************** + * + * CONNECTION + * + ************************************/ + + /** + * Connect (login) to device + * + */ + public Boolean connect() { + deviceError.reset(); + Boolean loginSuccess = false; + + try { + loginSuccess = connector.login(); + if (loginSuccess) { + connector.queryInfo(); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, deviceError.getMessage()); + } + } catch (Exception e) { + updateStatus(ThingStatus.UNKNOWN); + } + return loginSuccess; + } + + /** + * disconnect device + */ + public void disconnect() { + connector.logout(); + } + + /** + * handle device state by connector error + */ + public void handleConnectionState() { + ThingStatus deviceState = getThing().getStatus(); + Integer errorCode = deviceError.getCode(); + + if (errorCode == 0) { + if (deviceState != ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + } + } else if (LIST_REAUTH_ERRORS.contains(errorCode)) { + connect(); + } else if (LIST_COMMUNICATION_ERRORS.contains(errorCode)) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, deviceError.getMessage()); + disconnect(); + } else if (LIST_CONFIGURATION_ERRORS.contains(errorCode)) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, deviceError.getMessage()); + } else { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, deviceError.getMessage()); + } + } + + /** + * Return IP-Address of device + */ + public String getIpAddress() { + return this.config.ipAddress; + } + + /*********************************** + * + * CHANNELS + * + ************************************/ + /** + * Get ChannelID including group + * + * @param group String channel-group + * @param channel String channel-name + * @return String channelID + */ + protected String getChannelID(String group, String channel) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + if (CHANNEL_GROUP_THING_SET.contains(thingTypeUID) && group.length() > 0) { + return group + "#" + channel; + } + return channel; + } + + /** + * Get Channel from ChannelID + * + * @param channelID String channelID + * @return String channel-name + */ + protected String getChannelFromID(ChannelUID channelID) { + String channel = channelID.getIdWithoutGroup(); + channel = channel.replace(CHANNEL_GROUP_ACTUATOR + "#", ""); + channel = channel.replace(CHANNEL_GROUP_DEVICE + "#", ""); + channel = channel.replace(CHANNEL_GROUP_EFFECTS + "#", ""); + return channel; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoLightStrip.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoLightStrip.java new file mode 100644 index 0000000000000..d1dfc137258a2 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoLightStrip.java @@ -0,0 +1,230 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.util.HashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.openhab.binding.tapocontrol.internal.structures.TapoLightEffect; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonObject; + +/** + * TAPO Smart-Plug-Device. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoLightStrip extends TapoDevice { + private final Logger logger = LoggerFactory.getLogger(TapoLightStrip.class); + + /** + * Constructor + * + * @param thing Thing object representing device + */ + public TapoLightStrip(Thing thing) { + super(thing); + } + + /** + * handle command sent to device + * + * @param channelUID channelUID command is sent to + * @param command command to be sent + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + Boolean refreshInfo = false; + + String channel = channelUID.getIdWithoutGroup(); + String group = channelUID.getGroupId(); + if (command instanceof RefreshType) { + refreshInfo = true; + } else if (group == CHANNEL_GROUP_EFFECTS) { + setLightEffect(channel, command); + refreshInfo = true; + } else { + switch (channel) { + case CHANNEL_OUTPUT: + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, command == OnOffType.ON); + refreshInfo = true; + break; + case CHANNEL_BRIGHTNESS: + if (command instanceof PercentType) { + Float percent = ((PercentType) command).floatValue(); + setBrightness(percent.intValue()); // 0..100% = 0..100 + refreshInfo = true; + } else if (command instanceof DecimalType) { + setBrightness(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR_TEMP: + if (command instanceof DecimalType) { + setColorTemp(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR: + if (command instanceof HSBType) { + setColor((HSBType) command); + refreshInfo = true; + } + break; + default: + logger.warn("({}) command type '{}' not supported for channel '{}'", uid, command.toString(), + channelUID.getId()); + } + } + + /* refreshInfo */ + if (refreshInfo) { + queryDeviceInfo(true); + } + } + + /** + * SET BRIGHTNESS + * + * @param newBrightness percentage 0-100 of new brightness + */ + protected void setBrightness(Integer newBrightness) { + /* switch off if 0 */ + if (newBrightness == 0) { + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, false); + } else { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_BRIGHTNES, newBrightness); + connector.sendDeviceCommands(newState); + } + } + + /** + * SET COLOR + * + * @param command + */ + protected void setColor(HSBType command) { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_HUE, command.getHue()); + newState.put(DEVICE_PROPERTY_SATURATION, command.getSaturation()); + newState.put(DEVICE_PROPERTY_BRIGHTNES, command.getBrightness()); + connector.sendDeviceCommands(newState); + } + + /** + * SET COLORTEMP + * + * @param colorTemp (Integer) in Kelvin + */ + protected void setColorTemp(Integer colorTemp) { + HashMap newState = new HashMap<>(); + colorTemp = limitVal(colorTemp, BULB_MIN_COLORTEMP, BULB_MAX_COLORTEMP); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_COLORTEMP, colorTemp); + connector.sendDeviceCommands(newState); + } + + /** + * set Light Effect from channel/command + * + * @param channel channel (effect) to set + * @param command command (value) to set + */ + protected void setLightEffect(String channel, Command command) { + TapoLightEffect lightEffect = deviceInfo.getLightEffect(); + switch (channel) { + case CHANNEL_FX_BRIGHTNESS: + if (command instanceof PercentType) { + Float percent = ((PercentType) command).floatValue(); + lightEffect.setBrightness(percent.intValue()); // 0..100% = 0..100 + } else if (command instanceof DecimalType) { + lightEffect.setBrightness(((DecimalType) command).intValue()); + } + break; + case CHANNEL_FX_COLORS: + // comming soon + break; + case CHANNEL_FX_NAME: + lightEffect.setName(command.toString()); + break; + case CHANNEL_FX_ENABLE: + lightEffect.setEnable(command == OnOffType.ON); + break; + } + setLightEffects(lightEffect); + } + + /** + * SET LIGHTNING EFFECTS + * + * @param lightEffect new lightEffect + */ + protected void setLightEffects(TapoLightEffect lightEffect) { + JsonObject newEffect = new JsonObject(); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_ENABLE, lightEffect.getEnable()); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_NAME, lightEffect.getName()); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_BRIGHNTESS, lightEffect.getBrightness()); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_COLORTEMPRANGE, lightEffect.getColorTempRange().toString()); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_DISPLAYCOLORS, lightEffect.getDisplayColors().toString()); + newEffect.addProperty(PROPERTY_LIGHTNING_EFFECT_CUSTOM, lightEffect.getCustom()); + + connector.sendDeviceCommand(DEVICE_PROPERTY_EFFECT, newEffect.toString()); + } + + /** + * UPDATE PROPERTIES + * + * @param TapoDeviceInfo + */ + @Override + protected void devicePropertiesChanged(TapoDeviceInfo deviceInfo) { + TapoLightEffect lightEffect = deviceInfo.getLightEffect(); + super.devicePropertiesChanged(deviceInfo); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_OUTPUT), getOnOffType(deviceInfo.isOn())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_BRIGHTNESS), + getPercentType(deviceInfo.getBrightness())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR_TEMP), + getDecimalType(deviceInfo.getColorTemp())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR), deviceInfo.getHSB()); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH), + getDecimalType(deviceInfo.getSignalLevel())); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME), + getQuantityType(deviceInfo.getOnTime(), Units.SECOND)); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated())); + // light effect + publishState(getChannelID(CHANNEL_GROUP_EFFECTS, CHANNEL_FX_BRIGHTNESS), + getPercentType(lightEffect.getBrightness())); + publishState(getChannelID(CHANNEL_GROUP_EFFECTS, CHANNEL_FX_NAME), getStringType(lightEffect.getName())); + publishState(getChannelID(CHANNEL_GROUP_EFFECTS, CHANNEL_FX_ENABLE), getOnOffType(lightEffect.getEnable())); + publishState(getChannelID(CHANNEL_GROUP_EFFECTS, CHANNEL_FX_CUSTOM), getOnOffType(lightEffect.getCustom())); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java new file mode 100644 index 0000000000000..e23aab3acb881 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartBulb.java @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.util.HashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TAPO Smart-Plug-Device. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoSmartBulb extends TapoDevice { + private final Logger logger = LoggerFactory.getLogger(TapoSmartBulb.class); + + /** + * Constructor + * + * @param thing Thing object representing device + */ + public TapoSmartBulb(Thing thing) { + super(thing); + } + + /** + * handle command sent to device + * + * @param channelUID channelUID command is sent to + * @param command command to be sent + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + Boolean refreshInfo = false; + + String channel = channelUID.getIdWithoutGroup(); + if (command instanceof RefreshType) { + refreshInfo = true; + } else { + switch (channel) { + case CHANNEL_OUTPUT: + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, command == OnOffType.ON); + refreshInfo = true; + break; + case CHANNEL_BRIGHTNESS: + if (command instanceof PercentType) { + Float percent = ((PercentType) command).floatValue(); + setBrightness(percent.intValue()); // 0..100% = 0..100 + refreshInfo = true; + } else if (command instanceof DecimalType) { + setBrightness(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR_TEMP: + if (command instanceof DecimalType) { + setColorTemp(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR: + if (command instanceof HSBType) { + setColor((HSBType) command); + refreshInfo = true; + } + break; + default: + logger.warn("({}) command type '{}' not supported for channel '{}'", uid, command.toString(), + channelUID.getId()); + } + } + + /* refreshInfo */ + if (refreshInfo) { + queryDeviceInfo(true); + } + } + + /** + * SET BRIGHTNESS + * + * @param newBrightness percentage 0-100 of new brightness + */ + protected void setBrightness(Integer newBrightness) { + /* switch off if 0 */ + if (newBrightness == 0) { + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, false); + } else { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_BRIGHTNES, newBrightness); + connector.sendDeviceCommands(newState); + } + } + + /** + * SET COLOR + * + * @param command + */ + protected void setColor(HSBType command) { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_HUE, command.getHue()); + newState.put(DEVICE_PROPERTY_SATURATION, command.getSaturation()); + newState.put(DEVICE_PROPERTY_BRIGHTNES, command.getBrightness()); + connector.sendDeviceCommands(newState); + } + + /** + * SET COLORTEMP + * + * @param colorTemp (Integer) in Kelvin + */ + protected void setColorTemp(Integer colorTemp) { + HashMap newState = new HashMap<>(); + colorTemp = limitVal(colorTemp, BULB_MIN_COLORTEMP, BULB_MAX_COLORTEMP); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_COLORTEMP, colorTemp); + connector.sendDeviceCommands(newState); + } + + /** + * UPDATE PROPERTIES + * + * @param TapoDeviceInfo + */ + @Override + protected void devicePropertiesChanged(TapoDeviceInfo deviceInfo) { + super.devicePropertiesChanged(deviceInfo); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_OUTPUT), getOnOffType(deviceInfo.isOn())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_BRIGHTNESS), + getPercentType(deviceInfo.getBrightness())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR_TEMP), + getDecimalType(deviceInfo.getColorTemp())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR), deviceInfo.getHSB()); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH), + getDecimalType(deviceInfo.getSignalLevel())); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME), + getQuantityType(deviceInfo.getOnTime(), Units.SECOND)); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated())); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartPlug.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartPlug.java new file mode 100644 index 0000000000000..170dd8ed4b4bf --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoSmartPlug.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TAPO Smart-Plug-Device. + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoSmartPlug extends TapoDevice { + private final Logger logger = LoggerFactory.getLogger(TapoSmartPlug.class); + + /** + * Constructor + * + * @param thing Thing object representing device + */ + public TapoSmartPlug(Thing thing) { + super(thing); + } + + /** + * handle command sent to device + * + * @param channelUID channelUID command is sent to + * @param command command to be sent + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + Boolean refreshInfo = false; + + /* perform actions */ + if (command instanceof RefreshType) { + refreshInfo = true; + } else if (command == OnOffType.ON) { + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, true); + refreshInfo = true; + } else if (command == OnOffType.OFF) { + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, false); + refreshInfo = true; + } else { + logger.warn("({}) command type '{}' not supported for channel '{}'", uid, command.toString(), + channelUID.getId()); + } + + /* refreshInfo */ + if (refreshInfo) { + queryDeviceInfo(true); + } + } + + /** + * UPDATE PROPERTIES + * + * @param TapoDeviceInfo + */ + @Override + protected void devicePropertiesChanged(TapoDeviceInfo deviceInfo) { + super.devicePropertiesChanged(deviceInfo); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_OUTPUT), getOnOffType(deviceInfo.isOn())); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH), + getDecimalType(deviceInfo.getSignalLevel())); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME), + getQuantityType(deviceInfo.getOnTime(), Units.SECOND)); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), getOnOffType(deviceInfo.isOverheated())); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoUniversalDevice.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoUniversalDevice.java new file mode 100644 index 0000000000000..b45f105f380f5 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/device/TapoUniversalDevice.java @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.device; + +import static org.openhab.binding.tapocontrol.internal.constants.TapoThingConstants.*; +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.util.HashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.tapocontrol.internal.structures.TapoDeviceInfo; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TAPO Universal-Device + * universal device for testing pruposes + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoUniversalDevice extends TapoDevice { + private final Logger logger = LoggerFactory.getLogger(TapoUniversalDevice.class); + + // CHANNEL LIST + public static final String CHANNEL_GROUP_DEBUG = "debug"; + public static final String CHANNEL_RESPONSE = "deviceResponse"; + public static final String CHANNEL_COMMAND = "deviceCommand"; + + /** + * Constructor + * + * @param thing Thing object representing device + */ + public TapoUniversalDevice(Thing thing) { + super(thing); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.debug("({}) handleCommand '{}' for channelUID {}", uid, command.toString(), channelUID.getId()); + Boolean refreshInfo = false; + + String channel = channelUID.getIdWithoutGroup(); + if (command instanceof RefreshType) { + refreshInfo = true; + } else { + switch (channel) { + case CHANNEL_OUTPUT: + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, command == OnOffType.ON); + refreshInfo = true; + break; + case CHANNEL_BRIGHTNESS: + if (command instanceof PercentType) { + Float percent = ((PercentType) command).floatValue(); + setBrightness(percent.intValue()); // 0..100% = 0..100 + refreshInfo = true; + } else if (command instanceof DecimalType) { + setBrightness(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR_TEMP: + if (command instanceof DecimalType) { + setColorTemp(((DecimalType) command).intValue()); + refreshInfo = true; + } + break; + case CHANNEL_COLOR: + if (command instanceof HSBType) { + setColor((HSBType) command); + refreshInfo = true; + } + break; + case CHANNEL_COMMAND: + String[] cmd = command.toString().split(":"); + if (cmd.length == 1) { + connector.sendCustomQuery(cmd[0]); + } else if (cmd.length == 2) { + connector.sendDeviceCommand(cmd[0], cmd[1]); + } else { + logger.warn("({}) wrong command format '{}'", uid, command.toString()); + } + break; + default: + logger.warn("({}) command type '{}' not supported for channel '{}'", uid, command.toString(), + channelUID.getId()); + } + } + + /* refreshInfo */ + if (refreshInfo) { + queryDeviceInfo(); + } + } + + /** + * SET BRIGHTNESS + * + * @param newBrightness percentage 0-100 of new brightness + */ + protected void setBrightness(Integer newBrightness) { + /* switch off if 0 */ + if (newBrightness == 0) { + connector.sendDeviceCommand(DEVICE_PROPERTY_ON, false); + } else { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_BRIGHTNES, newBrightness); + connector.sendDeviceCommands(newState); + } + } + + /** + * SET COLOR + * + * @param command + */ + protected void setColor(HSBType command) { + HashMap newState = new HashMap<>(); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_HUE, command.getHue()); + newState.put(DEVICE_PROPERTY_SATURATION, command.getSaturation()); + newState.put(DEVICE_PROPERTY_BRIGHTNES, command.getBrightness()); + connector.sendDeviceCommands(newState); + } + + /** + * SET COLORTEMP + * + * @param colorTemp (Integer) in Kelvin + */ + protected void setColorTemp(Integer colorTemp) { + HashMap newState = new HashMap<>(); + colorTemp = limitVal(colorTemp, BULB_MIN_COLORTEMP, BULB_MAX_COLORTEMP); + newState.put(DEVICE_PROPERTY_ON, true); + newState.put(DEVICE_PROPERTY_COLORTEMP, colorTemp); + connector.sendDeviceCommands(newState); + } + + /** + * SET DEVICE INFOs to device + * + * @param deviceInfo + */ + @Override + public void setDeviceInfo(TapoDeviceInfo deviceInfo) { + devicePropertiesChanged(deviceInfo); + handleConnectionState(); + } + + /** + * Handle full responsebody received from connector + * + * @param responseBody + */ + public void responsePasstrough(String responseBody) { + logger.debug("({}) received response {}", uid, responseBody); + publishState(getChannelID(CHANNEL_GROUP_DEBUG, CHANNEL_RESPONSE), getStringType(responseBody)); + } + + /** + * UPDATE PROPERTIES + * + * @param TapoDeviceInfo + */ + @Override + protected void devicePropertiesChanged(TapoDeviceInfo deviceInfo) { + super.devicePropertiesChanged(deviceInfo); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_OUTPUT), getOnOffType(deviceInfo.isOn())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_BRIGHTNESS), + getPercentType(deviceInfo.getBrightness())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR_TEMP), + getDecimalType(deviceInfo.getColorTemp())); + publishState(getChannelID(CHANNEL_GROUP_ACTUATOR, CHANNEL_COLOR), deviceInfo.getHSB()); + + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_WIFI_STRENGTH), + getDecimalType(deviceInfo.getSignalLevel())); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_ONTIME), + getQuantityType(deviceInfo.getOnTime(), Units.SECOND)); + publishState(getChannelID(CHANNEL_GROUP_DEVICE, CHANNEL_OVERHEAT), + getDecimalType(deviceInfo.isOverheated() ? 1 : 0)); + } + + /*********************************** + * + * CHANNELS + * + ************************************/ + /** + * Get ChannelID including group + * + * @param group String channel-group + * @param channel String channel-name + * @return String channelID + */ + @Override + protected String getChannelID(String group, String channel) { + return group + "#" + channel; + } + + /** + * Get Channel from ChannelID + * + * @param channelID String channelID + * @return String channel-name + */ + protected String getChannelFromID(ChannelUID channelID) { + String channel = channelID.getIdWithoutGroup(); + channel = channel.replace(CHANNEL_GROUP_ACTUATOR + "#", ""); + channel = channel.replace(CHANNEL_GROUP_DEVICE + "#", ""); + channel = channel.replace(CHANNEL_GROUP_DEBUG + "#", ""); + return channel; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/MimeEncode.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/MimeEncode.java new file mode 100644 index 0000000000000..9a6f6da68e72f --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/MimeEncode.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import static java.util.Base64.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * MimeEncoder + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class MimeEncode { + + public byte[] encode(byte[] src) { + return getMimeEncoder().encode(src); + } + + public String encodeToString(byte[] src) { + return getMimeEncoder().encodeToString(src); + } + + public byte[] decode(byte[] src) { + return getMimeDecoder().decode(src); + } + + public byte[] decode(String src) { + return getMimeDecoder().decode(src); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/PayloadBuilder.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/PayloadBuilder.java new file mode 100644 index 0000000000000..aa3500200f408 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/PayloadBuilder.java @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +/** + * PAYLOAD BUILDER + * Generates payload for TapoHttp request + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class PayloadBuilder { + public String method = ""; + private JsonObject parameters = new JsonObject(); + + /** + * Set Command + * + * @param command command (method) to send + */ + public void setCommand(String command) { + this.method = command; + } + + /** + * Add Parameter + * + * @param name parameter name + * @param value parameter value (typeOf Bool,Number or String) + */ + public void addParameter(String name, Object value) { + if (value instanceof Boolean) { + this.parameters.addProperty(name, (Boolean) value); + } else if (value instanceof Number) { + this.parameters.addProperty(name, (Number) value); + } else { + this.parameters.addProperty(name, value.toString()); + } + } + + /** + * Get JSON Payload (STRING) + * + * @return String JSON-Payload + */ + public String getPayload() { + Gson gson = new Gson(); + JsonObject payload = getJsonPayload(); + return gson.toJson(payload); + } + + /** + * Get JSON Payload (JSON-Object) + * + * @return JsonObject JSON-Payload + */ + public JsonObject getJsonPayload() { + JsonObject payload = new JsonObject(); + long timeMils = System.currentTimeMillis();// * 1000; + + payload.addProperty("method", this.method); + payload.add("params", this.parameters); + payload.addProperty("requestTimeMils", timeMils); + + return payload; + } + + /** + * Flush Parameters + * remove all parameters + */ + public void flushParameters(String command) { + this.parameters = new JsonObject(); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCipher.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCipher.java new file mode 100644 index 0000000000000..7923ee1bc415c --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCipher.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * TAPO-CIPHER + * Based on K4CZP3R's p100-java-poc + * + * @author Christian Wild - Initial Initial contribution + */ +@NonNullByDefault +public class TapoCipher { + private final Logger logger = LoggerFactory.getLogger(TapoCipher.class); + protected static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding"; + protected static final String CIPHER_ALGORITHM = "AES"; + protected static final String CIPHER_CHARSET = "UTF-8"; + protected static final String HANDSHAKE_TRANSFORMATION = "RSA/ECB/PKCS1Padding"; + protected static final String HANDSHAKE_ALGORITHM = "RSA"; + protected static final String HANDSHAKE_CHARSET = "UTF-8"; + + @NonNullByDefault({}) + private Cipher encodeCipher; + @NonNullByDefault({}) + private Cipher decodeCipher; + @NonNullByDefault({}) + private MimeEncode mimeEncode; + + /** + * CREATE NEW EMPTY CIPHER + */ + public TapoCipher() { + } + + /** + * CREATE NEW CIPHER WITH KEY AND CREDENTIALS + * + * @param handshakeKey Key from Handshake-Request + * @param credentials TapoCredentials + * @throws Exception + */ + public TapoCipher(String handshakeKey, TapoCredentials credentials) { + setKey(handshakeKey, credentials); + } + + /** + * SET NEW KEY AND CREDENTIALS + * + * @param handshakeKey + * @param credentials + */ + public void setKey(String handshakeKey, TapoCredentials credentials) { + logger.trace("Init TapoCipher with key: {} ", handshakeKey); + MimeEncode mimeEncode = new MimeEncode(); + try { + byte[] decode = mimeEncode.decode(handshakeKey.getBytes(HANDSHAKE_CHARSET)); + byte[] decode2 = mimeEncode.decode(credentials.getPrivateKeyBytes()); + Cipher instance = Cipher.getInstance(HANDSHAKE_TRANSFORMATION); + KeyFactory kf = KeyFactory.getInstance(HANDSHAKE_ALGORITHM); + PrivateKey p = kf.generatePrivate(new PKCS8EncodedKeySpec(decode2)); + instance.init(Cipher.DECRYPT_MODE, p); + byte[] doFinal = instance.doFinal(decode); + byte[] bArr = new byte[16]; + byte[] bArr2 = new byte[16]; + System.arraycopy(doFinal, 0, bArr, 0, 16); + System.arraycopy(doFinal, 16, bArr2, 0, 16); + initCipher(bArr, bArr2); + } catch (Exception ex) { + logger.warn("Something went wrong: {}", ex.getMessage()); + } + } + + /** + * INIT ENCODE/DECDE-CIPHERS + * + * @param bArr + * @param bArr2 + * @throws Exception + */ + protected void initCipher(byte[] bArr, byte[] bArr2) throws Exception { + try { + mimeEncode = new MimeEncode(); + SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, CIPHER_ALGORITHM); + IvParameterSpec ivParameterSpec = new IvParameterSpec(bArr2); + this.encodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); + this.decodeCipher = Cipher.getInstance(CIPHER_TRANSFORMATION); + this.encodeCipher.init(1, secretKeySpec, ivParameterSpec); + this.decodeCipher.init(2, secretKeySpec, ivParameterSpec); + } catch (Exception e) { + logger.warn("initChiper failed: {}", e.getMessage()); + this.encodeCipher = null; + this.decodeCipher = null; + } + } + + /** + * ENCODE STRING + * + * @param str source string to encode + * @return encoded string + * @throws Exception + */ + public String encode(String str) throws Exception { + byte[] doFinal; + doFinal = this.encodeCipher.doFinal(str.getBytes(CIPHER_CHARSET)); + String encrypted = mimeEncode.encodeToString(doFinal); + return encrypted.replace("\r\n", ""); + } + + /** + * DECODE STRING + * + * @param str source string to decode + * @return decoded string + * @throws Exception + */ + public String decode(String str) throws Exception { + byte[] data = mimeEncode.decode(str.getBytes(CIPHER_CHARSET)); + byte[] doFinal; + doFinal = this.decodeCipher.doFinal(data); + return new String(doFinal); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCredentials.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCredentials.java new file mode 100644 index 0000000000000..416905e597948 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoCredentials.java @@ -0,0 +1,220 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler class for TAPO Credentials + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoCredentials { + + private final Logger logger = LoggerFactory.getLogger(TapoCredentials.class); + private MimeEncode mimeEncoder; + private String encodedPassword = ""; + private String encodedEmail = ""; + private String publicKey = ""; + private String privateKey = ""; + private String username = ""; + private String password = ""; + + /** + * INIT CLASS + * + */ + public TapoCredentials() { + this.mimeEncoder = new MimeEncode(); + } + + /** + * INIT CLASS + * + * @param email E-Mail-adress of Tapo Cloud + * @param passowrd Password of Tapo Cloud + */ + public TapoCredentials(String eMail, String password) { + this.mimeEncoder = new MimeEncode(); + setCredectials(eMail, password); + } + + /** + * set credentials. + * + * @param username username (eMail-adress) of Tapo Cloud + * @param passowrd Password of Tapo Cloud + */ + public void setCredectials(String eMail, String password) { + try { + this.username = eMail; + this.password = password; + encryptCredentials(eMail, password); + createKeyPair(); + } catch (Exception e) { + logger.warn("error init credential class '{}'", e.toString()); + } + } + + /** + * encrypt credentials. + * + * @param username username (eMail-adress) of Tapo Cloud + * @param passowrd Password of Tapo Cloud + */ + private void encryptCredentials(String username, String password) throws Exception { + logger.trace("encrypt credentials for '{}'", username); + + /* Password Encoding */ + byte[] byteWord = password.getBytes(); + this.encodedPassword = mimeEncoder.encodeToString(byteWord); + + /* User Encoding */ + String encodedUser = this.shaDigestUsername(username); + byteWord = encodedUser.getBytes("UTF-8"); + this.encodedEmail = mimeEncoder.encodeToString(byteWord); + } + + /** + * Create Key-Pairs + * + */ + public void createKeyPair() throws NoSuchAlgorithmException { + logger.trace("generating new keypair"); + KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA"); + instance.initialize(1024, new SecureRandom()); + KeyPair generateKeyPair = instance.generateKeyPair(); + + this.publicKey = new String(mimeEncoder.encode(((RSAPublicKey) generateKeyPair.getPublic()).getEncoded())); + this.privateKey = new String(mimeEncoder.encode(((RSAPrivateKey) generateKeyPair.getPrivate()).getEncoded())); + logger.trace("new privateKey: '{}'", this.privateKey); + logger.trace("new ublicKey: '{}'", this.publicKey); + } + + /** + * shaDigest USERNAME + * + */ + private String shaDigestUsername(String str) throws NoSuchAlgorithmException { + byte[] bArr = str.getBytes(); + byte[] digest = MessageDigest.getInstance("SHA1").digest(bArr); + + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + String hexString = Integer.toHexString(b & 255); + if (hexString.length() == 1) { + sb.append("0"); + sb.append(hexString); + } else { + sb.append(hexString); + } + } + return sb.toString(); + } + + /** + * RETURN ENCODED PASSWORD + * + */ + public String getEncodedPassword() { + return encodedPassword; + } + + /** + * RETURN ENCODED E-MAIL + * + */ + public String getEncodedEmail() { + return encodedEmail; + } + + /** + * RETURN PASSWORD + * + */ + public String getPassword() { + return password; + } + + /** + * RETURN Username (E-MAIL) + * + */ + public String getUsername() { + return username; + } + + /** + * RETURN PRIVATE-KEY + * + * @return String -----BEGIN PRIVATE KEY-----\n%s\n-----END PRIVATE KEY----- + */ + public String getPrivateKey() { + return String.format("-----BEGIN PRIVATE KEY-----%n%s%n-----END PRIVATE KEY-----%n", privateKey); + } + + /** + * RETURN PUBLIC KEY + * + * @return String -----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY----- + */ + public String getPublicKey() { + return String.format("-----BEGIN PUBLIC KEY-----%n%s%n-----END PUBLIC KEY-----%n", publicKey); + } + + /** + * RETURN PRIVATE-KEY (BYTES) + * + * @return UTF-8 coded byte[] with private key + */ + public byte[] getPrivateKeyBytes() { + try { + return privateKey.getBytes("UTF-8"); + } catch (Exception e) { + return new byte[0]; + } + } + + /** + * RETURN PUBLIC-KEY (BYTES) + * + * @return UTF-8 coded byte[] with private key + */ + public byte[] getPublicKeyBytes() { + try { + return publicKey.getBytes("UTF-8"); + } catch (Exception e) { + return new byte[0]; + } + } + + /** + * CHECK IF CREDENTIALS ARE SET + * + * @return + */ + public Boolean areSet() { + return !(this.username.isEmpty() || this.password.isEmpty()); + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoErrorHandler.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoErrorHandler.java new file mode 100644 index 0000000000000..78f70ae1ea096 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoErrorHandler.java @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import static org.openhab.binding.tapocontrol.internal.helpers.TapoUtils.*; + +import java.lang.reflect.Field; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.tapocontrol.internal.constants.TapoErrorConstants; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +/** + * Class Handling TapoErrors + * + * @author Christian Wild - Initial contribution + */ +@NonNullByDefault +public class TapoErrorHandler extends Exception { + private static final long serialVersionUID = 0L; + private Integer errorCode = 0; + private String errorMessage = ""; + private String infoMessage = ""; + private Gson gson = new Gson(); + + /** + * Constructor + * + */ + public TapoErrorHandler() { + } + + /** + * Constructor + * + * @param errorCode error code (number) + */ + public TapoErrorHandler(Integer errorCode) { + raiseError(errorCode); + } + + /** + * Constructor + * + * @param errorCode error code (number) + * @param infoMessage optional info-message + */ + public TapoErrorHandler(Integer errorCode, String infoMessage) { + raiseError(errorCode, infoMessage); + } + + /** + * Constructor + * + * @param exception Exception + */ + public TapoErrorHandler(Exception ex) { + raiseError(ex); + } + + /** + * Constructor + * + * @param exception Exception + * @param infoMessage optional info-message + */ + public TapoErrorHandler(Exception ex, String infoMessage) { + raiseError(ex, infoMessage); + } + + /*********************************** + * + * Private Functions + * + ************************************/ + + /** + * GET ERROR-MESSAGE + * + * @param errCode error Number (or constant ERR_CODE ) + * @return error-message if set constant ERR_CODE_MSG. if not name of ERR_CODE is returned + */ + private String getErrorMessage(Integer errCode) { + Field[] fields = TapoErrorConstants.class.getDeclaredFields(); + /* loop ErrorConstants and search for code in value */ + for (Field f : fields) { + String constName = f.getName(); + try { + Integer val = (Integer) f.get(this); + if (val != null && val.equals(errCode)) { + Field constantName = TapoErrorConstants.class.getDeclaredField(constName + "_MSG"); + String msg = getValueOrDefault(constantName.get(null), "").toString(); + if (msg.length() > 2) { + return msg; + } else { + return infoMessage + " (" + constName + ")"; + } + } + } catch (Exception e) { + // next loop + } + } + return infoMessage + " (" + errCode.toString() + ")"; + } + + /*********************************** + * + * Public Functions + * + ************************************/ + + /** + * Raises new error + * + * @param errorCode error code (number) + */ + public void raiseError(Integer errorCode) { + raiseError(errorCode, ""); + } + + /** + * Raises new error + * + * @param errorCode error code (number) + * @param infoMessage optional info-message + */ + public void raiseError(Integer errorCode, String infoMessage) { + this.errorCode = errorCode; + this.infoMessage = infoMessage; + this.errorMessage = getErrorMessage(errorCode); + } + + /** + * Raises new error + * + * @param exception Exception + */ + public void raiseError(Exception ex) { + raiseError(ex, ""); + } + + /** + * Raises new error + * + * @param exception Exception + * @param infoMessage optional info-message + */ + public void raiseError(Exception ex, String infoMessage) { + this.errorCode = ex.hashCode(); + this.infoMessage = infoMessage; + this.errorMessage = getValueOrDefault(ex.getMessage(), ex.toString()); + } + + /** + * Take over tapoError + * + * @param tapoError + */ + public void set(TapoErrorHandler tapoError) { + this.errorCode = tapoError.getNumber(); + this.infoMessage = tapoError.getExtendedInfo(); + this.errorMessage = getErrorMessage(this.errorCode); + } + + /** + * Reset Error + */ + public void reset() { + this.errorCode = 0; + this.errorMessage = ""; + this.infoMessage = ""; + } + + /*********************************** + * + * GET RESULTS + * + ************************************/ + + /** + * Get Error Message + * + * @return error text + */ + @Override + @Nullable + public String getMessage() { + return this.errorMessage; + } + + /** + * Get Error Message directly by error-number + * + * @param errorCode + * @return error message + */ + public String getMessage(Integer errorCode) { + return getErrorMessage(errorCode); + } + + /** + * Get Error Code + * + * @return error code (integer) + */ + public Integer getCode() { + return this.errorCode; + } + + /** + * Get Info Message + * + * @return error extended info + */ + public String getExtendedInfo() { + return this.infoMessage; + } + + /** + * Get Error Number + * + * @return error number + */ + public Integer getNumber() { + return this.errorCode; + } + + /** + * Check if has Error + * + * @return true if has error + */ + public Boolean hasError() { + return this.errorCode != 0; + } + + /** + * Get JSON-Object with errror + * + * @return JsonObject with error-informations + */ + public JsonObject getJson() { + JsonObject json; + json = gson.fromJson("{'error_code': '" + errorCode + "', 'error_message':'" + errorMessage + "'}", + JsonObject.class); + if (json == null) { + json = new JsonObject(); + } + return json; + } +} diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoUtils.java b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoUtils.java new file mode 100644 index 0000000000000..1364ec7cbd768 --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/java/org/openhab/binding/tapocontrol/internal/helpers/TapoUtils.java @@ -0,0 +1,348 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.tapocontrol.internal.helpers; + +import javax.measure.Unit; +import javax.measure.quantity.Time; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +/** + * {@link TapoUtils} TapoUtils - + * Utility Helper Functions + * + * @author Christian Wild - Initial Initial contribution + */ +@NonNullByDefault +public class TapoUtils { + + /************************************ + * CALCULATION UTILS + ***********************************/ + /** + * Limit Value between limits + * + * @param value Integer + * @param lowerLimit + * @param upperLimit + * @return + */ + public static Integer limitVal(@Nullable Integer value, Integer lowerLimit, Integer upperLimit) { + if (value == null || value < lowerLimit) { + return lowerLimit; + } else if (value > upperLimit) { + return upperLimit; + } + return value; + } + + /************************************ + * FORMAT UTILS + ***********************************/ + /** + * return value or default val if it's null + * + * @param Type of value + * @param value value + * @param defaultValue defaut value + * @return + */ + public static T getValueOrDefault(@Nullable T value, T defaultValue) { + return value == null ? defaultValue : value; + } + + /** + * Format MAC-Address replacing old division chars and add new one + * + * @param mac unformated mac-Address + * @param newDivisionChar new division char (e.g. ":","-" ) + * @return new formated mac-Address + */ + public static String formatMac(String mac, char newDivisionChar) { + String unformatedMac = unformatMac(mac); + String formatedMac = unformatedMac.replaceAll("(.{2})", "$1" + newDivisionChar).substring(0, 17); + return formatedMac; + } + + /** + * unformat MAC-Address replace all division chars + * + * @param mac + * @return + */ + public static String unformatMac(String mac) { + mac = mac.replace("-", ""); + mac = mac.replace(":", ""); + mac = mac.replace(".", ""); + return mac; + } + + /** + * HEX-STRING to byte convertion + */ + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + try { + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); + } + } catch (Exception e) { + } + return data; + } + + /** + * Return Boolean from string + * + * @param s - string to be converted + * @param defVal - Default Value + */ + public Boolean stringToBool(@Nullable String s, boolean defVal) { + if (s == null) { + return defVal; + } + try { + return Boolean.parseBoolean(s); + } catch (Exception e) { + return defVal; + } + } + + /** + * Return Integer from string + * + * @param s - string to be converted + * @param defVal - Default Value + */ + public Integer stringToInteger(@Nullable String s, Integer defVal) { + if (s == null) { + return defVal; + } + try { + return Integer.valueOf(s); + } catch (Exception e) { + return defVal; + } + } + + /*********************************** + * JSON-FORMATER + ************************************/ + + public static boolean isValidJson(String json) { + try { + Gson gson = new Gson(); + JsonObject jsnObject = gson.fromJson(json, JsonObject.class); + return jsnObject != null; + } catch (Exception e) { + return false; + } + } + + /** + * + * @param name parameter name + * @param defVal - default value; + * @return string value + */ + public static String jsonObjectToString(@Nullable JsonObject jsonObject, String name, String defVal) { + if (jsonObject != null && jsonObject.has(name)) { + return jsonObject.get(name).getAsString(); + } else { + return defVal; + } + } + + /** + * + * @param name parameter name + * @return string value + */ + public static String jsonObjectToString(@Nullable JsonObject jsonObject, String name) { + return jsonObjectToString(jsonObject, name, ""); + } + + /** + * + * @param name parameter name + * @param defVal - default value; + * @return boolean value + */ + public static Boolean jsonObjectToBool(@Nullable JsonObject jsonObject, String name, Boolean defVal) { + if (jsonObject != null && jsonObject.has(name)) { + return jsonObject.get(name).getAsBoolean(); + } else { + return false; + } + } + + /** + * + * @param name parameter name + * @return boolean value + */ + public static Boolean jsonObjectToBool(@Nullable JsonObject jsonObject, String name) { + return jsonObjectToBool(jsonObject, name, false); + } + + /** + * + * @param name parameter name + * @param defVal - default value; + * @return integer value + */ + public static Integer jsonObjectToInt(@Nullable JsonObject jsonObject, String name, Integer defVal) { + if (jsonObject != null && jsonObject.has(name)) { + return jsonObject.get(name).getAsInt(); + } else { + return defVal; + } + } + + /** + * + * @param name parameter name + * @return integer value + */ + public static Integer jsonObjectToInt(@Nullable JsonObject jsonObject, String name) { + return jsonObjectToInt(jsonObject, name, 0); + } + + /** + * + * @param name parameter name + * @param defVal - default value; + * @return number value + */ + public static Number jsonObjectToNumber(@Nullable JsonObject jsonObject, String name, Number defVal) { + if (jsonObject != null && jsonObject.has(name)) { + return jsonObject.get(name).getAsNumber(); + } else { + return defVal; + } + } + + /** + * + * @param name parameter name + * @return number value + */ + public static Number jsonObjectToNumber(@Nullable JsonObject jsonObject, String name) { + return jsonObjectToNumber(jsonObject, name, 0); + } + + /************************************ + * TYPE UTILS + ***********************************/ + + /** + * Return OnOffType from bool + * + * @param boolVal + */ + public static OnOffType getOnOffType(@Nullable Boolean boolVal) { + return (boolVal != null ? boolVal ? OnOffType.ON : OnOffType.OFF : OnOffType.OFF); + } + + /** + * Return OnOffType from bool + * + * @param boolVal + */ + public static OnOffType getOnOffType(Integer intVal) { + return intVal == 0 ? OnOffType.OFF : OnOffType.ON; + } + + /** + * Return StringType from String + * + * @param strVal + */ + public static StringType getStringType(@Nullable String strVal) { + return new StringType(strVal != null ? strVal : ""); + } + + /** + * Return DecimalType from Double + * + * @param numVal + */ + public static DecimalType getDecimalType(@Nullable Double numVal) { + return new DecimalType((numVal != null ? numVal : 0)); + } + + /** + * Return DecimalType from Integer + * + * @param numVal + */ + public static DecimalType getDecimalType(@Nullable Integer numVal) { + return new DecimalType((numVal != null ? numVal : 0)); + } + + /** + * Return DecimalType from Long + * + * @param numVal + */ + public static DecimalType getDecimalTypel(@Nullable Long numVal) { + return new DecimalType((numVal != null ? numVal : 0)); + } + + /** + * + * @param numVal value 0-100 + * @return PercentType + */ + public static PercentType getPercentType(@Nullable Integer numVal) { + Integer val = limitVal(numVal, 0, 100); + return new PercentType(val); + } + + /** + * Return HSBType from integers + * + * @param hue integer hue-color + * @param saturation integer saturation + * @param brightness integer brightness + * @return HSBType + */ + public static HSBType getHSBType(Integer hue, Integer saturation, Integer brightness) { + DecimalType h = new DecimalType(hue); + PercentType s = new PercentType(saturation); + PercentType b = new PercentType(brightness); + return new HSBType(h, s, b); + } + + /** + * Return QuantityType with Time + * + * @param numVal Number with value + * @param unit TimeUnit (Unit + + org.openhab.addons.bundles + org.openhab.binding.deutschebahn + ${project.version} + org.openhab.addons.bundles org.openhab.binding.digiplex diff --git a/bundles/org.openhab.binding.deutschebahn/NOTICE b/bundles/org.openhab.binding.deutschebahn/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/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/openhab-addons diff --git a/bundles/org.openhab.binding.deutschebahn/README.md b/bundles/org.openhab.binding.deutschebahn/README.md new file mode 100644 index 0000000000000..23184d523fea2 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/README.md @@ -0,0 +1,345 @@ +# Deutsche Bahn Binding + +The Deutsche Bahn Binding provides the latest timetable information for all trains that arrive or depart at a specific train station, including live information for delays and changes in timetable. +The information are requested from the timetable api of Deutsche Bahn developer portal, so you'll need a (free) developer account to use this binding. + +## Supported Things + +- **timetable** The timetable bridge connects to the timetable api and provides information for the next trains that will arrive or depart at the configured station. +- **train** The train thing represents one trains within the configured timetable. This may be an arrival or a departure. + +## Thing Configuration + +### Generate Access-Key for timetable API + +To configure a timetable you first need to register at Deutsche Bahn developer portal and register for timetable API to get an access key. + +1. Go to [Deutsche Bahn Developer](https://developer.deutschebahn.com) +2. Register new account or login with an existing one +3. If no application is configured yet (check Tab "Meine Anwendungen") create a new application. Only the name is required, any other fields can be left blank. +4. Go to APIs - Timetables v1 (may be displayed on second page) +5. Choose your previously created application and hit "Abonnieren" +6. In confirmation-dialog choose "Wechsel zu meine Abonnements" +7. Create an access key for the production environment by hitting "Schlüssel Erstellen" +8. Copy the "Zugangstoken". This is required to access the api from openHAB. + +### Determine the EVA-No of your station + +For the selection of the station within openHAB you need the eva no. of the station. +You can look up the number within the csv file available at [Haltestellendaten](https://data.deutschebahn.com/dataset.tags.EVA-Nr..html). + +### Configure timetable bridge + +With access key for developer portal and eva no. of your station you're ready to configure a timetable (bridge) for this station. +In addition you can configure if only arrivals, only departures or all trains should be contained within the timetable. + +**timetable** parameters: + +| Property | Default | Required | Description | +|-|-|-|-| +| `accessToken` | | Yes | The access token for the timetable api within the developer portal of Deutsche Bahn. | +| `evaNo` | | Yes | The eva nr. of the train station for which the timetable will be requested.| +| `trainFilter` | | Yes | Selects the trains that will be displayed in the timetable. Either only arrivals, only departures or all trains can be displayed. | + + +### Configuring the trains + +Once you've created the timetable you can add train-things that represent the trains within this timetable. +Each train represents one position within the timetable. For example: If you configure a train with position 1 this will be +the next train that arrives / departs at the given station. Position 2 will be the second one, and so on. If you want to +show the next 4 trains for a station, create 4 things with positions 1 to 4. + +**Attention:** The timetable api only provides data for the next 18 hours. If the timetable contains less train entries than you've created +train things, the channels of these trains will be undefined. + +**train** parameters: + +| Property | Default | Required | Description | +|-|-|-|-| +| `position` | | Yes | The position of the train within the timetable. | + + +## Channels + +Each train has a set of channels, that provides access to any information served by the timetable API. A detailed description of the values and their meaning can be found within +the [Timetables V1 API Description](https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData&). +The information are grouped into three channel-groups: +The first channel group (trip) contains all information for the trip of the train, for example the category (like ICE, RE, S). +The second and third channel group contains information about the the arrival and the departure of the train at the given station. +Both of the groups may provide an 'UNDEF' channel value, when the train does not arrive / depart at this station +(due it starts or ends at the given station). If you have configured your timetable to contain only departures (with property trainFilter) the departure channel values will always be defined +and if you have selected only arrivals the arrival channel values will always be defined. +Channels will have a 'NULL' channel value, when the corresponding attribute is not set. + +Basically most information are available as planned and changed value. This allows to easy display changed values (for example the delay or changed platform). + + +**Channels for trip information** +| channel | type | description | +|----------|--------|------------------------------| +| category | String | Provides the category of the trip, e.g. "ICE" or "RE". | +| number | String | Provides the trip/train number, e.g. "4523". | +| filter-flags | String | Provides the filter flags. | +| trip-type | String | Provides the type of the trip. | +| owner | String | Provides the owner of the train. A unique short-form and only intended to map a trip to specific evu (EisenbahnVerkehrsUnternehmen). | + + +**Channels for arrival / departure** +| channel | type | description | +|----------|--------|------------------------------| +| planned-path | String | Provides the planned path of a train. | +| changed-path | String | Provides the changed path of a train. | +| planned-platform | String | Provides the planned platform of a train. | +| changed-platform | String | Provides the changed platform of a train. | +| planned-time | DateTime | Provides the planned time of a train. | +| changed-time | DateTime | Provides the changed time of a train. | +| planned-status | String | Provides the planned status (planned, added, cancelled) of a train. | +| changed-status | String | Provides the changed status (planned, added, cancelled) of a train. | +| cancellation-time | DateTime | Time when the cancellation of this stop was created. | +| line | String | The line of the train. | +| messages | String | Messages for this train. Contains all translated codes from the messages of the selected train stop. Multiple messages will be separated with a single dash. | +| hidden | Switch | On if the event should not be shown because travellers are not supposed to enter or exit the train at this stop. | +| wings | String | A sequence of trip id separated by pipe symbols. | +| transition | String | Trip id of the next or previous train of a shared train. At the start stop this references the previous trip, at the last stop it references the next trip. | +| planned-distant-endpoint | String | Planned distant endpoint of a train. | +| changed-distant-endpoint | String | Changed distant endpoint of a train. | +| distant-change | Number | Distant change | +| planned-final-station | String | Planned final station of the train. For arrivals the starting station is returned, for departures the target station is returned. | +| planned-intermediate-stations | String | Returns the planned stations this train came from (for arrivals) or the stations this train will go to (for departures). Stations will be separated by single dash. | +| changed-final-station | String | Changed final station of the train. For arrivals the starting station is returned, for departures the target station is returned. | +| changed-intermediate-stations | String | Returns the changed stations this train came from (for arrivals) or the stations this train will go to (for departures). Stations will be separated by single dash. | + +## Full Example + +timetable.things + +``` +Bridge deutschebahn:timetable:timetableLehrte "Fahrplan Lehrte" [ accessToken="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", trainFilter="departures", evaNo="8000226" ] { + Thing deutschebahn:train:timetableLehrte:lehrteZug1 "Zug 1" [ position="1" ] + Thing deutschebahn:train:timetableLehrte:lehrteZug2 "Zug 2" [ position="2" ] +} +``` + +timetable.items + +``` +// Groups +Group zug1 "Zug 1" +Group zug1Fahrt "Zug 1 Fahrt" (zug1) +Group zug1Ankunft "Zug 1 Ankunft" (zug1) +Group zug1Abfahrt "Zug 1 Abfahrt" (zug1) + +// Trip Information +String Zug1_Trip_Category "Kategorie" (zug1Fahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:trip#category"} +String Zug1_Trip_Number "Nummer" (zug1Fahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:trip#number"} +String Zug1_Trip_FilterFlags "Filter" (zug1Fahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:trip#filter-flags"} +String Zug1_Trip_TripType "Fahrttyp" (zug1Fahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:trip#trip-type"} +String Zug1_Trip_Owner "Unternehmen" (zug1Fahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:trip#owner"} + + +// Arrival Information +DateTime Zug1_Arrival_Plannedtime "Geplante Zeit" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-time"} +DateTime Zug1_Arrival_Changedtime "Geänderte Zeit" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-time"} +String Zug1_Arrival_Plannedplatform "Geplantes Gleis" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-platform"} +String Zug1_Arrival_Changedplatform "Geändertes Gleis" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-platform"} +String Zug1_Arrival_Line "Linie" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#line"} +String Zug1_Arrival_Plannedintermediatestations "Geplante Halte" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-intermediate-stations"} +String Zug1_Arrival_Changedintermediatestations "Geänderte Halte" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-intermediate-stations"} +String Zug1_Arrival_Plannedfinalstation "Geplanter Start-/Zielbahnhof" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-final-station"} +String Zug1_Arrival_Changedfinalstation "Geänderter Start-/Zielbahnhof" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-final-station"} +String Zug1_Arrival_Messages "Meldungen" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#messages"} +String Zug1_Arrival_Plannedstatus "Geplanter Status" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-status"} +String Zug1_Arrival_Changedstatus "Geänderter Status" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-status"} +DateTime Zug1_Arrival_Cancellationtime "Stornierungs-Zeitpunkt" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#cancellation-time"} + +// Arrival advanced information +String Zug1_Arrival_Planneddistantendpoint "Geplanter entfernter Endpunkt" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-distant-endpoint"} +String Zug1_Arrival_Changeddistantendpoint "Geänderter entfernter Endpunkt" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-distant-endpoint"} +String Zug1_Arrival_Plannedpath "Geplante Route" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#planned-path"} +String Zug1_Arrival_Changedpath "Geändert Route" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#changed-path"} +Number Zug1_Arrival_Distantchange "Geänderter Zielbahnhof" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#distant-change"} +Switch Zug1_Arrival_Hidden "Versteckt" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#hidden"} +String Zug1_Arrival_Transition "Übergang" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#transition"} +String Zug1_Arrival_Wings "Wings" (zug1Ankunft) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:arrival#wings"} + +// Departure Information +DateTime Zug1_Departure_Plannedtime "Geplante Zeit" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-time"} +DateTime Zug1_Departure_Changedtime "Geänderte Zeit" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-time"} +String Zug1_Departure_Plannedplatform "Geplantes Gleis" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-platform"} +String Zug1_Departure_Changedplatform "Geändertes Gleis" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-platform"} +String Zug1_Departure_Line "Linie" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#line"} +String Zug1_Departure_Plannedintermediatestations "Geplante Halte" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-intermediate-stations"} +String Zug1_Departure_Changedintermediatestations "Geänderte Halte" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-intermediate-stations"} +String Zug1_Departure_Plannedfinalstation "Geplanter Start-/Zielbahnhof" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-final-station"} +String Zug1_Departure_Changedfinalstation "Geänderter Start-/Zielbahnhof" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-final-station"} +String Zug1_Departure_Messages "Meldungen" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#messages"} +String Zug1_Departure_Plannedstatus "Geplanter Status" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-status"} +String Zug1_Departure_Changedstatus "Geänderter Status" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-status"} +DateTime Zug1_Departure_Cancellationtime "Stornierungs-Zeitpunkt" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#cancellation-time"} + +// Departure advanced information +String Zug1_Departure_Planneddistantendpoint "Geplanter entfernter Endpunkt" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-distant-endpoint"} +String Zug1_Departure_Changeddistantendpoint "Geänderter entfernter Endpunkt" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-distant-endpoint"} +String Zug1_Departure_Plannedpath "Geplante Route" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#planned-path"} +String Zug1_Departure_Changedpath "Geändert Route" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#changed-path"} +Number Zug1_Departure_Distantchange "Geänderter Zielbahnhof" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#distant-change"} +Switch Zug1_Departure_Hidden "Versteckt" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#hidden"} +String Zug1_Departure_Transition "Übergang" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#transition"} +String Zug1_Departure_Wings "Wings" (zug1Abfahrt) {channel="deutschebahn:train:timetableLehrte:lehrteZug1:departure#wings"} + +``` + +Example widget for displaying train details + +``` +uid: timetable_train_details +tags: + - card +props: + parameters: + - context: item + label: Geplante Zeit + name: planned_time + required: true + type: TEXT + - context: item + label: Geänderte Zeit + name: changed_time + required: true + type: TEXT + - context: item + label: Geplantes Gleis + name: planned_platform + required: true + type: TEXT + - context: item + label: Geändertes Gleis + name: changed_platform + required: true + type: TEXT + - context: item + label: Linie + name: line + required: true + type: TEXT + - context: item + label: Meldungen + name: messages + required: true + type: TEXT + - context: item + label: Geplanter Start-/Zielbahnhof + name: planned_final_station + required: true + type: TEXT + - context: item + label: Geplante Halte + name: planned_intermediate_stations + required: true + type: TEXT + - context: item + label: Geändeter Start-/Zielbahnhof + name: changed_final_station + required: true + type: TEXT + - context: item + label: Geänderte Halte + name: changed_intermediate_stations + required: true + type: TEXT + - context: item + label: Geänderter Status + name: changed_state + required: true + type: TEXT + - context: item + label: Kategorie + name: category + required: true + type: TEXT + - context: item + label: Nummer + name: number + required: true + type: TEXT + parameterGroups: [] +timestamp: Oct 14, 2021, 11:24:45 AM +component: f7-card +config: + style: + padding: 10px +slots: + default: + - component: f7-row + slots: + default: + - component: f7-col + config: + width: 15 + slots: + default: + - component: Label + config: + text: "=items[props.planned_time].displayState + (items[props.changed_time].state != 'NULL' && items[props.changed_time].state != items[props.planned_time].state ? ' (' + items[props.changed_time].displayState + ')' : '')" + style: + color: "=items[props.changed_time].state != 'NULL' && items[props.changed_time].state != items[props.planned_time].state ? 'red' : ''" + - component: f7-col + config: + width: 75 + slots: + default: + - component: Label + config: + text: "=(items[props.changed_state].state == 'c' ? 'Zug fällt aus - ' : '') + (items[props.messages].state != 'NULL' ? items[props.messages].state : '')" + style: + color: red + - component: f7-col + config: + width: 10 + slots: + default: + - component: Label + config: + text: "=items[props.changed_platform].state != 'NULL' ? items[props.changed_platform].state : items[props.planned_platform].state" + style: + color: "=items[props.changed_platform].state != 'NULL' ? 'red' : ''" + text-align: right + - component: f7-row + slots: + default: + - component: f7-col + config: + width: 15 + slots: + default: + - component: Label + config: + text: "=items[props.line].state != 'NULL' ? (items[props.category].state + ' ' + items[props.line].state) : (items[props.category].state + ' ' + items[props.number].state)" + - component: f7-col + config: + width: 50 + slots: + default: + - component: Label + config: + text: "=items[props.changed_intermediate_stations].state != 'NULL' ? items[props.changed_intermediate_stations].state : items[props.planned_intermediate_stations].state" + style: + color: "=items[props.changed_intermediate_stations].state != 'NULL' ? 'red' : ''" + - component: f7-col + config: + width: 35 + slots: + default: + - component: Label + config: + text: "=items[props.changed_final_station].state != 'NULL' ? items[props.changed_final_station].state : items[props.planned_final_station].state" + style: + color: "=items[props.changed_final_station].state != 'NULL' ? 'red' : ''" + font-weight: bold + text-align: right +``` + + +Using the widget for displaying the next four departures: + +![Departures Hannover HBF](doc/Abfahrten_HannoverHBF.png "openHAB page with four widgets displaying the next departures at Hannover HBF") diff --git a/bundles/org.openhab.binding.deutschebahn/doc/Abfahrten_HannoverHBF.png b/bundles/org.openhab.binding.deutschebahn/doc/Abfahrten_HannoverHBF.png new file mode 100644 index 0000000000000000000000000000000000000000..2bc58850ac17db5bbdae1ce4f344854608bbed57 GIT binary patch literal 142067 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%0DbtpEMIj=Z00z#eHmwmt21ytBPteB9Vww~U9X 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 SZ+tiKkD9WkQn`Xfz`p?ULQ^LI literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.binding.deutschebahn/pom.xml b/bundles/org.openhab.binding.deutschebahn/pom.xml new file mode 100644 index 0000000000000..48ddb0006be01 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/pom.xml @@ -0,0 +1,54 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.deutschebahn + + openHAB Add-ons :: Bundles :: Deutsche Bahn Binding + + + + + org.jvnet.jaxb2.maven2 + maven-jaxb2-plugin + 0.14.0 + + + generate-jaxb-sources + + generate + + + + + org.openhab.binding.deutschebahn.internal.timetable.dto + src/main/resources/xsd + true + en + false + true + + -Xxew + -Xxew:instantiate early + + + + com.github.jaxb-xew-plugin + jaxb-xew-plugin + 1.10 + + + + + + + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/feature/feature.xml b/bundles/org.openhab.binding.deutschebahn/src/main/feature/feature.xml new file mode 100644 index 0000000000000..4269910d79c44 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.deutschebahn/${project.version} + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java new file mode 100644 index 0000000000000..b5c6db1040b75 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.JaxbEntity; +import org.openhab.core.types.State; + +/** + * Accessor for attribute value of an DTO-Object. + * + * @author Sönke Küper - Initial contribution. + * + * @param type of value in Bean. + * @param type of value in Bean. + * @param type of state. + */ +@NonNullByDefault +public abstract class AbstractDtoAttributeSelector { + + private final Function getter; + private final BiConsumer setter; + private final Function getState; + private final String channelTypeName; + private final Class stateType; + + /** + * Creates an new {@link EventAttribute}. + * + * @param getter Function to get the raw value. + * @param setter Function to set the raw value. + * @param getState Function to get the Value as {@link State}. + */ + protected AbstractDtoAttributeSelector(final String channelTypeName, // + final Function getter, // + final BiConsumer setter, // + final Function getState, // + final Class stateType) { + this.channelTypeName = channelTypeName; + this.getter = getter; + this.setter = setter; + this.getState = getState; + this.stateType = stateType; + } + + /** + * Returns the type of the state value. + */ + public final Class getStateType() { + return this.stateType; + } + + /** + * Returns the name of the corresponding channel-type. + */ + public final String getChannelTypeName() { + return this.channelTypeName; + } + + /** + * Returns the {@link State} for the selected attribute from the given DTO object + * Returns null if the value is null. + */ + @Nullable + public final STATE_TYPE getState(final DTO_TYPE object) { + final VALUE_TYPE value = this.getValue(object); + if (value == null) { + return null; + } + return this.getState.apply(value); + } + + /** + * Returns the value for the selected attribute from the given DTO object. + */ + @Nullable + public final VALUE_TYPE getValue(final DTO_TYPE object) { + return this.getter.apply(object); + } + + /** + * Sets the value for the selected attribute in the given DTO object + */ + public final void setValue(final DTO_TYPE event, final VALUE_TYPE object) { + this.setter.accept(event, object); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java new file mode 100644 index 0000000000000..6c0d767066949 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.types.State; + +/** + * Selection of an attribute within an {@link TimetableStop} that provides a channel {@link State}. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public interface AttributeSelection { + + /** + * Returns the {@link State} that should be set for the channels'value for this attribute. + */ + @Nullable + public abstract State getState(TimetableStop stop); +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnBindingConstants.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnBindingConstants.java new file mode 100644 index 0000000000000..539b22e738f61 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnBindingConstants.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link DeutscheBahnBindingConstants} class defines common constants, which are used across the whole binding. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public class DeutscheBahnBindingConstants { + + /** + * Binding-ID. + */ + public static final String BINDING_ID = "deutschebahn"; + + /** + * {@link ThingTypeUID} for Timetable-API Bridge. + */ + public static final ThingTypeUID TIMETABLE_TYPE = new ThingTypeUID(BINDING_ID, "timetable"); + + /** + * {@link ThingTypeUID} for Train. + */ + public static final ThingTypeUID TRAIN_TYPE = new ThingTypeUID(BINDING_ID, "train"); +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnHandlerFactory.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnHandlerFactory.java new file mode 100644 index 0000000000000..059f6b4dc53df --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnHandlerFactory.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import static org.openhab.binding.deutschebahn.internal.DeutscheBahnBindingConstants.TIMETABLE_TYPE; +import static org.openhab.binding.deutschebahn.internal.DeutscheBahnBindingConstants.TRAIN_TYPE; + +import java.util.Date; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link DeutscheBahnHandlerFactory} is responsible for creating things and thing handlers. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.deutschebahn", service = ThingHandlerFactory.class) +public class DeutscheBahnHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(TIMETABLE_TYPE, TRAIN_TYPE); + + @Override + public boolean supportsThingType(final ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(final Thing thing) { + final ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + + if (TIMETABLE_TYPE.equals(thingTypeUID)) { + return new DeutscheBahnTimetableHandler((Bridge) thing, TimetablesV1Impl::new, Date::new); + } else if (TRAIN_TYPE.equals(thingTypeUID)) { + return new DeutscheBahnTrainHandler(thing); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java new file mode 100644 index 0000000000000..ee93c69650e1b --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link DeutscheBahnTimetableConfiguration} for the Timetable bridge-type. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public class DeutscheBahnTimetableConfiguration { + + /** + * Access-Token. + */ + public String accessToken = ""; + + /** + * evaNo of the station to be queried. + */ + public String evaNo = ""; + + /** + * Filter for timetable stops. + */ + public String trainFilter = ""; + + /** + * Returns the {@link TimetableStopFilter}. + */ + public TimetableStopFilter getTimetableStopFilter() { + return TimetableStopFilter.valueOf(this.trainFilter.toUpperCase()); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java new file mode 100644 index 0000000000000..616493a999157 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java @@ -0,0 +1,302 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; + +import javax.xml.bind.JAXBException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.TimetableLoader; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Api; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1ApiFactory; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.io.net.http.HttpUtil; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** + * The {@link DeutscheBahnTimetableHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public class DeutscheBahnTimetableHandler extends BaseBridgeHandler { + + /** + * Wrapper containing things grouped by their position and calculates the max. required position. + */ + private static final class GroupedThings { + + private int maxPosition = 0; + private final Map> thingsPerPosition = new HashMap<>(); + + public void addThing(Thing thing) { + if (isTrain(thing)) { + int position = thing.getConfiguration().as(DeutscheBahnTrainConfiguration.class).position; + this.maxPosition = Math.max(this.maxPosition, position); + List thingsAtPosition = this.thingsPerPosition.get(position); + if (thingsAtPosition == null) { + thingsAtPosition = new ArrayList<>(); + this.thingsPerPosition.put(position, thingsAtPosition); + } + thingsAtPosition.add(thing); + } + } + + /** + * Returns the things at the given position. + */ + @Nullable + public List getThingsAtPosition(int position) { + return this.thingsPerPosition.get(position); + } + + /** + * Returns the max. configured position. + */ + public int getMaxPosition() { + return this.maxPosition; + } + } + + private static final long UPDATE_INTERVAL_SECONDS = 30; + + private final Lock monitor = new ReentrantLock(); + private @Nullable ScheduledFuture updateJob; + + private final Logger logger = LoggerFactory.getLogger(DeutscheBahnTimetableHandler.class); + private @Nullable TimetableLoader loader; + + private TimetablesV1ApiFactory timetablesV1ApiFactory; + + private Supplier currentTimeProvider; + + /** + * Creates an new {@link DeutscheBahnTimetableHandler}. + */ + public DeutscheBahnTimetableHandler( // + final Bridge bridge, // + final TimetablesV1ApiFactory timetablesV1ApiFactory, // + final Supplier currentTimeProvider) { + super(bridge); + this.timetablesV1ApiFactory = timetablesV1ApiFactory; + this.currentTimeProvider = currentTimeProvider; + } + + private List loadTimetable() { + final TimetableLoader currentLoader = this.loader; + if (currentLoader == null) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR); + return Collections.emptyList(); + } + + try { + final List stops = currentLoader.getTimetableStops(); + this.updateStatus(ThingStatus.ONLINE); + return stops; + } catch (final IOException e) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + return Collections.emptyList(); + } + } + + /** + * The Bridge-Handler does not handle any commands. + */ + @Override + public void handleCommand(final ChannelUID channelUID, final Command command) { + } + + @Override + public void initialize() { + final DeutscheBahnTimetableConfiguration config = this.getConfigAs(DeutscheBahnTimetableConfiguration.class); + + try { + final TimetablesV1Api api = this.timetablesV1ApiFactory.create(config.accessToken, HttpUtil::executeUrl); + + final TimetableStopFilter stopFilter = config.getTimetableStopFilter(); + + final EventType eventSelection = stopFilter == TimetableStopFilter.ARRIVALS ? EventType.ARRIVAL + : EventType.ARRIVAL; + + this.loader = new TimetableLoader( // + api, // + stopFilter, // + eventSelection, // + currentTimeProvider, // + config.evaNo, // + 1); // will be updated on first call + + this.updateStatus(ThingStatus.UNKNOWN); + + this.scheduler.execute(() -> { + this.updateChannels(); + this.restartJob(); + }); + } catch (JAXBException | SAXException | URISyntaxException e) { + this.logger.error("Error initializing api", e); + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + } + } + + @Override + public void dispose() { + this.stopUpdateJob(); + } + + /** + * Schedules an job that updates the timetable every 30 seconds. + */ + private void restartJob() { + this.logger.debug("Restarting jobs for bridge {}", this.getThing().getUID()); + this.monitor.lock(); + try { + this.stopUpdateJob(); + if (this.getThing().getStatus() == ThingStatus.ONLINE) { + this.updateJob = this.scheduler.scheduleWithFixedDelay(// + this::updateChannels, // + 0L, // + UPDATE_INTERVAL_SECONDS, // + TimeUnit.SECONDS // + ); + + this.logger.debug("Scheduled {} update of deutsche bahn timetable", this.updateJob); + } + } finally { + this.monitor.unlock(); + } + } + + /** + * Stops the update job. + */ + private void stopUpdateJob() { + this.monitor.lock(); + try { + final ScheduledFuture job = this.updateJob; + if (job != null) { + job.cancel(true); + } + this.updateJob = null; + } finally { + this.monitor.unlock(); + } + } + + private void updateChannels() { + final TimetableLoader currentLoader = this.loader; + if (currentLoader == null) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR); + return; + } + final GroupedThings groupedThings = this.groupThingsPerPosition(); + currentLoader.setStopCount(groupedThings.getMaxPosition()); + final List timetableStops = this.loadTimetable(); + if (timetableStops.isEmpty()) { + updateThingsToUndefined(groupedThings); + return; + } + + this.logger.debug("Retrieved {} timetable stops.", timetableStops.size()); + this.updateThings(groupedThings, timetableStops); + } + + /** + * No data was retrieved, so update all channel values to undefined. + */ + private void updateThingsToUndefined(GroupedThings groupedThings) { + for (List things : groupedThings.thingsPerPosition.values()) { + for (Thing thing : things) { + updateChannelsToUndefined(thing); + } + } + } + + private void updateChannelsToUndefined(Thing thing) { + for (Channel channel : thing.getChannels()) { + this.updateState(channel.getUID(), UnDefType.UNDEF); + } + } + + private void updateThings(GroupedThings groupedThings, final List timetableStops) { + int position = 1; + for (final TimetableStop stop : timetableStops) { + final List thingsAtPosition = groupedThings.getThingsAtPosition(position); + + if (thingsAtPosition != null) { + for (Thing thing : thingsAtPosition) { + final ThingHandler thingHandler = thing.getHandler(); + if (thingHandler != null) { + assert thingHandler instanceof DeutscheBahnTrainHandler; + ((DeutscheBahnTrainHandler) thingHandler).updateChannels(stop); + } + } + } + position++; + } + + // Update all things to undefined, for which no data was received. + while (position <= groupedThings.getMaxPosition()) { + final List thingsAtPosition = groupedThings.getThingsAtPosition(position); + if (thingsAtPosition != null) { + for (Thing thing : thingsAtPosition) { + updateChannelsToUndefined(thing); + } + } + position++; + } + } + + /** + * Returns an map containing the things grouped by timetable stop position. + */ + private GroupedThings groupThingsPerPosition() { + final GroupedThings groupedThings = new GroupedThings(); + for (Thing child : this.getThing().getThings()) { + groupedThings.addThing(child); + } + return groupedThings; + } + + private static boolean isTrain(Thing thing) { + final ThingTypeUID thingTypeUid = thing.getThingTypeUID(); + return thingTypeUid.equals(DeutscheBahnBindingConstants.TRAIN_TYPE); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainConfiguration.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainConfiguration.java new file mode 100644 index 0000000000000..196d6acca37ca --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainConfiguration.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link DeutscheBahnTrainConfiguration} for the train thing type. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public class DeutscheBahnTrainConfiguration { + + /** + * Position of the train in the timetable. + */ + public int position = 0; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandler.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandler.java new file mode 100644 index 0000000000000..e04b95ce48c8f --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandler.java @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler for an Train-Thing in DeutscheBahn Binding. + * + * Represents an Train that arrives / departs at the station selected by the DeutscheBahnTimetable-Bridge. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public class DeutscheBahnTrainHandler extends BaseThingHandler { + + /** + * Wraps the Channel-UID with the configured {@link AttributeSelection}. + */ + private final class ChannelWithConfig { + + private final ChannelUID channelUid; + private final AttributeSelection attributeSelection; + + /** + * Creates an new ChannelWithConfig. + * + * @param channelUid The UID of the channel + * @param configuration Configuration for the given channel. + * @param attributeSelection The attribute that provides the state that will be displayed. + */ + public ChannelWithConfig( // + final ChannelUID channelUid, // + final AttributeSelection attributeSelection) { + this.channelUid = channelUid; + this.attributeSelection = attributeSelection; + } + + /** + * Updates the value for the channel from given {@link TimetableStop}. + */ + public void updateChannelValue(final TimetableStop stop) { + final State newState = this.determineState(stop); + if (newState != null) { + DeutscheBahnTrainHandler.this.updateState(this.channelUid, newState); + } else { + DeutscheBahnTrainHandler.this.updateState(this.channelUid, UnDefType.NULL); + } + } + + @Nullable + private State determineState(final TimetableStop stop) { + return this.attributeSelection.getState(stop); + } + + @Override + public String toString() { + return this.channelUid.toString(); + } + } + + private final Logger logger = LoggerFactory.getLogger(DeutscheBahnTrainHandler.class); + private final List configuredChannels = new ArrayList<>(); + + /** + * Creates an new {@link DeutscheBahnTrainHandler}. + */ + public DeutscheBahnTrainHandler(Thing thing) { + super(thing); + } + + @Override + public void initialize() { + this.updateStatus(ThingStatus.UNKNOWN); + + if (this.getBridge() == null) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Please select bridge"); + return; + } + + this.createChannelMapping(); + this.updateStatus(ThingStatus.ONLINE); + } + + private void createChannelMapping() { + this.configuredChannels.clear(); + for (Channel channel : this.getThing().getChannelsOfGroup("trip")) { + this.createTripChannelConfiguration(channel); + } + for (Channel channel : this.getThing().getChannelsOfGroup("arrival")) { + this.createEventChannelConfiguration(EventType.ARRIVAL, channel); + } + for (Channel channel : this.getThing().getChannelsOfGroup("departure")) { + this.createEventChannelConfiguration(EventType.DEPARTURE, channel); + } + this.logger.debug("Created {} configured channels for thing {}.", this.configuredChannels.size(), + this.getThing().getUID()); + } + + /** + * Creates an {@link ChannelWithConfig} for an channel that represents an attribute of an + * {@link org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel}. + */ + private void createTripChannelConfiguration(Channel channel) { + final ChannelUID channelUid = channel.getUID(); + final String attributeName = getAttributeName(channelUid); + final TripLabelAttribute attribute = TripLabelAttribute.getByChannelName(attributeName); + if (attribute == null) { + this.logger.warn("Could not find trip attribute {} of channel: {} .", attribute, channelUid.getId()); + return; + } + final ChannelWithConfig channelWithConfig = new ChannelWithConfig( // + channelUid, // + attribute); + this.configuredChannels.add(channelWithConfig); + } + + /** + * Creates the {@link ChannelWithConfig} for an channel that represents an attribute of an + * {@link org.openhab.binding.deutschebahn.internal.timetable.dto.Event}.} + */ + private void createEventChannelConfiguration(EventType eventType, Channel channel) { + final ChannelUID channelUid = channel.getUID(); + final String attributeName = getAttributeName(channelUid); + final EventAttribute attribute = EventAttribute.getByChannelName(attributeName, eventType); + if (attribute == null) { + this.logger.warn("Could not find event attribute {} of channel: {} .", attribute, channelUid.getId()); + return; + } + final ChannelWithConfig channelWithConfig = new ChannelWithConfig( // + channelUid, // + new EventAttributeSelection(eventType, attribute)); + this.configuredChannels.add(channelWithConfig); + } + + /** + * Strips the attribute name from the channel-UID. + */ + private static String getAttributeName(ChannelUID channelUid) { + final String channelId = channelUid.getId(); + int hashIndex = channelId.indexOf("#"); + assert hashIndex > 0; + final String attributeName = channelId.substring(hashIndex + 1); + return attributeName; + } + + /** + * Does not handle any commands. + */ + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + } + + /** + * Updates the value for the channels of this train from the given {@link TimetableStop}. + */ + void updateChannels(TimetableStop stop) { + for (ChannelWithConfig channel : this.configuredChannels) { + channel.updateChannelValue(stop); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java new file mode 100644 index 0000000000000..26ad3e5a098ca --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java @@ -0,0 +1,427 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.EventStatus; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Message; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; + +/** + * Selector for the Attribute of an {@link Event}. + * + * chapter "1.2.11 Event" in Technical Interface Description for external Developers + * + * @see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData&#tab1 + * + * @author Sönke Küper - initial contribution + * + * @param type of value in Bean. + * @param type of state. + */ +@NonNullByDefault +public final class EventAttribute + extends AbstractDtoAttributeSelector { + + /** + * Planned Path. + */ + public static final EventAttribute PPTH = new EventAttribute<>("planned-path", Event::getPpth, + Event::setPpth, StringType::new, StringType.class); + + /** + * Changed Path. + */ + public static final EventAttribute CPTH = new EventAttribute<>("changed-path", Event::getCpth, + Event::setCpth, StringType::new, StringType.class); + /** + * Planned platform. + */ + public static final EventAttribute PP = new EventAttribute<>("planned-platform", Event::getPp, + Event::setPp, StringType::new, StringType.class); + /** + * Changed platform. + */ + public static final EventAttribute CP = new EventAttribute<>("changed-platform", Event::getCp, + Event::setCp, StringType::new, StringType.class); + /** + * Planned time. + */ + public static final EventAttribute PT = new EventAttribute<>("planned-time", + getDate(Event::getPt), setDate(Event::setPt), EventAttribute::createDateTimeType, DateTimeType.class); + /** + * Changed time. + */ + public static final EventAttribute CT = new EventAttribute<>("changed-time", + getDate(Event::getCt), setDate(Event::setCt), EventAttribute::createDateTimeType, DateTimeType.class); + /** + * Planned status. + */ + public static final EventAttribute PS = new EventAttribute<>("planned-status", + Event::getPs, Event::setPs, EventAttribute::fromEventStatus, StringType.class); + /** + * Changed status. + */ + public static final EventAttribute CS = new EventAttribute<>("changed-status", + Event::getCs, Event::setCs, EventAttribute::fromEventStatus, StringType.class); + /** + * Hidden. + */ + public static final EventAttribute HI = new EventAttribute<>("hidden", Event::getHi, + Event::setHi, EventAttribute::parseHidden, OnOffType.class); + /** + * Cancellation time. + */ + public static final EventAttribute CLT = new EventAttribute<>("cancellation-time", + getDate(Event::getClt), setDate(Event::setClt), EventAttribute::createDateTimeType, DateTimeType.class); + /** + * Wing. + */ + public static final EventAttribute WINGS = new EventAttribute<>("wings", Event::getWings, + Event::setWings, StringType::new, StringType.class); + /** + * Transition. + */ + public static final EventAttribute TRA = new EventAttribute<>("transition", Event::getTra, + Event::setTra, StringType::new, StringType.class); + /** + * Planned distant endpoint. + */ + public static final EventAttribute PDE = new EventAttribute<>("planned-distant-endpoint", + Event::getPde, Event::setPde, StringType::new, StringType.class); + /** + * Changed distant endpoint. + */ + public static final EventAttribute CDE = new EventAttribute<>("changed-distant-endpoint", + Event::getCde, Event::setCde, StringType::new, StringType.class); + /** + * Distant change. + */ + public static final EventAttribute DC = new EventAttribute<>("distant-change", Event::getDc, + Event::setDc, DecimalType::new, DecimalType.class); + /** + * Line. + */ + public static final EventAttribute L = new EventAttribute<>("line", Event::getL, Event::setL, + StringType::new, StringType.class); + + /** + * Messages. + */ + public static final EventAttribute, StringType> MESSAGES = new EventAttribute<>("messages", + EventAttribute.getMessages(), EventAttribute::setMessages, EventAttribute::mapMessages, StringType.class); + + /** + * Planned Start station. + */ + public static final EventAttribute PLANNED_START_STATION = new EventAttribute<>( + "planned-start-station", EventAttribute.getSingleStationFromPath(Event::getPpth, true), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Planned Previous stations. + */ + public static final EventAttribute PLANNED_PREVIOUS_STATIONS = new EventAttribute<>( + "planned-previous-stations", EventAttribute.getIntermediateStationsFromPath(Event::getPpth, true), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Planned Target station. + */ + public static final EventAttribute PLANNED_TARGET_STATION = new EventAttribute<>( + "planned-target-station", EventAttribute.getSingleStationFromPath(Event::getPpth, false), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Planned Following stations. + */ + public static final EventAttribute PLANNED_FOLLOWING_STATIONS = new EventAttribute<>( + "planned-following-stations", EventAttribute.getIntermediateStationsFromPath(Event::getPpth, false), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Changed Start station. + */ + public static final EventAttribute CHANGED_START_STATION = new EventAttribute<>( + "changed-start-station", EventAttribute.getSingleStationFromPath(Event::getCpth, true), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Changed Previous stations. + */ + public static final EventAttribute CHANGED_PREVIOUS_STATIONS = new EventAttribute<>( + "changed-previous-stations", EventAttribute.getIntermediateStationsFromPath(Event::getCpth, true), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Changed Target station. + */ + public static final EventAttribute CHANGED_TARGET_STATION = new EventAttribute<>( + "changed-target-station", EventAttribute.getSingleStationFromPath(Event::getCpth, false), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * Changed Following stations. + */ + public static final EventAttribute CHANGED_FOLLOWING_STATIONS = new EventAttribute<>( + "changed-following-stations", EventAttribute.getIntermediateStationsFromPath(Event::getCpth, false), + EventAttribute.voidSetter(), StringType::new, StringType.class); + + /** + * List containing all known {@link EventAttribute}. + */ + public static final List> ALL_ATTRIBUTES = Arrays.asList(PPTH, CPTH, PP, CP, PT, CT, PS, CS, + HI, CLT, WINGS, TRA, PDE, CDE, DC, L, MESSAGES); + + private static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyMMddHHmm"); + + /** + * Creates an new {@link EventAttribute}. + * + * @param getter Function to get the raw value. + * @param setter Function to set the raw value. + * @param getState Function to get the Value as {@link State}. + */ + private EventAttribute(final String channelTypeName, // + final Function getter, // + final BiConsumer setter, // + final Function getState, // + final Class stateType) { + super(channelTypeName, getter, setter, getState, stateType); + } + + private static StringType fromEventStatus(final EventStatus value) { + return new StringType(value.value()); + } + + private static OnOffType parseHidden(@Nullable Integer value) { + return OnOffType.from(value != null && value == 1); + } + + private static Function getDate(final Function getValue) { + return (final Event event) -> { + return parseDate(getValue.apply(event)); + }; + } + + private static BiConsumer setDate(final BiConsumer setter) { + return (final Event event, final Date value) -> { + synchronized (DATETIME_FORMAT) { + String formattedDate = DATETIME_FORMAT.format(value); + setter.accept(event, formattedDate); + } + }; + } + + private static void setMessages(Event event, List messages) { + event.getM().clear(); + event.getM().addAll(messages); + } + + @Nullable + private static synchronized Date parseDate(@Nullable final String dateValue) { + if ((dateValue == null) || dateValue.isEmpty()) { + return null; + } + try { + synchronized (DATETIME_FORMAT) { + return DATETIME_FORMAT.parse(dateValue); + } + } catch (final ParseException e) { + return null; + } + } + + @Nullable + private static DateTimeType createDateTimeType(final @Nullable Date value) { + if (value == null) { + return null; + } else { + final ZonedDateTime d = ZonedDateTime.ofInstant(value.toInstant(), ZoneId.systemDefault()); + return new DateTimeType(d); + } + } + + /** + * Maps the status codes from the messages into status texts. + */ + @Nullable + private static StringType mapMessages(final @Nullable List messages) { + if (messages == null || messages.isEmpty()) { + return StringType.EMPTY; + } else { + final String messageTexts = messages // + .stream()// + .filter((Message message) -> message.getC() != null) // + .map(Message::getC) // + .distinct() // + .map(MessageCodes::getMessage) // + .filter((String messageText) -> !messageText.isEmpty()) // + .collect(Collectors.joining(" - ")); + + return new StringType(messageTexts); + } + } + + private static Function> getMessages() { + return new Function>() { + + @Override + public @Nullable List apply(Event t) { + if (t.getM().isEmpty()) { + return null; + } else { + return t.getM(); + } + } + }; + } + + /** + * Returns an single station from an path value (i.e. pipe separated value of stations). + * + * @param getPath Getter for the path. + * @param returnFirst if true the first value will be returned, false will return the last + * value. + */ + private static Function getSingleStationFromPath( + final Function getPath, boolean returnFirst) { + return (final Event event) -> { + String path = getPath.apply(event); + if (path == null || path.isEmpty()) { + return null; + } + + final String[] stations = splitPath(path); + if (returnFirst) { + return stations[0]; + } else { + return stations[stations.length - 1]; + } + }; + } + + /** + * Returns all intermediate stations from an path. The first or last station will be omitted. The values will be + * separated by an single dash -. + * + * @param getPath Getter for the path. + * @param removeFirst if true the first value will be removed, false will remove the last + * value. + */ + private static Function getIntermediateStationsFromPath( + final Function getPath, boolean removeFirst) { + return (final Event event) -> { + final String path = getPath.apply(event); + if (path == null || path.isEmpty()) { + return null; + } + final String[] stationValues = splitPath(path); + Stream stations = Arrays.stream(stationValues); + if (removeFirst) { + stations = stations.skip(1); + } else { + stations = stations.limit(stationValues.length - 1); + } + return stations.collect(Collectors.joining(" - ")); + }; + } + + /** + * Setter that does nothing. + * Used for derived attributes that can't be set. + */ + private static BiConsumer voidSetter() { + return new BiConsumer() { + + @Override + public void accept(Event t, VALUE_TYPE u) { + } + }; + } + + private static String[] splitPath(final String path) { + return path.split("\\|"); + } + + /** + * Returns an {@link EventAttribute} for the given channel-type and {@link EventType}. + */ + @Nullable + public static EventAttribute getByChannelName(final String channelName, EventType eventType) { + switch (channelName) { + case "planned-path": + return PPTH; + case "changed-path": + return CPTH; + case "planned-platform": + return PP; + case "changed-platform": + return CP; + case "planned-time": + return PT; + case "changed-time": + return CT; + case "planned-status": + return PS; + case "changed-status": + return CS; + case "hidden": + return HI; + case "cancellation-time": + return CLT; + case "wings": + return WINGS; + case "transition": + return TRA; + case "planned-distant-endpoint": + return PDE; + case "changed-distant-endpoint": + return CDE; + case "distant-change": + return DC; + case "line": + return L; + case "messages": + return MESSAGES; + case "planned-final-station": + return eventType == EventType.ARRIVAL ? PLANNED_START_STATION : PLANNED_TARGET_STATION; + case "planned-intermediate-stations": + return eventType == EventType.ARRIVAL ? PLANNED_PREVIOUS_STATIONS : PLANNED_FOLLOWING_STATIONS; + case "changed-final-station": + return eventType == EventType.ARRIVAL ? CHANGED_START_STATION : CHANGED_TARGET_STATION; + case "changed-intermediate-stations": + return eventType == EventType.ARRIVAL ? CHANGED_PREVIOUS_STATIONS : CHANGED_FOLLOWING_STATIONS; + default: + return null; + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java new file mode 100644 index 0000000000000..51224949f9a10 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * Selection that returns the value of an {@link EventAttribute}. The required {@link Event} is + * selected with the given {@link EventType}. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public final class EventAttributeSelection implements AttributeSelection { + + private final EventType eventType; + private final EventAttribute eventAttribute; + + /** + * Creates an new {@link EventAttributeSelection}. + */ + public EventAttributeSelection(EventType eventType, EventAttribute eventAttribute) { + this.eventType = eventType; + this.eventAttribute = eventAttribute; + } + + @Nullable + @Override + public State getState(TimetableStop stop) { + final Event event = eventType.getEvent(stop); + if (event == null) { + return UnDefType.UNDEF; + } else { + return this.eventAttribute.getState(event); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventType.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventType.java new file mode 100644 index 0000000000000..a8422aabced52 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventType.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.function.Function; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Type of an {@link Event} within an {@link TimetableStop}. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public enum EventType { + + /** + * Selects the Arrival-Element (i.e. ar). + */ + ARRIVAL(TimetableStop::getAr, TimetableStop::getDp), + + /** + * Selects the departure element (i.e. dp). + */ + DEPARTURE(TimetableStop::getDp, TimetableStop::getAr); + + private final Function getter; + private final Function oppositeGetter; + + private EventType(Function getter, + Function oppositeGetter) { + this.getter = getter; + this.oppositeGetter = oppositeGetter; + } + + /** + * Returns the selected event from the given {@link TimetableStop}. + */ + @Nullable + public final Event getEvent(TimetableStop stop) { + return this.getter.apply(stop); + } + + /** + * Returns the opposite event from the given {@link TimetableStop}. + */ + @Nullable + public final Event getOppositeEvent(TimetableStop stop) { + return this.oppositeGetter.apply(stop); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/MessageCodes.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/MessageCodes.java new file mode 100644 index 0000000000000..fae86487fed87 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/MessageCodes.java @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Class containing the mappings for all message status codes. + * + * chapter "2 List of all codes" in Technical Interface Description for external Developers + * + * @see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData&#tab1 + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class MessageCodes { + + private static Map codes = new HashMap<>(); + static { + codes.put(0, "keine Verspätungsbegründung"); + codes.put(2, "Polizeiliche Ermittlung"); + codes.put(3, "Feuerwehreinsatz an der Strecke"); + codes.put(4, "kurzfristiger Personalausfall"); + codes.put(5, "ärztliche Versorgung eines Fahrgastes"); + codes.put(6, "Betätigen der Notbremse"); + codes.put(7, "Personen im Gleis"); + codes.put(8, "Notarzteinsatz am Gleis"); + codes.put(9, "Streikauswirkungen"); + codes.put(10, "Tiere im Gleis"); + codes.put(11, "Unwetter"); + codes.put(12, "Warten auf ein verspätetes Schiff"); + codes.put(13, "Pass- und Zollkontrolle"); + codes.put(14, "Technische Störung am Bahnhof"); + codes.put(15, "Beeinträchtigung durch Vandalismus"); + codes.put(16, "Entschärfung einer Fliegerbombe"); + codes.put(17, "Beschädigung einer Brücke"); + codes.put(18, "umgestürzter Baum im Gleis"); + codes.put(19, "Unfall an einem Bahnübergang"); + codes.put(20, "Tiere im Gleis"); + codes.put(21, "Warten auf Fahrgäste aus einem anderen Zug"); + codes.put(22, "Witterungsbedingte Störung"); + codes.put(23, "Feuerwehreinsatz auf Bahngelände"); + codes.put(24, "Verspätung im Ausland"); + codes.put(25, "Warten auf weitere Wagen"); + codes.put(28, "Gegenstände im Gleis"); + codes.put(29, "Ersatzverkehr mit Bus ist eingerichtet"); + codes.put(31, "Bauarbeiten"); + codes.put(32, "Verzögerung beim Ein-/Ausstieg"); + codes.put(33, "Oberleitungsstörung"); + codes.put(34, "Signalstörung"); + codes.put(35, "Streckensperrung"); + codes.put(36, "technische Störung am Zug"); + codes.put(38, "technische Störung an der Strecke"); + codes.put(39, "Anhängen von zusätzlichen Wagen"); + codes.put(40, "Stellwerksstörung /-ausfall"); + codes.put(41, "Störung an einem Bahnübergang"); + codes.put(42, "außerplanmäßige Geschwindigkeitsbeschränkung"); + codes.put(43, "Verspätung eines vorausfahrenden Zuges"); + codes.put(44, "Warten auf einen entgegenkommenden Zug"); + codes.put(45, "Überholung"); + codes.put(46, "Warten auf freie Einfahrt"); + codes.put(47, "verspätete Bereitstellung des Zuges"); + codes.put(48, "Verspätung aus vorheriger Fahrt"); + codes.put(55, "technische Störung an einem anderen Zug"); + codes.put(56, "Warten auf Fahrgäste aus einem Bus"); + codes.put(57, "Zusätzlicher Halt zum Ein-/Ausstieg für Reisende"); + codes.put(58, "Umleitung des Zuges"); + codes.put(59, "Schnee und Eis"); + codes.put(60, "Reduzierte Geschwindigkeit wegen Sturm"); + codes.put(61, "Türstörung"); + codes.put(62, "behobene technische Störung am Zug"); + codes.put(63, "technische Untersuchung am Zug"); + codes.put(64, "Weichenstörung"); + codes.put(65, "Erdrutsch"); + codes.put(66, "Hochwasser"); + codes.put(70, "WLAN im gesamten Zug nicht verfügbar"); + codes.put(71, "WLAN in einem/mehreren Wagen nicht verfügbar"); + codes.put(72, "Info-/Entertainment nicht verfügbar"); + codes.put(73, "Heute: Mehrzweckabteil vorne"); + codes.put(74, "Heute: Mehrzweckabteil hinten"); + codes.put(75, "Heute: 1. Klasse vorne"); + codes.put(76, "Heute: 1. Klasse hinten"); + codes.put(77, "ohne 1. Klasse"); + codes.put(79, "ohne Mehrzweckabteil"); + codes.put(80, "andere Reihenfolge der Wagen"); + codes.put(82, "mehrere Wagen fehlen"); + codes.put(83, "Störung fahrzeuggebundene Einstiegshilfe"); + codes.put(84, "Zug verkehrt richtig gereiht"); + codes.put(85, "ein Wagen fehlt"); + codes.put(86, "gesamter Zug ohne Reservierung"); + codes.put(87, "einzelne Wagen ohne Reservierung"); + codes.put(88, "keine Qualitätsmängel"); + codes.put(89, "Reservierungen sind wieder vorhanden"); + codes.put(90, "kein gastronomisches Angebot"); + codes.put(91, "fehlende Fahrradbeförderung"); + codes.put(92, "Eingeschränkte Fahrradbeförderung"); + codes.put(93, "keine behindertengerechte Einrichtung"); + codes.put(94, "Ersatzbewirtschaftung"); + codes.put(95, "Ohne behindertengerechtes WC"); + codes.put(96, "Überbesetzung mit Kulanzleistungen"); + codes.put(97, "Überbesetzung ohne Kulanzleistungen"); + codes.put(98, "sonstige Qualitätsmängel"); + codes.put(99, "Verzögerungen im Betriebsablauf"); + } + + private MessageCodes() { + } + + /** + * Returns the message for the given code or emtpy string if not present. + */ + public static String getMessage(final int code) { + final String message = codes.get(code); + if (message == null) { + return ""; + } else { + return message; + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java new file mode 100644 index 0000000000000..e0256f42453e9 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.function.Predicate; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Filter that selects {@link TimetableStop}, if they have an departure or an arrival element (or both). + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public enum TimetableStopFilter implements Predicate { + + /** + * Selects all entries. + */ + ALL { + @Override + public boolean test(TimetableStop t) { + return true; + } + }, + + /** + * Selects only stops with an departure. + */ + DEPARTURES { + @Override + public boolean test(TimetableStop t) { + return t.getDp() != null; + } + }, + + /** + * Selects only stops with an arrival. + */ + ARRIVALS { + @Override + public boolean test(TimetableStop t) { + return t.getAr() != null; + } + }; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java new file mode 100644 index 0000000000000..2acbaeaab5e40 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * Selection that returns the value of an {@link TripLabel}. + * + * chapter "1.2.7 TripLabel" in Technical Interface Description for external Developers + * + * @see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData&#tab1 + * + * @author Sönke Küper - Initial contribution. + * + * @param type of value in Bean. + * @param type of state. + */ +@NonNullByDefault +public final class TripLabelAttribute extends + AbstractDtoAttributeSelector implements AttributeSelection { + + /** + * Trip category. + */ + public static final TripLabelAttribute C = new TripLabelAttribute<>("category", TripLabel::getC, + TripLabel::setC, StringType::new, StringType.class); + + /** + * Number. + */ + public static final TripLabelAttribute N = new TripLabelAttribute<>("number", TripLabel::getN, + TripLabel::setN, StringType::new, StringType.class); + + /** + * Filter flags. + */ + public static final TripLabelAttribute F = new TripLabelAttribute<>("filter-flags", + TripLabel::getF, TripLabel::setF, StringType::new, StringType.class); + /** + * Trip Type. + */ + public static final TripLabelAttribute T = new TripLabelAttribute<>("trip-type", + TripLabel::getT, TripLabel::setT, TripLabelAttribute::fromTripType, StringType.class); + /** + * Owner. + */ + public static final TripLabelAttribute O = new TripLabelAttribute<>("owner", TripLabel::getO, + TripLabel::setO, StringType::new, StringType.class); + + /** + * Creates an new {@link TripLabelAttribute}. + * + * @param getter Function to get the raw value. + * @param setter Function to set the raw value. + * @param getState Function to get the Value as {@link State}. + */ + private TripLabelAttribute(final String channelTypeName, // + final Function getter, // + final BiConsumer setter, // + final Function getState, // + final Class stateType) { + super(channelTypeName, getter, setter, getState, stateType); + } + + @Nullable + @Override + public State getState(TimetableStop stop) { + if (stop.getTl() == null) { + return UnDefType.UNDEF; + } + return super.getState(stop.getTl()); + } + + private static StringType fromTripType(final TripType value) { + return new StringType(value.value()); + } + + /** + * Returns an {@link TripLabelAttribute} for the given channel-name. + */ + @Nullable + public static TripLabelAttribute getByChannelName(final String channelName) { + switch (channelName) { + case "category": + return C; + case "number": + return N; + case "filter-flags": + return F; + case "trip-type": + return T; + case "owner": + return O; + default: + return null; + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java new file mode 100644 index 0000000000000..96d1cf38639dc --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java @@ -0,0 +1,300 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.io.IOException; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.TimetableStopFilter; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.library.types.DateTimeType; + +/** + * Helper for loading the required amount of {@link TimetableStop} via an {@link TimetablesV1Api}. + * This consists of a series of calls. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class TimetableLoader { + + // The api provides at most 18 hours in advance. + private static final int MAX_ADVANCE_HOUR = 18; + + // The recent changes only contains all changes done within the last 2 minutes. + private static final int MAX_RECENT_CHANGE_UPDATE = 120; + + // The min. request interval for recent changes is 30 seconds. + private static final int MIN_RECENT_CHANGE_INTERVAL = 30; + + // Cache containing the TimetableStops per ID + private final Map cachedStopsPerId; + private final Map cachedChanges; + + private final TimetablesV1Api api; + private final TimetableStopFilter stopFilter; + private final TimetableStopComparator comparator; + private final Supplier currentTimeProvider; + private int stopCount; + + private final String evaNo; + + @Nullable + private Date lastRequestedPlan; + @Nullable + private Date lastRequestedChanges; + + /** + * Creates an new {@link TimetableLoader}. + * + * @param api {@link TimetablesV1Api} to use. + * @param stopFilter Filter for selection of loaded {@link TimetableStop}. + * @param requestedStopCount Count of stops to be loaded on each call. + * @param currentTimeProvider {@link Supplier} for the current time. + */ + public TimetableLoader(final TimetablesV1Api api, final TimetableStopFilter stopFilter, final EventType eventToSort, + final Supplier currentTimeProvider, final String evaNo, final int requestedStopCount) { + this.api = api; + this.stopFilter = stopFilter; + this.currentTimeProvider = currentTimeProvider; + this.evaNo = evaNo; + this.stopCount = requestedStopCount; + this.comparator = new TimetableStopComparator(eventToSort); + this.cachedStopsPerId = new HashMap<>(); + this.cachedChanges = new HashMap<>(); + this.lastRequestedChanges = null; + this.lastRequestedPlan = null; + } + + /** + * Sets the count of needed {@link TimetableStop} that is required at each call of {@link #getTimetableStops()}. + */ + public void setStopCount(int stopCount) { + this.stopCount = stopCount; + } + + /** + * Updates the cache with current data from plan and changes and returns the {@link TimetableStop}. + */ + public List getTimetableStops() throws IOException { + this.updateCache(); + final List result = new ArrayList<>(this.cachedStopsPerId.values()); + Collections.sort(result, this.comparator); + return result; + } + + /** + * Updates the cached {@link TimetableStop} to ensure that the requested amount of stops is available. + */ + private void updateCache() throws IOException { + final Date currentTime = this.currentTimeProvider.get(); + + // First update the changes. This will merge them into the existing plan data + // or cache them, if no corresponding stop is available. + this.updateChanges(currentTime); + + // Remove all stops that are in the past + this.removeOldStops(currentTime); + + // Finally fill up plan until required amount of data is available. + this.updatePlan(currentTime); + } + + /** + * Removes all stops from the cache with planned and changed time after the current time. + */ + private void removeOldStops(final Date currentTime) { + final Iterator> it = this.cachedStopsPerId.entrySet().iterator(); + while (it.hasNext()) { + final Entry currentEntry = it.next(); + final TimetableStop stop = currentEntry.getValue(); + + // Remove entry if planned and changed time are in the past + if (isInPast(stop, currentTime)) { + it.remove(); + } + } + } + + /** + * Returns true if the planned and changed time from arrival and departure are in the past. + */ + private static boolean isInPast(TimetableStop stop, Date currentTime) { + return isBefore(EventAttribute.PT, stop.getAr(), currentTime) // + && isBefore(EventAttribute.CT, stop.getAr(), currentTime) // + && isBefore(EventAttribute.PT, stop.getDp(), currentTime) // + && isBefore(EventAttribute.PT, stop.getDp(), currentTime); + } + + /** + * Checks if the value of the given {@link EventAttribute} is either null or before + * the given compareTime. + * If the {@link Event} is null it will return true. + */ + private static boolean isBefore( // + final EventAttribute attribute, // + final @Nullable Event event, // + final Date toCompare) { + if (event == null) { + return true; + } + final Date value = attribute.getValue(event); + if (value == null) { + return true; + } else { + return value.before(toCompare); + } + } + + /** + * Checks if enough plan entries are available and loads them from the backing {@link TimetablesV1Api} if required. + */ + private void updatePlan(final Date currentTime) throws IOException { + // If enough stops are available in cache do nothing. + if (this.cachedStopsPerId.size() >= this.stopCount) { + return; + } + + // start requesting at last request time. + final GregorianCalendar requestTime = new GregorianCalendar(); + if (this.lastRequestedPlan != null) { + requestTime.setTime(this.lastRequestedPlan); + requestTime.set(Calendar.HOUR_OF_DAY, requestTime.get(Calendar.HOUR_OF_DAY) + 1); + } else { + requestTime.setTime(currentTime); + } + + // Determine the max. time for which an plan is available + final GregorianCalendar maxRequestTime = new GregorianCalendar(); + maxRequestTime.setTime(currentTime); + maxRequestTime.set(Calendar.HOUR_OF_DAY, maxRequestTime.get(Calendar.HOUR_OF_DAY) + MAX_ADVANCE_HOUR); + + // load until required amount of stops is present or no more data is available. + while ((this.cachedStopsPerId.size() < this.stopCount) && requestTime.before(maxRequestTime)) { + final Timetable timetable = this.api.getPlan(this.evaNo, requestTime.getTime()); + this.lastRequestedPlan = requestTime.getTime(); + + // Filter only stops that are selected by given filter + final List stops = timetable // + .getS() // + .stream() // + .filter(this.stopFilter) // + .collect(Collectors.toList()); + + // Merge the loaded stops with the cached changes and put them into the plan cache. + this.processLoadedPlan(stops, currentTime); + + // Move request time one hour ahead. + requestTime.set(Calendar.HOUR_OF_DAY, requestTime.get(Calendar.HOUR_OF_DAY) + 1); + } + } + + /** + * Merges the loaded plan stops with the previously cached changes. + * The result will be cached as plan data, if not in the past. + */ + private void processLoadedPlan(List stops, Date currentTime) { + for (final TimetableStop stop : stops) { + + // Check if an change for the stop was cached and apply it + final TimetableStop change = this.cachedChanges.remove(stop.getId()); + if (change != null) { + TimetableStopMerger.merge(stop, change); + } + + // Check if stop is in past after applying changes and put + // into cached plan if not. + if (!isInPast(stop, currentTime)) { + this.cachedStopsPerId.put(stop.getId(), stop); + } + } + } + + /** + * Loads the changes from the api and merges them into the cached plan entries. + */ + private void updateChanges(final Date currentTime) throws IOException { + final List changes = this.loadChanges(currentTime); + this.processChanges(changes); + } + + /** + * Merges the given {@link TimetableStop} into the cached plan. + * If no stop in the plan for the change exist it will be put into the changes cache. + */ + private void processChanges(final List changes) { + for (final TimetableStop change : changes) { + + final TimetableStop existingEntry = this.cachedStopsPerId.get(change.getId()); + if (existingEntry != null) { + TimetableStopMerger.merge(existingEntry, change); + } else { + this.cachedChanges.put(change.getId(), change); + } + } + } + + /** + * Loads the full or recent changes depending on last request time. + */ + private List loadChanges(final Date currentTime) throws IOException { + boolean fullChanges = false; + final long secondsSinceLastUpdate = this.getSecondsSinceLastRequestedChanges(currentTime); + + // The recent changes are updated every 30 seconds, so if last update is less than 30 seconds do nothing. + if (secondsSinceLastUpdate < MIN_RECENT_CHANGE_INTERVAL) { + return Collections.emptyList(); + } + + // The recent changes are only available for 120 seconds, so if last update is older perform an full update. + if (secondsSinceLastUpdate >= MAX_RECENT_CHANGE_UPDATE) { + fullChanges = true; + } + + Timetable changes; + if (fullChanges) { + changes = this.api.getFullChanges(this.evaNo); + } else { + changes = this.api.getRecentChanges(this.evaNo); + } + this.lastRequestedChanges = currentTime; + return changes.getS(); + } + + @SuppressWarnings("null") + private long getSecondsSinceLastRequestedChanges(final Date currentTime) { + if (this.lastRequestedChanges == null) { + return Long.MAX_VALUE; + } else { + return ChronoUnit.SECONDS.between(this.lastRequestedChanges.toInstant(), currentTime.toInstant()); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopComparator.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopComparator.java new file mode 100644 index 0000000000000..520430fb61534 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopComparator.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.util.Comparator; +import java.util.Date; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * {@link Comparator} that sorts the {@link TimetableStop} according planned date and time. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public class TimetableStopComparator implements Comparator { + + private final EventType eventSelection; + + /** + * Creates an new {@link TimetableStopComparator} that sorts {@link TimetableStop} according the Event selected + * selected by the given {@link EventType}. + */ + public TimetableStopComparator(EventType eventSelection) { + this.eventSelection = eventSelection; + } + + @Override + public int compare(TimetableStop o1, TimetableStop o2) { + return determinePlannedDate(o1, this.eventSelection).compareTo(determinePlannedDate(o2, this.eventSelection)); + } + + /** + * Returns the planned-Time for the given {@link TimetableStop}. + * The time will be returned from the {@link Event} selected by the given {@link EventType}. + * If the {@link TimetableStop} has no according {@link Event} the other Event will be used. + */ + private static Date determinePlannedDate(TimetableStop stop, EventType eventSelection) { + Event selectedEvent = eventSelection.getEvent(stop); + if (selectedEvent == null) { + selectedEvent = eventSelection.getOppositeEvent(stop); + } + if (selectedEvent == null) { + throw new AssertionError("one event is always present"); + } + final Date value = EventAttribute.PT.getValue(selectedEvent); + if (value == null) { + throw new AssertionError("planned time cannot be null"); + } + return value; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopMerger.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopMerger.java new file mode 100644 index 0000000000000..e5ca984b8be64 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStopMerger.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Utility for merging timetable stops. + * This is required, thus first only the plan is returned from the API and afterwards the loaded timetable-stops must be + * merged with the fetched changes. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +final class TimetableStopMerger { + + /** + * Merges the {@link TimetableStop} inplace to the first TimetableStop. + */ + public static void merge(final TimetableStop first, final TimetableStop second) { + mergeStopAttributes(first, second); + } + + /** + * Updates all values from the second {@link TimetableStop} into the first one. + */ + private static void mergeStopAttributes(final TimetableStop first, final TimetableStop second) { + mergeEventAttributes(first.getAr(), second.getAr()); + mergeEventAttributes(first.getDp(), second.getDp()); + } + + /** + * Updates all values from the second Event into the first one. + */ + private static void mergeEventAttributes(@Nullable final Event first, @Nullable final Event second) { + if ((first == null) || (second == null)) { + return; + } + + for (final EventAttribute attribute : EventAttribute.ALL_ATTRIBUTES) { + updateAttribute(attribute, first, second); + } + } + + /** + * Sets the value of the given {@link EventAttribute} from the second Event in the first event, if not + * null. + */ + private static void updateAttribute(final EventAttribute attribute, final Event first, + final Event second) { + final @Nullable VALUE_TYPE value = attribute.getValue(second); + if (value != null) { + attribute.setValue(first, value); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Api.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Api.java new file mode 100644 index 0000000000000..fa5ec52ddda45 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Api.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; + +/** + * Interface for timetables API in V1. + * + * @see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public interface TimetablesV1Api { + + /** + * Requests the timetable with the planned data for the given station and time. + * Calls the "/plan" endpoint of the rest-service. + * + * REST-endpoint documentation: (from + * {@see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData}). + * Returns a Timetable object (see Timetable) that contains planned data for the specified station (evaNo) + * within the hourly time slice given by date (format YYMMDD) and hour (format HH). The data includes stops + * for all trips that arrive or depart within that slice. There is a small overlap between slices since some + * trips arrive in one slice and depart in another. + * + * Planned data does never contain messages. On event level, planned data contains the 'plannned' attributes pt, pp, + * ps and ppth + * while the 'changed' attributes ct, cp, cs and cpth are absent. + * + * Planned data is generated many hours in advance and is static, i.e. it does never change. + * It should be cached by web caches.public interface allows access to information about a station. + * + * @param evaNo The Station EVA-number. + * @param time The time for which the timetable is requested. It will be requested for the given day and hour. + * + * @return The {@link Timetable} containing the planned arrivals and departues. + */ + public abstract Timetable getPlan(String evaNo, Date time) throws IOException; + + /** + * Requests all known changes in the timetable for the given station. + * Calls the "/fchg" endpoint of the rest-service. + * + * REST-endpoint documentation: (from + * {@see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData}). + * Returns a Timetable object (see Timetable) that contains all known changes for the station given by evaNo. + * + * The data includes all known changes from now on until undefinitely into the future. Once changes become obsolete + * (because their trip departs from the station) they are removed from this resource. + * + * Changes may include messages. On event level, they usually contain one or more of the 'changed' attributes ct, + * cp, cs or cpth. + * Changes may also include 'planned' attributes if there is no associated planned data for the change (e.g. an + * unplanned stop or trip). + * + * Full changes are updated every 30s and should be cached for that period by web caches. + * + * @param evaNo The Station EVA-number. + * + * @return The {@link Timetable} containing all known changes for the given station. + */ + public abstract Timetable getFullChanges(String evaNo) throws IOException; + + /** + * Requests the timetable with the planned data for the given station and time. + * Calls the "/plan" endpoint of the rest-service. + * + * REST-endpoint documentation: (from + * {@see https://developer.deutschebahn.com/store/apis/info?name=Timetables&version=v1&provider=DBOpenData}). + * Returns a Timetable object (see Timetable) that contains all recent changes for the station given by evaNo. + * Recent changes are always a subset of the full changes. They may equal full changes but are typically much + * smaller. + * Data includes only those changes that became known within the last 2 minutes. + * + * A client that updates its state in intervals of less than 2 minutes should load full changes initially and then + * proceed to periodically load only the recent changes in order to save bandwidth. + * + * Recent changes are updated every 30s as well and should be cached for that period by web caches. + * + * @param evaNo The Station EVA-number. + * + * @return The {@link Timetable} containing recent changes (from last two minutes) for the given station. + */ + public abstract Timetable getRecentChanges(String evaNo) throws IOException; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiFactory.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiFactory.java new file mode 100644 index 0000000000000..5eaa552029aba --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiFactory.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.net.URISyntaxException; + +import javax.xml.bind.JAXBException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl.HttpCallable; +import org.xml.sax.SAXException; + +/** + * Factory for {@link TimetablesV1Api}. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public interface TimetablesV1ApiFactory { + + /** + * Creates an new instance of the {@link TimetablesV1Api}. + */ + public abstract TimetablesV1Api create(final String authToken, final HttpCallable httpCallable) + throws JAXBException, SAXException, URISyntaxException; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Impl.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Impl.java new file mode 100644 index 0000000000000..e4eccc5370b67 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1Impl.java @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.net.URISyntaxException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.validation.Schema; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.http.HttpHeader; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** + * Default Implementation of {@link TimetablesV1Api}. + * + * @author Sönke Küper - Initial contribution + */ +@NonNullByDefault +public final class TimetablesV1Impl implements TimetablesV1Api { + + /** + * Interface for stubbing HTTP-Calls in jUnit tests. + */ + public interface HttpCallable { + + /** + * Executes the given url with the given httpMethod. + * Furthermore the http.proxyXXX System variables are read and + * set into the {@link org.eclipse.jetty.client.HttpClient}. + * + * @param httpMethod the HTTP method to use + * @param url the url to execute + * @param httpHeaders optional http request headers which has to be sent within request + * @param content the content to be sent to the given url or null if no content should + * be sent. + * @param contentType the content type of the given content + * @param timeout the socket timeout in milliseconds to wait for data + * @return the response body or NULL when the request went wrong + * @throws IOException when the request execution failed, timed out or it was interrupted + */ + public abstract String executeUrl(String httpMethod, String url, Properties httpHeaders, + @Nullable InputStream content, @Nullable String contentType, int timeout) throws IOException; + } + + private static final String PLAN_URL = "https://api.deutschebahn.com/timetables/v1/plan/%evaNo%/%date%/%hour%"; + private static final String FCHG_URL = "https://api.deutschebahn.com/timetables/v1/fchg/%evaNo%"; + private static final String RCHG_URL = "https://api.deutschebahn.com/timetables/v1/rchg/%evaNo%"; + + private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyMMdd"); + private static final SimpleDateFormat HOUR_FORMAT = new SimpleDateFormat("HH"); + + private final String authToken; + private final HttpCallable httpCallable; + + private final Logger logger = LoggerFactory.getLogger(TimetablesV1Impl.class); + private JAXBContext jaxbContext; + // private Schema schema; + + /** + * Creates an new {@link TimetablesV1Impl}. + * + * @param authToken The authentication token for timetable api on developer.deutschebahn.com. + */ + public TimetablesV1Impl(final String authToken, final HttpCallable httpCallable) + throws JAXBException, SAXException, URISyntaxException { + this.authToken = authToken; + this.httpCallable = httpCallable; + + // The results from webservice does not conform to the schema provided. The triplabel-Element (tl) is expected + // to occour as + // last Element within an timetableStop (s) element. But it is the first element when requesting the plan. + // When requesting the changes it is the last element, so the schema can't just be corrected. + // If written to developer support, but got no response yet, so schema validation is disabled at the moment. + + // final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + // final URL schemaURL = getClass().getResource("/xsd/Timetables_REST.xsd"); + // assert schemaURL != null; + // this.schema = schemaFactory.newSchema(schemaURL); + this.jaxbContext = JAXBContext.newInstance(Timetable.class.getPackageName(), Timetable.class.getClassLoader()); + } + + @Override + public Timetable getPlan(final String evaNo, final Date time) throws IOException { + return this.performHttpApiRequest(buildPlanRequestURL(evaNo, time)); + } + + @Override + public Timetable getFullChanges(final String evaNo) throws IOException { + return this.performHttpApiRequest(buildFchgRequestURL(evaNo)); + } + + @Override + public Timetable getRecentChanges(final String evaNo) throws IOException { + return this.performHttpApiRequest(buildRchgRequestURL(evaNo)); + } + + private Timetable performHttpApiRequest(final String url) throws IOException { + this.logger.debug("Performing http request to timetable api with url {}", url); + + String response; + try { + response = this.httpCallable.executeUrl( // + "GET", // + url, // + this.createHeaders(), // + null, // + null, // + REQUEST_TIMEOUT_MS); + return this.mapResponseToTimetable(response); + } catch (IOException e) { + logger.debug("Error getting data from webservice.", e); + throw e; + } + } + + /** + * Parses and creates the {@link Timetable} from the response or + * returns an empty {@link Timetable} if response was empty. + */ + private Timetable mapResponseToTimetable(final String response) throws IOException { + if (response.isEmpty()) { + return new Timetable(); + } + + try { + return unmarshal(response, Timetable.class); + } catch (JAXBException | SAXException e) { + this.logger.error("Error parsing response from timetable api.", e); + throw new IOException(e); + } + } + + /** + * Creates the HTTP-Headers required for http requests. + */ + private Properties createHeaders() { + final Properties headers = new Properties(); + headers.put(HttpHeader.ACCEPT.asString(), "application/xml"); + headers.put(HttpHeader.AUTHORIZATION.asString(), "Bearer " + this.authToken); + return headers; + } + + private T unmarshal(final String xmlContent, final Class clazz) throws JAXBException, SAXException { + return unmarshal( // + jaxbContext, // + null, // Provide no schema, due webservice results are not schema-valid. + xmlContent, // + clazz // + ); + } + + @SuppressWarnings("unchecked") + private static T unmarshal(final JAXBContext jaxbContext, @Nullable final Schema schema, + final String xmlContent, final Class clss) throws JAXBException { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setSchema(schema); + final JAXBElement resultObject = (JAXBElement) unmarshaller.unmarshal(new StringReader(xmlContent)); + return resultObject.getValue(); + } + + /** + * Build rest endpoint URL for request the planned timetable. + */ + private String buildPlanRequestURL(final String evaNr, final Date date) { + synchronized (this) { + final String dateParam = DATE_FORMAT.format(date); + final String hourParam = HOUR_FORMAT.format(date); + + return PLAN_URL // + .replace("%evaNo%", evaNr) // + .replace("%date%", dateParam) // + .replace("%hour%", hourParam); + } + } + + /** + * Build rest endpoint URL for request all known changes in the timetable. + */ + private static String buildFchgRequestURL(final String evaNr) { + return FCHG_URL.replace("%evaNo%", evaNr); + } + + /** + * Build rest endpoint URL for request all known changes in the timetable. + */ + private static String buildRchgRequestURL(final String evaNr) { + return RCHG_URL.replace("%evaNo%", evaNr); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..7deb3797ee87c --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + Deutsche Bahn Binding + This binding provides timetable information for train stations of Deutsche Bahn. + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn_de.properties b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn_de.properties new file mode 100644 index 0000000000000..80181986adecd --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn_de.properties @@ -0,0 +1,85 @@ +# binding +binding.deutschebahn.name = DeutscheBahn +binding.deutschebahn.description = Anbindung an die OpenData Schnittstelle der DeutschenBahn fr den Abruf von Fahrplaninformationen. + +# thing type timetable +thing-type.deutschebahn.timetable.label = DeutscheBahn Fahrplan +thing-type.deutschebahn.timetable.description = Verbindung zur Webserivce-API der DeutschenBahn fr den Abruf des Fahrplans. Die bereitgestellten Daten knnen dann ber ein Thing "Zug" dargestellt werden. + +# thing type timetable config description +thing-type.config.deutschebahn.timetable.accessToken.label = Zugriffsschlssel +thing-type.config.deutschebahn.timetable.accessToken.description = Zugriffsschlssel fr die Timetable V1 API aus dem Developer-Portal der DeutschenBahn. +thing-type.config.deutschebahn.timetable.evaNo.label = eva Nr des Bahnhofs +thing-type.config.deutschebahn.timetable.evaNo.description = evaNr des Bahnhofs, fr den der Fahrplan abgerufen wird. Siehe https://data.deutschebahn.com/dataset.tags.EVA-Nr..html. +thing-type.config.deutschebahn.timetable.trainFilter.label = Zugfilter +thing-type.config.deutschebahn.timetable.trainFilter.description = Selektiert die Zge (Anknfte / Abfahrten), die in dem Fahrplan enthalten sein sollen. Wenn nicht angegeben werden nur die Abfahrten angezeigt. + +# thing type train +thing-type.deutschebahn.train.label = Zug +thing-type.deutschebahn.train.description = Stellt einen Zug im Fahrplan dar, der an dem konfigurierten Bahnhof ankommt oder abfhrt. +thing-type.deutschebahn.train.group.trip.label = Fahrtinformationen +thing-type.deutschebahn.train.group.trip.description = Enthlt alle Informationen ber die Fahrt des Zuges. +thing-type.deutschebahn.train.group.arrival.label = Ankunft +thing-type.deutschebahn.train.group.arrival.description = Enthlt alle Informationen ber die Ankunft des Zuges. +thing-type.deutschebahn.train.group.departure.label = Abfahrt +thing-type.deutschebahn.train.group.departure.description = Enthlt alle Informationen ber die Abfahrt des Zuges. + +# thing type train config description +thing-type.config.deutschebahn.train.position.label = Position +thing-type.config.deutschebahn.train.position.description = Gibt die Position des Zuges im Fahrplan an. z.B. wird mit 1 der erste Zug im Fahrplan selektiert, mit 2 der Zweite usw. + +# trip information channel types +channel-type.deutschebahn.category.label = Kateogrie +channel-type.deutschebahn.category.description = Die Kategorie des Zuges, z.B. "ICE" oder "RE". +channel-type.deutschebahn.number.label = Zugnummer +channel-type.deutschebahn.number.description = Die Zugnummer, z.B. "4523". +channel-type.deutschebahn.filter-flags.label = Filter +channel-type.deutschebahn.filter-flags.description = Filter fr die Fahrt. +channel-type.deutschebahn.trip-type.label = Fahrttyp +channel-type.deutschebahn.trip-type.description = Gibt den Typ der Fahrt an. +channel-type.deutschebahn.owner.label = Eigentmer +channel-type.deutschebahn.owner.description = Gibt die eindeutige Kurzbezeichnung des EisenbahnVerkehrsUnternehmen des Zuges an. + +# event channel types +channel-type.deutschebahn.planned-path.label = Geplante Route +channel-type.deutschebahn.planned-path.description = Gibt die geplante Route des Zuges an, dabei werden die Stationen mit | getrennt aufgelistet. Fr Anknfte besteht der Pfad aus den Halten, die vor der aktuellen Station kamen, das erste Element ist der Startbahnhof. Fr Abfahrten werden die Stationen aufgelistet, die nach der aktuellen Station kommen. Das letzte Element ist der Zielbahnhof. +channel-type.deutschebahn.changed-path.label = Gendert Route +channel-type.deutschebahn.changed-path.description = Gibt die genderte Route des Zuges an, dabei werden die Stationen mit | getrennt aufgelistet. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.planned-platform.label = Geplantes Gleis +channel-type.deutschebahn.planned-platform.description = Gibt das geplante Gleis an, auf dem der Zug ankommt/abfhrt. +channel-type.deutschebahn.changed-platform.label = Gendertes Gleis +channel-type.deutschebahn.changed-platform.description = Gibt das gendert Gleis an, auf dem der Zug ankommt/abfhrt. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.planned-time.label = Geplante Zeit +channel-type.deutschebahn.planned-time.description = Gibt die geplante Zeit fr die Ankunft/Abfahrt des Zuges an. +channel-type.deutschebahn.changed-time.label = Genderte Zeit +channel-type.deutschebahn.changed-time.description = Gibt die gender Zeit fr die Ankunft/Abfahrt des Zuges an. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.planned-status.label = Geplanter Status +channel-type.deutschebahn.planned-status.description = Gibt den Stauts des Fahrplaneintrags an. +channel-type.deutschebahn.changed-status.label = Genderter Status +channel-type.deutschebahn.changed-status.description = Gibt den genderten Status des Fahrplaneintrags an. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.cancellation-time.label = Stornierungs-Zeitpunkt +channel-type.deutschebahn.cancellation-time.description = Gibt den Zeitpunkt an, an dem der Halt storniert wurde. +channel-type.deutschebahn.line.label = Linie +channel-type.deutschebahn.line.description = Gibt die Linie des Zuges an. +channel-type.deutschebahn.messages.label = Meldungen +channel-type.deutschebahn.messages.description = Textmeldungen, die fr diese Ankunft/Abfahrt des Zuges vorliegen. Mehrere Meldungen werden mit einem Strich getrennt ausgegeben. +channel-type.deutschebahn.hidden.label = Versteckt +channel-type.deutschebahn.hidden.description = Gibt an, ob die Ankunft/Abfahrt im Fahrplan nicht angezeigt werden soll, da ein Ein-/Aussteigen nicht mglich ist. +channel-type.deutschebahn.wings.label = Wing +channel-type.deutschebahn.wings.description = Gibt eine Folge | separierten "Trip-IDs"an. +channel-type.deutschebahn.transition.label = bergang +channel-type.deutschebahn.transition.description = Gibt bei Zgen, die zusmmengefhrt oder getrennt werden die Trip-ID des vorherigen oder nachfolgenden Zuges an. +channel-type.deutschebahn.planned-distant-endpoint.label = Geplanter entfernter Endpunkt +channel-type.deutschebahn.planned-distant-endpoint.description = Gibt den geplanten entfernten Endpunkt des Zuges an. +channel-type.deutschebahn.changed-distant-endpoint.label = Genderter entfernter Endpunkt +channel-type.deutschebahn.changed-distant-endpoint.description = Gibt den genderten entfernten Endpunkt des Zuges an. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.distant-change.label = Genderter Zielbahnhof +channel-type.deutschebahn.distant-change.description = Gibt den genderten Zielbahnhof des Zuges an. +channel-type.deutschebahn.planned-final-station.label = Geplanter Start-/Zielbahnhof +channel-type.deutschebahn.planned-final-station.description = Gibt den geplanten Startbahnhof (fr Anknfte) bzw. Zielbahnhof (fr Abfahrten) an. +channel-type.deutschebahn.planned-intermediate-stations.label = Geplante Halte +channel-type.deutschebahn.planned-intermediate-stations.description = Gibt die geplanten Halte des Zuges auf dem Weg zum aktuellen Bahnhof an (fr Anknfte) bzw. die folgenden Halte (fr Abfahrten). +channel-type.deutschebahn.changed-final-station.label = Genderter Start-/Zielbahnhof +channel-type.deutschebahn.changed-final-station.description = Gibt den genderten Startbahnhof (fr Anknfte) bzw. Zielbahnhof (fr Abfahrten) an. Ist nicht gesetzt, falls keine nderungen vorliegen. +channel-type.deutschebahn.changed-intermediate-stations.label = Genderte Halte +channel-type.deutschebahn.changed-intermediate-stations.description = Gibt die genderten Halte des Zuges auf dem Weg zum aktuellen Bahnhof an (fr Anknfte) bzw. die folgenden Halte (fr Abfahrten). Ist nicht gesetzt, falls keine nderungen vorliegen. diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..d85a7c028ebac --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,342 @@ + + + + + + + Connection to the timetable API of Deutsche Bahn. Provides timetable data that can be displayed using the + train things. + + + + + Access Token from Deutsche Bahn developer portal for accessing the webservice api. + + + + evaNo of the station, for which the timetable should be requested. see + https://data.deutschebahn.com/dataset.tags.EVA-Nr..html + + + true + departures + + Selects the trains that will be be displayed in this timetable. If not set only departures will be + provided. + + + + + + + + + + + + + + + Displays informations about an train within the given timetable at one station. + + + + Contains all informations about the trip of the train. + + + + + Contains all informations about the arrival of the train at the station. + Channels may be empty, if the + trains starts at this station. + + + + + Contains all informations about the departure of the train at the station. + Channels may be empty, if the + trains ends at this station. + + + + + + + Selects the position of the train in the timetable. + + + + + + + Contains all informations about the trip of the train. + + + + + + + + + + + + Contains all attributes for an event (arrival / departure) of an train at the station. + + + + + + + + + + + + + + + + + + + + + + + + + + + + String + + Provides the category of the trip, e.g. "ICE" or "RE". + + + + + String + + Provides the trip/train number, e.g. "4523". + + + + + String + + Provides the filter flags. + + + + + String + + Provides the type of the trip. + + + + + + + + String + + Provides the owner of the train. A unique short-form and only intended to map a trip to specific evu + (EisenbahnVerkehrsUnternehmen). + + + + + + String + + Provides the planned platform of a train. + + + + + String + + Provides the changed platform of a train. + + + + + DateTime + + Provides the planned time of a train. + + + + + DateTime + + Provides the changed time of a train. + + + + + String + + Provides the planned status of a train. + + + + + + + + + + + String + + Provides the changed status of a train. + + + + + + + + + + + String + + The line indicator. + + + + + String + + Messages for this train. Contains all translated codes from the messages of the selected train stop. + Multiple messages will be separated with an single dash. + + + + + + DateTime + + Time when the cancellation of this stop was created. + + + + + String + + Provides the planned path of a train. + For arrival, the path indicates the stations that come before the + current station. The first element then is the trip’s + start station. For departure, the path indicates the stations + that come after the current station. The last ele-ment + in the path then is the trip’s destination station. Note that + the current station is never included in the path + (neither for arrival nor for departure). + + + + + String + + Provides the planned path of a train. + For arrival, the path indicates the stations that come before the + current station. The first element then is the trip’s + start station. For departure, the path indicates the stations + that come after the current station. The last ele-ment + in the path then is the trip’s destination station. Note that + the current station is never included in the path + (neither for arrival nor for departure). + + + + + Switch + + On if the event should not be shown, because travellers are not supposed to enter or exit the train + at + this stop. + + + + + String + + A sequence of trip id separated by the pipe symbols (“|”). + + + + + String + + Trip id of the next or previous train of a shared train. At the start stop this references the previous + trip, at the last stop it references the next trip. + + + + + String + + Planned distant endpoint. + + + + + String + + Changed distant endpoint. + + + + + Number + + distant change + + + + + + String + + Planned final station of the train. For arrivals the starting station is returned, for departures the + target station is returned. + + + + String + + Returns the planned stations this train came from (for arrivals) or the stations this train will go to + (for departures). Stations will be separated by single dash. + + + + + String + + Changed final station of the train. For arrivals the starting station is returned, for departures the + target station is returned. + + + + + String + + Returns the changed stations this train came from (for arrivals) or the stations this train will go to + (for departures). Stations will be separated by single dash. + + + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/xsd/Timetables_REST.xsd b/bundles/org.openhab.binding.deutschebahn/src/main/resources/xsd/Timetables_REST.xsd new file mode 100644 index 0000000000000..c0091341a79be --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/xsd/Timetables_REST.xsd @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandlerTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandlerTest.java new file mode 100644 index 0000000000000..5209ad9d283e9 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandlerTest.java @@ -0,0 +1,187 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.timetable.TimeproviderStub; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1ApiFactory; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1ApiStub; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl.HttpCallable; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1ImplTestHelper; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandlerCallback; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * Tests for {@link DeutscheBahnTimetableHandler}. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public class DeutscheBahnTimetableHandlerTest implements TimetablesV1ImplTestHelper { + + private static Configuration createConfig() { + final Configuration config = new Configuration(); + config.put("accessToken", "letMeIn"); + config.put("evaNo", "8000226"); + config.put("trainFilter", "all"); + return config; + } + + private static Bridge mockBridge() { + final Bridge bridge = mock(Bridge.class); + when(bridge.getUID()).thenReturn(new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable")); + when(bridge.getConfiguration()).thenReturn(createConfig()); + + final List things = new ArrayList<>(); + things.add(DeutscheBahnTrainHandlerTest.mockThing(1)); + things.add(DeutscheBahnTrainHandlerTest.mockThing(2)); + things.add(DeutscheBahnTrainHandlerTest.mockThing(3)); + when(things.get(0).getHandler()).thenReturn(mock(DeutscheBahnTrainHandler.class)); + when(things.get(1).getHandler()).thenReturn(mock(DeutscheBahnTrainHandler.class)); + when(things.get(2).getHandler()).thenReturn(mock(DeutscheBahnTrainHandler.class)); + + when(bridge.getThings()).thenReturn(things); + + return bridge; + } + + private DeutscheBahnTimetableHandler createAndInitHandler(final ThingHandlerCallback callback, final Bridge bridge) + throws Exception { + return createAndInitHandler(callback, bridge, createApiWithTestdata().getApiFactory()); + } + + private DeutscheBahnTimetableHandler createAndInitHandler( // + final ThingHandlerCallback callback, // + final Bridge bridge, // + final TimetablesV1ApiFactory apiFactory) throws Exception { // + final TimeproviderStub timeProvider = new TimeproviderStub(); + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 30); + + final DeutscheBahnTimetableHandler handler = new DeutscheBahnTimetableHandler(bridge, apiFactory, timeProvider); + handler.setCallback(callback); + handler.initialize(); + return handler; + } + + @Test + public void testUpdateChannels() throws Exception { + final Bridge bridge = mockBridge(); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + + final DeutscheBahnTimetableHandler handler = createAndInitHandler(callback, bridge); + + try { + verify(callback).statusUpdated(eq(bridge), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(bridge), + argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); + + verifyThingUpdated(bridge, 0, "-5296516961807204721-2108160906-5"); + verifyThingUpdated(bridge, 1, "-8364795265993682073-2108160911-6"); + verifyThingUpdated(bridge, 2, "-2949440726131702047-2108160858-10"); + } finally { + handler.dispose(); + } + } + + private void verifyThingUpdated(final Bridge bridge, int offset, String stopId) { + final Thing train = bridge.getThings().get(offset); + final DeutscheBahnTrainHandler childHandler = (DeutscheBahnTrainHandler) train.getHandler(); + verify(childHandler, timeout(1000)) + .updateChannels(argThat((TimetableStop stop) -> stop.getId().equals(stopId))); + } + + @Test + public void testUpdateTrainsToUndefinedIfNoDataWasProvided() throws Exception { + final Bridge bridge = mockBridge(); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + + final TimetablesV1ApiStub stubWithError = TimetablesV1ApiStub.createWithException(); + + final DeutscheBahnTimetableHandler handler = createAndInitHandler(callback, bridge, + (String authToken, HttpCallable httpCallable) -> stubWithError); + + try { + verify(callback).statusUpdated(eq(bridge), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(bridge), + argThat(arg -> arg.getStatus().equals(ThingStatus.OFFLINE))); + + verifyChannelsUpdatedToUndef(bridge, 0, callback, UnDefType.UNDEF); + verifyChannelsUpdatedToUndef(bridge, 1, callback, UnDefType.UNDEF); + verifyChannelsUpdatedToUndef(bridge, 2, callback, UnDefType.UNDEF); + + } finally { + handler.dispose(); + } + } + + private static void verifyChannelsUpdatedToUndef(Bridge bridge, int offset, ThingHandlerCallback callback, + State expectedState) { + final Thing thing = bridge.getThings().get(offset); + for (Channel channel : thing.getChannels()) { + verify(callback).stateUpdated(eq(channel.getUID()), eq(expectedState)); + } + } + + @Test + public void testUpdateTrainsToUndefinedIfNotEnoughDataWasProvided() throws Exception { + final Bridge bridge = mockBridge(); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + + // Bridge contains 3 trains, but Timetable contains only 1 items, so two trains has to be updated to undef + // value. + final Timetable timetable = new Timetable(); + TimetableStop stop01 = new TimetableStop(); + stop01.setId("stop01id"); + Event dp = new Event(); + dp.setPt("2108161000"); + stop01.setDp(dp); + timetable.getS().add(stop01); + + final TimetablesV1ApiStub stubWithData = TimetablesV1ApiStub.createWithResult(timetable); + + final DeutscheBahnTimetableHandler handler = createAndInitHandler(callback, bridge, + (String authToken, HttpCallable httpCallable) -> stubWithData); + + try { + verify(callback).statusUpdated(eq(bridge), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(bridge), + argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); + + verifyThingUpdated(bridge, 0, stop01.getId()); + verifyChannelsUpdatedToUndef(bridge, 1, callback, UnDefType.UNDEF); + verifyChannelsUpdatedToUndef(bridge, 2, callback, UnDefType.UNDEF); + + } finally { + handler.dispose(); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandlerTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandlerTest.java new file mode 100644 index 0000000000000..627e53d3f5f3d --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTrainHandlerTest.java @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandlerCallback; +import org.openhab.core.thing.internal.BridgeImpl; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * Tests for {@link DeutscheBahnTrainHandler}. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public class DeutscheBahnTrainHandlerTest { + + private static final String SAMPLE_PATH = "Bielefeld Hbf|Herford|Löhne(Westf)|Bad Oeynhausen|Porta Westfalica|Minden(Westf)|Bückeburg|Stadthagen|Haste|Wunstorf|Hannover Hbf|Lehrte"; + + private static Configuration createConfig(int position) { + final Configuration config = new Configuration(); + config.put("position", String.valueOf(position)); + return config; + } + + static Thing mockThing(int id) { + final Thing thing = mock(Thing.class); + when(thing.getUID()).thenReturn(new ThingUID(DeutscheBahnBindingConstants.TRAIN_TYPE, "train-" + id)); + when(thing.getThingTypeUID()).thenReturn(DeutscheBahnBindingConstants.TRAIN_TYPE); + when(thing.getConfiguration()).thenReturn(createConfig(id)); + ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable"); + when(thing.getBridgeUID()).thenReturn(bridgeId); + + final Channel tripLabelCategory = mockChannel(thing.getUID(), "trip#category"); + + final Channel arrivalPlannedTime = mockChannel(thing.getUID(), "arrival#planned-time"); + final Channel arrivalLine = mockChannel(thing.getUID(), "arrival#line"); + final Channel arrivalChangedTime = mockChannel(thing.getUID(), "arrival#changed-time"); + + final Channel departurePlannedTime = mockChannel(thing.getUID(), "departure#planned-time"); + final Channel departurePlannedPlatform = mockChannel(thing.getUID(), "departure#planned-platform"); + final Channel departureTargetStation = mockChannel(thing.getUID(), "departure#planned-final-station"); + + when(thing.getChannelsOfGroup("trip")).thenReturn(Arrays.asList(tripLabelCategory)); + when(thing.getChannelsOfGroup("arrival")) + .thenReturn(Arrays.asList(arrivalPlannedTime, arrivalLine, arrivalChangedTime)); + when(thing.getChannelsOfGroup("departure")) + .thenReturn(Arrays.asList(departurePlannedTime, departurePlannedPlatform, departureTargetStation)); + when(thing.getChannels()).thenReturn(Arrays.asList( // + tripLabelCategory, // + arrivalPlannedTime, arrivalLine, arrivalChangedTime, // + departurePlannedTime, departurePlannedPlatform, departureTargetStation)); + + return thing; + } + + private static Channel mockChannel(final ThingUID thingId, final String channelId) { + final Channel channel = Mockito.mock(Channel.class); + when(channel.getUID()).thenReturn(new ChannelUID(thingId, channelId)); + return channel; + } + + private static DeutscheBahnTrainHandler createAndInitHandler(final ThingHandlerCallback callback, + final Thing thing) { + final DeutscheBahnTrainHandler handler = new DeutscheBahnTrainHandler(thing); + handler.setCallback(callback); + handler.initialize(); + return handler; + } + + private static State getDateTime(final Date day) { + final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(day.toInstant(), ZoneId.systemDefault()); + return new DateTimeType(zonedDateTime); + } + + @Test + public void testUpdateChannels() { + final Thing thing = mockThing(1); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable"); + when(callback.getBridge(bridgeId)) + .thenReturn(new BridgeImpl(DeutscheBahnBindingConstants.TIMETABLE_TYPE, bridgeId)); + final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing); + + try { + verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(thing), + argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); + + // Provide data that will update the channels + TimetableStop stop = new TimetableStop(); + + TripLabel label = new TripLabel(); + label.setC("WFB"); + stop.setTl(label); + + Event arrival = new Event(); + arrival.setPt("2108161434"); + arrival.setL("RE60"); + stop.setAr(arrival); + Event departure = new Event(); + departure.setPt("2108161435"); + departure.setPp("2"); + departure.setPpth(SAMPLE_PATH); + stop.setDp(departure); + + handler.updateChannels(stop); + + final Date arrivalTime = new GregorianCalendar(2021, 7, 16, 14, 34).getTime(); + final Date departureTime = new GregorianCalendar(2021, 7, 16, 14, 35).getTime(); + + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "trip#category"), + new StringType("WFB")); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#planned-time"), + getDateTime(arrivalTime)); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#line"), + new StringType("RE60")); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#changed-time"), + UnDefType.NULL); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-time"), + getDateTime(departureTime)); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-platform"), + new StringType("2")); + verify(callback, timeout(1000)).stateUpdated( + new ChannelUID(thing.getUID(), "departure#planned-final-station"), new StringType("Lehrte")); + } finally { + handler.dispose(); + } + } + + @Test + public void testUpdateChannelsWithEventNotPresent() { + final Thing thing = mockThing(1); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + ThingUID bridgeId = new ThingUID(DeutscheBahnBindingConstants.TIMETABLE_TYPE, "timetable"); + when(callback.getBridge(bridgeId)) + .thenReturn(new BridgeImpl(DeutscheBahnBindingConstants.TIMETABLE_TYPE, bridgeId)); + final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing); + + try { + verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(thing), + argThat(arg -> arg.getStatus().equals(ThingStatus.ONLINE))); + + // Provide data that will update the channels + TimetableStop stop = new TimetableStop(); + + Event arrival = new Event(); + arrival.setPt("2108161434"); + arrival.setL("RE60"); + stop.setAr(arrival); + + handler.updateChannels(stop); + + final Date arrivalTime = new GregorianCalendar(2021, 7, 16, 14, 34).getTime(); + + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "trip#category"), + UnDefType.UNDEF); + + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#planned-time"), + getDateTime(arrivalTime)); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#line"), + new StringType("RE60")); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "arrival#changed-time"), + UnDefType.NULL); + + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-time"), + UnDefType.UNDEF); + verify(callback, timeout(1000)).stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-platform"), + UnDefType.UNDEF); + verify(callback, timeout(1000)) + .stateUpdated(new ChannelUID(thing.getUID(), "departure#planned-final-station"), UnDefType.UNDEF); + } finally { + handler.dispose(); + } + } + + @Test + public void testWithoutBridgeStateUpdatesToOffline() { + final Thing thing = mockThing(1); + final ThingHandlerCallback callback = mock(ThingHandlerCallback.class); + final DeutscheBahnTrainHandler handler = createAndInitHandler(callback, thing); + + try { + verify(callback).statusUpdated(eq(thing), argThat(arg -> arg.getStatus().equals(ThingStatus.UNKNOWN))); + verify(callback, timeout(1000)).statusUpdated(eq(thing), + argThat(arg -> arg.getStatus().equals(ThingStatus.OFFLINE))); + } finally { + handler.dispose(); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java new file mode 100644 index 0000000000000..1f11a0891b56c --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.function.Consumer; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.EventStatus; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Message; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; + +/** + * Tests Mapping from {@link Event} attribute values to openhab state values. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +@SuppressWarnings("unchecked") +public class EventAttributeTest { + + private static final String SAMPLE_PATH = "Bielefeld Hbf|Herford|Löhne(Westf)|Bad Oeynhausen|Porta Westfalica|Minden(Westf)|Bückeburg|Stadthagen|Haste|Wunstorf|Hannover Hbf|Lehrte"; + + private void doTestEventAttribute( // + String channelName, // + @Nullable String expectedChannelName, // + Consumer setValue, // + VALUE_TYPE expectedValue, // + @Nullable STATE_TYPE expectedState, // + EventType eventType, // + boolean performSetterTest) { // + final EventAttribute attribute = (EventAttribute) EventAttribute + .getByChannelName(channelName, eventType); + assertThat(attribute, is(not(nullValue()))); + assertThat(attribute.getChannelTypeName(), is(expectedChannelName == null ? channelName : expectedChannelName)); + assertThat(attribute.getValue(new Event()), is(nullValue())); + assertThat(attribute.getState(new Event()), is(nullValue())); + + // Create an event and set the attribute value. + final Event eventWithValueSet = new Event(); + setValue.accept(eventWithValueSet); + + // then try get value and state. + assertThat(attribute.getValue(eventWithValueSet), is(expectedValue)); + assertThat(attribute.getState(eventWithValueSet), is(expectedState)); + + // Try set Value in new Event + final Event copyTarget = new Event(); + attribute.setValue(copyTarget, expectedValue); + if (performSetterTest) { + assertThat(attribute.getValue(copyTarget), is(expectedValue)); + } + } + + @Test + public void testGetNonExistingChannel() { + assertThat(EventAttribute.getByChannelName("unkownChannel", EventType.ARRIVAL), is(nullValue())); + } + + @Test + public void testPlannedPath() { + doTestEventAttribute("planned-path", null, (Event e) -> e.setPpth(SAMPLE_PATH), SAMPLE_PATH, + new StringType(SAMPLE_PATH), EventType.DEPARTURE, true); + } + + @Test + public void testChangedPath() { + doTestEventAttribute("changed-path", null, (Event e) -> e.setCpth(SAMPLE_PATH), SAMPLE_PATH, + new StringType(SAMPLE_PATH), EventType.DEPARTURE, true); + } + + @Test + public void testPlannedPlatform() { + String platform = "2"; + doTestEventAttribute("planned-platform", null, (Event e) -> e.setPp(platform), platform, + new StringType(platform), EventType.DEPARTURE, true); + } + + @Test + public void testChangedPlatform() { + String platform = "2"; + doTestEventAttribute("changed-platform", null, (Event e) -> e.setCp(platform), platform, + new StringType(platform), EventType.DEPARTURE, true); + } + + @Test + public void testWings() { + String wings = "-906407760000782942-1403311431"; + doTestEventAttribute("wings", null, (Event e) -> e.setWings(wings), wings, new StringType(wings), + EventType.DEPARTURE, true); + } + + @Test + public void testTransition() { + String transition = "2016448009055686515-1403311438-1"; + doTestEventAttribute("transition", null, (Event e) -> e.setTra(transition), transition, + new StringType(transition), EventType.DEPARTURE, true); + } + + @Test + public void testPlannedDistantEndpoint() { + String endpoint = "Hannover Hbf"; + doTestEventAttribute("planned-distant-endpoint", null, (Event e) -> e.setPde(endpoint), endpoint, + new StringType(endpoint), EventType.DEPARTURE, true); + } + + @Test + public void testChangedDistantEndpoint() { + String endpoint = "Hannover Hbf"; + doTestEventAttribute("changed-distant-endpoint", null, (Event e) -> e.setCde(endpoint), endpoint, + new StringType(endpoint), EventType.DEPARTURE, true); + } + + @Test + public void testLine() { + String line = "RE60"; + doTestEventAttribute("line", null, (Event e) -> e.setL(line), line, new StringType(line), EventType.DEPARTURE, + true); + } + + @Test + public void testPlannedTime() { + String time = "2109111825"; + GregorianCalendar expectedValue = new GregorianCalendar(2021, 8, 11, 18, 25, 0); + DateTimeType expectedState = new DateTimeType( + ZonedDateTime.ofInstant(expectedValue.toInstant(), ZoneId.systemDefault())); + doTestEventAttribute("planned-time", null, (Event e) -> e.setPt(time), expectedValue.getTime(), expectedState, + EventType.DEPARTURE, true); + } + + @Test + public void testChangedTime() { + String time = "2109111825"; + GregorianCalendar expectedValue = new GregorianCalendar(2021, 8, 11, 18, 25, 0); + DateTimeType expectedState = new DateTimeType( + ZonedDateTime.ofInstant(expectedValue.toInstant(), ZoneId.systemDefault())); + doTestEventAttribute("changed-time", null, (Event e) -> e.setCt(time), expectedValue.getTime(), expectedState, + EventType.DEPARTURE, true); + } + + @Test + public void testCancellationTime() { + String time = "2109111825"; + GregorianCalendar expectedValue = new GregorianCalendar(2021, 8, 11, 18, 25, 0); + DateTimeType expectedState = new DateTimeType( + ZonedDateTime.ofInstant(expectedValue.toInstant(), ZoneId.systemDefault())); + doTestEventAttribute("cancellation-time", null, (Event e) -> e.setClt(time), expectedValue.getTime(), + expectedState, EventType.DEPARTURE, true); + } + + @Test + public void testPlannedStatus() { + EventStatus expectedValue = EventStatus.A; + doTestEventAttribute("planned-status", null, (Event e) -> e.setPs(expectedValue), expectedValue, + new StringType(expectedValue.name().toLowerCase()), EventType.DEPARTURE, true); + } + + @Test + public void testChangedStatus() { + EventStatus expectedValue = EventStatus.C; + doTestEventAttribute("changed-status", null, (Event e) -> e.setCs(expectedValue), expectedValue, + new StringType(expectedValue.name().toLowerCase()), EventType.DEPARTURE, true); + } + + @Test + public void testHidden() { + doTestEventAttribute("hidden", null, (Event e) -> e.setHi(0), 0, OnOffType.OFF, EventType.DEPARTURE, true); + doTestEventAttribute("hidden", null, (Event e) -> e.setHi(1), 1, OnOffType.ON, EventType.DEPARTURE, true); + } + + @Test + public void testDistantChange() { + doTestEventAttribute("distant-change", null, (Event e) -> e.setDc(42), 42, new DecimalType(42), + EventType.DEPARTURE, true); + } + + @Test + public void testPlannedFinalStation() { + doTestEventAttribute("planned-final-station", "planned-target-station", (Event e) -> e.setPpth(SAMPLE_PATH), + "Lehrte", new StringType("Lehrte"), EventType.DEPARTURE, false); + doTestEventAttribute("planned-final-station", "planned-start-station", (Event e) -> e.setPpth(SAMPLE_PATH), + "Bielefeld Hbf", new StringType("Bielefeld Hbf"), EventType.ARRIVAL, false); + } + + @Test + public void testChangedFinalStation() { + doTestEventAttribute("changed-final-station", "changed-target-station", (Event e) -> e.setCpth(SAMPLE_PATH), + "Lehrte", new StringType("Lehrte"), EventType.DEPARTURE, false); + doTestEventAttribute("changed-final-station", "changed-start-station", (Event e) -> e.setCpth(SAMPLE_PATH), + "Bielefeld Hbf", new StringType("Bielefeld Hbf"), EventType.ARRIVAL, false); + } + + @Test + public void testPlannedIntermediateStations() { + String expectedFollowing = "Bielefeld Hbf - Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf"; + doTestEventAttribute("planned-intermediate-stations", "planned-following-stations", + (Event e) -> e.setPpth(SAMPLE_PATH), expectedFollowing, new StringType(expectedFollowing), + EventType.DEPARTURE, false); + String expectedPrevious = "Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf - Lehrte"; + doTestEventAttribute("planned-intermediate-stations", "planned-previous-stations", + (Event e) -> e.setPpth(SAMPLE_PATH), expectedPrevious, new StringType(expectedPrevious), + EventType.ARRIVAL, false); + } + + @Test + public void testChangedIntermediateStations() { + String expectedFollowing = "Bielefeld Hbf - Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf"; + doTestEventAttribute("changed-intermediate-stations", "changed-following-stations", + (Event e) -> e.setCpth(SAMPLE_PATH), expectedFollowing, new StringType(expectedFollowing), + EventType.DEPARTURE, false); + String expectedPrevious = "Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf - Lehrte"; + doTestEventAttribute("changed-intermediate-stations", "changed-previous-stations", + (Event e) -> e.setCpth(SAMPLE_PATH), expectedPrevious, new StringType(expectedPrevious), + EventType.ARRIVAL, false); + } + + @Test + public void testMessages() { + String expectedOneMessage = "Verzögerungen im Betriebsablauf"; + List messages = new ArrayList<>(); + Message m1 = new Message(); + m1.setC(99); + messages.add(m1); + doTestEventAttribute("messages", null, (Event e) -> e.getM().addAll(messages), messages, + new StringType(expectedOneMessage), EventType.DEPARTURE, true); + + String expectedTwoMessages = "Verzögerungen im Betriebsablauf - keine Qualitätsmängel"; + Message m2 = new Message(); + m2.setC(88); + messages.add(m2); + doTestEventAttribute("messages", null, (Event e) -> e.getM().addAll(messages), messages, + new StringType(expectedTwoMessages), EventType.DEPARTURE, true); + } + + @Test + public void testFilterDuplicateMessages() { + String expectedOneMessage = "andere Reihenfolge der Wagen - technische Störung am Zug - Zug verkehrt richtig gereiht"; + List messages = new ArrayList<>(); + Message m1 = new Message(); + m1.setC(80); + messages.add(m1); + Message m2 = new Message(); + m2.setC(80); + messages.add(m2); + Message m3 = new Message(); + m3.setC(36); + messages.add(m3); + Message m4 = new Message(); + m4.setC(80); + messages.add(m4); + Message m5 = new Message(); + m5.setC(84); + messages.add(m5); + + doTestEventAttribute("messages", null, (Event e) -> e.getM().addAll(messages), messages, + new StringType(expectedOneMessage), EventType.DEPARTURE, true); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/TripLabelAttributeTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/TripLabelAttributeTest.java new file mode 100644 index 0000000000000..191378a57b3bf --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/TripLabelAttributeTest.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import java.util.function.Consumer; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; + +/** + * Tests Mapping from {@link TripLabel} attribute values to openhab state values. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +@SuppressWarnings("unchecked") +public class TripLabelAttributeTest { + + private void doTestTripAttribute( // + String channelName, // + @Nullable String expectedChannelName, // + Consumer setValue, // + VALUE_TYPE expectedValue, // + @Nullable STATE_TYPE expectedState, // + boolean performSetterTest) { // + final TripLabelAttribute attribute = (TripLabelAttribute) TripLabelAttribute + .getByChannelName(channelName); + assertThat(attribute, is(not(nullValue()))); + assertThat(attribute.getChannelTypeName(), is(expectedChannelName == null ? channelName : expectedChannelName)); + assertThat(attribute.getValue(new TripLabel()), is(nullValue())); + assertThat(attribute.getState(new TripLabel()), is(nullValue())); + + // Create an trip label and set the attribute value. + final TripLabel labelWithValueSet = new TripLabel(); + setValue.accept(labelWithValueSet); + + // then try get value and state. + assertThat(attribute.getValue(labelWithValueSet), is(expectedValue)); + assertThat(attribute.getState(labelWithValueSet), is(expectedState)); + + // Try set Value in new Event + final TripLabel copyTarget = new TripLabel(); + attribute.setValue(copyTarget, expectedValue); + if (performSetterTest) { + assertThat(attribute.getValue(copyTarget), is(expectedValue)); + } + } + + @Test + public void testGetNonExistingChannel() { + assertThat(TripLabelAttribute.getByChannelName("unkownChannel"), is(nullValue())); + } + + @Test + public void testCategory() { + final String category = "ICE"; + doTestTripAttribute("category", null, (TripLabel e) -> e.setC(category), category, new StringType(category), + true); + } + + @Test + public void testNumber() { + final String number = "4567"; + doTestTripAttribute("number", null, (TripLabel e) -> e.setN(number), number, new StringType(number), true); + } + + @Test + public void testOwner() { + final String owner = "W3"; + doTestTripAttribute("owner", null, (TripLabel e) -> e.setO(owner), owner, new StringType(owner), true); + } + + @Test + public void testFilterFlages() { + final String filter = "a"; + doTestTripAttribute("filter-flags", null, (TripLabel e) -> e.setF(filter), filter, new StringType(filter), + true); + } + + @Test + public void testTripType() { + final TripType type = TripType.E; + doTestTripAttribute("trip-type", null, (TripLabel e) -> e.setT(type), type, new StringType("e"), true); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimeproviderStub.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimeproviderStub.java new file mode 100644 index 0000000000000..0bf7072e48d56 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimeproviderStub.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.function.Supplier; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Stub time provider. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class TimeproviderStub implements Supplier { + + public GregorianCalendar time = new GregorianCalendar(); + + @Override + public Date get() { + return this.time.getTime(); + } + + public void moveAhead(int seconds) { + this.time.set(Calendar.SECOND, time.get(Calendar.SECOND) + seconds); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoaderTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoaderTest.java new file mode 100644 index 0000000000000..6a25c8cf51b2b --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoaderTest.java @@ -0,0 +1,229 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.TimetableStopFilter; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Tests for the {@link TimetableLoader}. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public class TimetableLoaderTest implements TimetablesV1ImplTestHelper { + + @Test + public void testLoadRequiredStopCount() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL, + EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 20); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 30); + + final List stops = loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09", + "https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/10", + "https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/11")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + assertThat(stops, hasSize(21)); + assertEquals("-5296516961807204721-2108160906-5", stops.get(0).getId()); + assertEquals("-3222259045572671319-2108161155-1", stops.get(20).getId()); + + // when requesting again no further call to plan is made, because required stops are available. + final List stops02 = loader.getTimetableStops(); + assertThat(stops02, hasSize(21)); + assertThat(timeTableTestModule.getRequestedPlanUrls(), hasSize(3)); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), hasSize(1)); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + } + + @Test + public void testLoadNewDataIfRequired() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL, + EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 8); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0); + + final List stops = loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + assertThat(stops, hasSize(8)); + assertEquals("1763676552526687479-2108160847-6", stops.get(0).getId()); + assertEquals("8681599812964340829-2108160955-1", stops.get(7).getId()); + + // Move clock ahead for 30 minutes, so that some of the fetched data is in past and new plan data must be + // requested + timeProvider.moveAhead(30 * 60); + + final List stops02 = loader.getTimetableStops(); + assertThat(stops02, hasSize(13)); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09", + "https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/10")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226", + "https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + assertEquals("-5296516961807204721-2108160906-5", stops02.get(0).getId()); + assertEquals("-3376513334056532423-2108161055-1", stops02.get(12).getId()); + } + + @Test + public void testRequestUpdates() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ALL, + EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 1); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 30); + + // First call - plan and full changes are requested. + loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + // Changes are updated only every 30 seconds, so move clock ahead 20 seconds, no request is made + timeProvider.moveAhead(20); + loader.getTimetableStops(); + + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + // Move ahead 10 seconds, so recent changes are fetched + timeProvider.moveAhead(10); + loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/rchg/8000226")); + + // Move again ahead 30 seconds, recent changes are fetched again + timeProvider.moveAhead(30); + loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/rchg/8000226", + "https://api.deutschebahn.com/timetables/v1/rchg/8000226")); + + // If recent change were not updated last 120 seconds the full changes must be requested + timeProvider.moveAhead(120); + loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226", + "https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/rchg/8000226", + "https://api.deutschebahn.com/timetables/v1/rchg/8000226")); + } + + @Test + public void testReturnOnlyArrivals() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.ARRIVALS, + EventType.ARRIVAL, timeProvider, EVA_LEHRTE, 20); + + // Simulate that only one url is available + timeTableTestModule.addAvailableUrl("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09"); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0); + + final List stops = loader.getTimetableStops(); + + // File contains 8 stops, but 2 are only departures + assertThat(stops, hasSize(6)); + assertEquals("1763676552526687479-2108160847-6", stops.get(0).getId()); + assertEquals("-735649762452915464-2108160912-6", stops.get(5).getId()); + } + + @Test + public void testReturnOnlyDepartures() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.DEPARTURES, + EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 20); + + // Simulate that only one url is available + timeTableTestModule.addAvailableUrl("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09"); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 0); + + final List stops = loader.getTimetableStops(); + + // File contains 8 stops, but 2 are only arrivals + assertThat(stops, hasSize(6)); + assertEquals("-94442819435724762-2108160916-1", stops.get(0).getId()); + assertEquals("8681599812964340829-2108160955-1", stops.get(5).getId()); + } + + @Test + public void testRemoveEntryOnlyIfChangedTimeIsInPast() throws Exception { + final TimetablesApiTestModule timeTableTestModule = this.createApiWithTestdata(); + final TimeproviderStub timeProvider = new TimeproviderStub(); + final TimetableLoader loader = new TimetableLoader(timeTableTestModule.getApi(), TimetableStopFilter.DEPARTURES, + EventType.DEPARTURE, timeProvider, EVA_LEHRTE, 1); + + timeProvider.time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 35); + + final List stops = loader.getTimetableStops(); + assertThat(timeTableTestModule.getRequestedPlanUrls(), + contains("https://api.deutschebahn.com/timetables/v1/plan/8000226/210816/09")); + assertThat(timeTableTestModule.getRequestedFullChangesUrls(), + contains("https://api.deutschebahn.com/timetables/v1/fchg/8000226")); + assertThat(timeTableTestModule.getRequestedRecentChangesUrls(), empty()); + + // Stop -5296516961807204721-2108160906-5 has its planned time at 9:34, but its included because its changed + // time is 9:42 + assertThat(stops, hasSize(4)); + assertEquals("-5296516961807204721-2108160906-5", stops.get(0).getId()); + assertEquals("2108160942", stops.get(0).getDp().getCt()); + assertEquals("8681599812964340829-2108160955-1", stops.get(3).getId()); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStubHttpCallable.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStubHttpCallable.java new file mode 100644 index 0000000000000..44aab0cfbe9f0 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableStubHttpCallable.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl.HttpCallable; + +/** + * Stub Implementation for {@link HttpCallable}, that provides Data for the selected station, date and hour from file + * system. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public class TimetableStubHttpCallable implements HttpCallable { + + private static final Pattern PLAN_URL_PATTERN = Pattern + .compile("https://api.deutschebahn.com/timetables/v1/plan/(\\d+)/(\\d+)/(\\d+)"); + private static final Pattern FULL_CHANGES_URL_PATTERN = Pattern + .compile("https://api.deutschebahn.com/timetables/v1/fchg/(\\d+)"); + private static final Pattern RECENT_CHANGES_URL_PATTERN = Pattern + .compile("https://api.deutschebahn.com/timetables/v1/rchg/(\\d+)"); + + private final File testdataDir; + private final List requestedPlanUrls; + private final List requestedFullChangesUrls; + private final List requestedRecentChangesUrls; + + // Allows simulation of available data. + // if not set all available files will be served. + private @Nullable Set availableUrls = null; + + public TimetableStubHttpCallable(File testdataDir) { + this.testdataDir = testdataDir; + this.requestedPlanUrls = new ArrayList<>(); + this.requestedFullChangesUrls = new ArrayList(); + this.requestedRecentChangesUrls = new ArrayList(); + } + + public void addAvailableUrl(String url) { + if (this.availableUrls == null) { + availableUrls = new HashSet<>(); + } + this.availableUrls.add(url); + } + + @Override + public String executeUrl( // + String httpMethod, // + String url, // + Properties httpHeaders, // + @Nullable InputStream content, // + @Nullable String contentType, // + int timeout) throws IOException { + final Matcher planMatcher = PLAN_URL_PATTERN.matcher(url); + if (planMatcher.matches()) { + requestedPlanUrls.add(url); + return processRequest(url, planMatcher, this::getPlanData); + } + + final Matcher fullChangesMatcher = FULL_CHANGES_URL_PATTERN.matcher(url); + if (fullChangesMatcher.matches()) { + requestedFullChangesUrls.add(url); + return processRequest(url, fullChangesMatcher, this::getFullChanges); + } + + final Matcher recentChangesMatcher = RECENT_CHANGES_URL_PATTERN.matcher(url); + if (recentChangesMatcher.matches()) { + requestedRecentChangesUrls.add(url); + return processRequest(url, recentChangesMatcher, this::getRecentChanges); + } + return ""; + } + + private String processRequest(String url, Matcher matcher, Function responseSupplier) { + if (availableUrls != null && !availableUrls.contains(url)) { + return ""; + } else { + return responseSupplier.apply(matcher); + } + } + + private String getPlanData(final Matcher planMatcher) { + final String evaNo = planMatcher.group(1); + final String day = planMatcher.group(2); + final String hour = planMatcher.group(3); + + final File responseFile = new File(this.testdataDir, "plan/" + evaNo + "/" + day + "/" + hour + ".xml"); + return serveFileContentIfExists(responseFile); + } + + private String serveFileContentIfExists(File responseFile) { + if (!responseFile.exists()) { + return ""; + } + + try { + return Files.readString(responseFile.toPath()); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + private String getRecentChanges(Matcher recentChangesMatcher) { + final String evaNo = recentChangesMatcher.group(1); + File responseFile = new File(this.testdataDir, "rchg/" + evaNo + ".xml"); + return serveFileContentIfExists(responseFile); + } + + private String getFullChanges(Matcher fullChangesMatcher) { + final String evaNo = fullChangesMatcher.group(1); + File responseFile = new File(this.testdataDir, "fchg/" + evaNo + ".xml"); + return serveFileContentIfExists(responseFile); + } + + public List getRequestedPlanUrls() { + return requestedPlanUrls; + } + + public List getRequestedFullChangesUrls() { + return requestedFullChangesUrls; + } + + public List getRequestedRecentChangesUrls() { + return requestedRecentChangesUrls; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesApiTestModule.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesApiTestModule.java new file mode 100644 index 0000000000000..5c90d602d502b --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesApiTestModule.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.net.URISyntaxException; +import java.util.List; + +import javax.xml.bind.JAXBException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl.HttpCallable; +import org.xml.sax.SAXException; + +/** + * Testmodule that contains the {@link TimetablesV1Api} and {@link TimetableStubHttpCallable}. + * Used in tests to check which http calls have been made. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class TimetablesApiTestModule { + + private final TimetablesV1Api api; + private final TimetableStubHttpCallable httpStub; + + public TimetablesApiTestModule(TimetablesV1Api api, TimetableStubHttpCallable httpStub) { + this.api = api; + this.httpStub = httpStub; + } + + public TimetablesV1Api getApi() { + return api; + } + + public void addAvailableUrl(String url) { + this.httpStub.addAvailableUrl(url); + } + + public List getRequestedPlanUrls() { + return httpStub.getRequestedPlanUrls(); + } + + public List getRequestedFullChangesUrls() { + return httpStub.getRequestedFullChangesUrls(); + } + + public List getRequestedRecentChangesUrls() { + return httpStub.getRequestedRecentChangesUrls(); + } + + public TimetablesV1ApiFactory getApiFactory() { + return new TimetablesV1ApiFactory() { + + @Override + public TimetablesV1Api create(String authToken, HttpCallable httpCallable) + throws JAXBException, SAXException, URISyntaxException { + return api; + } + }; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiStub.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiStub.java new file mode 100644 index 0000000000000..3b14cdfdc5824 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ApiStub.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import java.io.IOException; +import java.util.Date; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; + +/** + * Stub Implementation of {@link TimetablesV1Api}, that may return an preconfigured Timetable or + * throws an {@link IOException} if not data has been set. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class TimetablesV1ApiStub implements TimetablesV1Api { + + @Nullable + private final Timetable result; + + private TimetablesV1ApiStub(@Nullable Timetable result) { + this.result = result; + } + + /** + * Creates an new {@link TimetablesV1ApiStub}, that returns the given result. + */ + public static TimetablesV1ApiStub createWithResult(Timetable timetable) { + return new TimetablesV1ApiStub(timetable); + } + + /** + * Creates an new {@link TimetablesV1ApiStub} that throws an Exception. + */ + public static TimetablesV1ApiStub createWithException() { + return new TimetablesV1ApiStub(null); + } + + @Override + public Timetable getPlan(String evaNo, Date time) throws IOException { + final Timetable currentResult = this.result; + if (currentResult == null) { + throw new IOException("No timetable data is available"); + } else { + return currentResult; + } + } + + @Override + public Timetable getFullChanges(String evaNo) throws IOException { + return new Timetable(); + } + + @Override + public Timetable getRecentChanges(String evaNo) throws IOException { + return new Timetable(); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTest.java new file mode 100644 index 0000000000000..9e5ae39276040 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTest.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; + +/** + * Tests for {@link TimetablesV1Impl} + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public class TimetablesV1ImplTest implements TimetablesV1ImplTestHelper { + + @Test + public void testGetDataForLehrte() throws Exception { + TimetablesV1Api timeTableApi = createApiWithTestdata().getApi(); + + Date time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 22).getTime(); + + Timetable timeTable = timeTableApi.getPlan(EVA_LEHRTE, time); + assertNotNull(timeTable); + assertEquals(8, timeTable.getS().size()); + } + + @Test + public void testGetNonExistingData() throws Exception { + TimetablesV1Api timeTableApi = createApiWithTestdata().getApi(); + + Date time = new GregorianCalendar(2021, Calendar.AUGUST, 16, 9, 22).getTime(); + + Timetable timeTable = timeTableApi.getPlan("ABCDEF", time); + assertNotNull(timeTable); + assertEquals(0, timeTable.getS().size()); + } + + @Test + public void testGetDataForHannoverHBF() throws Exception { + TimetablesV1Api timeTableApi = createApiWithTestdata().getApi(); + + Date time = new GregorianCalendar(2021, Calendar.OCTOBER, 14, 11, 00).getTime(); + + Timetable timeTable = timeTableApi.getPlan(EVA_HANNOVER_HBF, time); + assertNotNull(timeTable); + assertEquals(50, timeTable.getS().size()); + + Timetable changes = timeTableApi.getFullChanges(EVA_HANNOVER_HBF); + assertNotNull(changes); + assertEquals(730, changes.getS().size()); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTestHelper.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTestHelper.java new file mode 100644 index 0000000000000..2a92393279619 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/timetable/TimetablesV1ImplTestHelper.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.timetable; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.File; +import java.net.URL; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Helper interface for jUnit Tests to provide an {@link TimetablesApiTestModule}. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public interface TimetablesV1ImplTestHelper { + + public static final String EVA_LEHRTE = "8000226"; + public static final String EVA_HANNOVER_HBF = "8000152"; + public static final String AUTH_TOKEN = "354c8161cd7fb0936c840240280c131e"; + + /** + * Creates an {@link TimetablesApiTestModule} that uses http response data from file system. + */ + public default TimetablesApiTestModule createApiWithTestdata() throws Exception { + final URL timetablesData = getClass().getResource("/timetablesData"); + assertNotNull(timetablesData); + final File testDataDir = new File(timetablesData.toURI()); + final TimetableStubHttpCallable httpStub = new TimetableStubHttpCallable(testDataDir); + final TimetablesV1Impl timeTableApi = new TimetablesV1Impl(AUTH_TOKEN, httpStub); + return new TimetablesApiTestModule(timeTableApi, httpStub); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000152.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000152.xml new file mode 100644 index 0000000000000..b95ec6d5eb10c --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000152.xml @@ -0,0 +1,5401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000226.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000226.xml new file mode 100644 index 0000000000000..b4783dbe27c03 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/fchg/8000226.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000152/211014/11.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000152/211014/11.xml new file mode 100644 index 0000000000000..52bb29f7e56dd --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000152/211014/11.xml @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/07.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/07.xml new file mode 100644 index 0000000000000..4f00d86594ccf --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/07.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/08.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/08.xml new file mode 100644 index 0000000000000..c2413f0139472 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/08.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/09.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/09.xml new file mode 100644 index 0000000000000..0613399d0f9f6 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/09.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/10.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/10.xml new file mode 100644 index 0000000000000..e2d7fe24c89a8 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/10.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/11.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/11.xml new file mode 100644 index 0000000000000..494e57b898e8b --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/11.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/12.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/12.xml new file mode 100644 index 0000000000000..f1b3ee40f6bd7 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/12.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/13.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/13.xml new file mode 100644 index 0000000000000..e4212807bf6d3 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/13.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/14.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/14.xml new file mode 100644 index 0000000000000..682e6e2413f1c --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/14.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/15.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/15.xml new file mode 100644 index 0000000000000..f65a2880434b8 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/15.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/16.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/16.xml new file mode 100644 index 0000000000000..68e29297f1407 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/16.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/17.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/17.xml new file mode 100644 index 0000000000000..6fb571efa3533 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/17.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/18.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/18.xml new file mode 100644 index 0000000000000..0f143706b5c1d --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/18.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/19.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/19.xml new file mode 100644 index 0000000000000..ce466a72562bc --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/19.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/20.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/20.xml new file mode 100644 index 0000000000000..1ba8e2629e637 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/20.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/21.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/21.xml new file mode 100644 index 0000000000000..5714e711df55f --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/21.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/22.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/22.xml new file mode 100644 index 0000000000000..63fc2808f2ae0 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/22.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/23.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/23.xml new file mode 100644 index 0000000000000..d30ab2d780e48 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210816/23.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/00.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/00.xml new file mode 100644 index 0000000000000..6acd438713d8e --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/00.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/01.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/01.xml new file mode 100644 index 0000000000000..5a5adda84e890 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/01.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/02.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/02.xml new file mode 100644 index 0000000000000..5f341233944ce --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/02.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/03.xml b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/03.xml new file mode 100644 index 0000000000000..5f341233944ce --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/resources/timetablesData/plan/8000226/210817/03.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/bundles/pom.xml b/bundles/pom.xml index de55c1a3f5b88..9635e6296d4cc 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -96,6 +96,7 @@ org.openhab.binding.dbquery org.openhab.binding.deconz org.openhab.binding.denonmarantz + org.openhab.binding.deutschebahn org.openhab.binding.digiplex org.openhab.binding.digitalstrom org.openhab.binding.dlinksmarthome From 007a486771795fa490cd18cc9f890ca3ac605812 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 28 Nov 2021 19:31:53 +0100 Subject: [PATCH 141/361] Report SAT Errors with GHA Annotations (#11652) Let's test the GHA annotations for errors also in this repo! Similar to openhab/openhab-core#2543 Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .github/openhab-compile-problems.json | 21 +++++++++++++++++++++ .github/workflows/ci-build.yml | 13 +++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/openhab-compile-problems.json diff --git a/.github/openhab-compile-problems.json b/.github/openhab-compile-problems.json new file mode 100644 index 0000000000000..a5c5c4bb9dc51 --- /dev/null +++ b/.github/openhab-compile-problems.json @@ -0,0 +1,21 @@ +{ + "problemMatcher": [ + { + "owner": "openhab-compile-problems", + "severity": "error", + "pattern": [ + { + "regexp": "Failed to execute goal.*Compilation failure" + }, + { + "regexp": "^\\[ERROR\\] (.+\\.java):\\[(.+),(.+)\\] (.*)$", + "file": 1, + "line": 2, + "col": 3, + "message": 4, + "loop": true + } + ] + } + ] +} diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index ae6fc2af989fa..fc5c2a2cf96be 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -54,6 +54,11 @@ jobs: with: maven-version: ${{ matrix.maven }} + - name: Register Problem Matchers + id: problem_matchers + run: | + echo "::add-matcher::.github/openhab-compile-problems.json" + - name: Get Changed Files id: files uses: Ana06/get-changed-files@v2.0.0 @@ -84,3 +89,11 @@ jobs: with: name: sat-summary-report path: target/summary_report.html + + - name: Report SAT Errors as Annotations + uses: ghys/checkstyle-github-action@main + if: ${{ always() && ((steps.build.outcome == 'success') || (steps.build.outcome == 'failure')) }} + with: + title: CheckStyle Violations + path: '**/checkstyle-result.xml' + mode: inline From 2b7454f6e357c91284d6f437193ffe151dfcc27d Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 28 Nov 2021 19:32:50 +0100 Subject: [PATCH 142/361] Use Maven 3.8.4 in GHA CI builds (#11649) This new version fixes a few regressions, see: https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12316922&version=12350685 Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .github/workflows/ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index fc5c2a2cf96be..24c0cc756f00d 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: java: [ '11' ] - maven: [ '3.8.3'] + maven: [ '3.8.4'] os: [ 'ubuntu-20.04' ] name: Build (Java ${{ matrix.java }}, ${{ matrix.os }}) runs-on: ${{ matrix.os }} From 6c6fbc85dbfb9128c19d63d543fed2f0bda17661 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 28 Nov 2021 21:58:08 +0100 Subject: [PATCH 143/361] Update bnd to 6.1.0 (#11650) For release notes, see: https://github.com/bndtools/bnd/wiki/Changes-in-6.1.0 Related to openhab/openhab-core#2583 Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- itests/org.openhab.binding.astro.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.avmfritz.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.feed.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.hue.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.max.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.mielecloud.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.modbus.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.nest.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.ntp.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.systeminfo.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.tradfri.tests/itest.bndrun | 4 ++-- itests/org.openhab.binding.wemo.tests/itest.bndrun | 4 ++-- itests/org.openhab.persistence.mapdb.tests/itest.bndrun | 4 ++-- pom.xml | 2 +- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/itests/org.openhab.binding.astro.tests/itest.bndrun b/itests/org.openhab.binding.astro.tests/itest.bndrun index 0116b30104a05..b4924f7fdb13a 100644 --- a/itests/org.openhab.binding.astro.tests/itest.bndrun +++ b/itests/org.openhab.binding.astro.tests/itest.bndrun @@ -38,7 +38,6 @@ Fragment-Host: org.openhab.binding.astro org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -50,4 +49,5 @@ Fragment-Host: org.openhab.binding.astro net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun index a7670b4b6036e..b44c40a905aec 100644 --- a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun +++ b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun @@ -64,7 +64,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -75,4 +74,5 @@ Fragment-Host: org.openhab.binding.avmfritz net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.feed.tests/itest.bndrun b/itests/org.openhab.binding.feed.tests/itest.bndrun index 7a8e614b2a9f3..e377d99eedfac 100644 --- a/itests/org.openhab.binding.feed.tests/itest.bndrun +++ b/itests/org.openhab.binding.feed.tests/itest.bndrun @@ -68,11 +68,11 @@ Fragment-Host: org.openhab.binding.feed org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ junit-jupiter-engine;version='[5.8.1,5.8.2)',\ junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ - junit-platform-launcher;version='[1.8.1,1.8.2)' + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.hue.tests/itest.bndrun b/itests/org.openhab.binding.hue.tests/itest.bndrun index cab24b5c3e6e2..dc760309aa28e 100644 --- a/itests/org.openhab.binding.hue.tests/itest.bndrun +++ b/itests/org.openhab.binding.hue.tests/itest.bndrun @@ -72,11 +72,11 @@ Fragment-Host: org.openhab.binding.hue org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ junit-jupiter-engine;version='[5.8.1,5.8.2)',\ junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ - junit-platform-launcher;version='[1.8.1,1.8.2)' + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.max.tests/itest.bndrun b/itests/org.openhab.binding.max.tests/itest.bndrun index d26cdf945fac0..20cc682b43f2a 100644 --- a/itests/org.openhab.binding.max.tests/itest.bndrun +++ b/itests/org.openhab.binding.max.tests/itest.bndrun @@ -59,11 +59,11 @@ Fragment-Host: org.openhab.binding.max org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ junit-jupiter-engine;version='[5.8.1,5.8.2)',\ junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ - junit-platform-launcher;version='[1.8.1,1.8.2)' + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun index d57509e7e8320..9daae00cf5d7b 100644 --- a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun +++ b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun @@ -74,7 +74,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -85,4 +84,5 @@ Fragment-Host: org.openhab.binding.mielecloud net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.modbus.tests/itest.bndrun b/itests/org.openhab.binding.modbus.tests/itest.bndrun index 67013583741b6..9521f950d3bd7 100644 --- a/itests/org.openhab.binding.modbus.tests/itest.bndrun +++ b/itests/org.openhab.binding.modbus.tests/itest.bndrun @@ -62,7 +62,6 @@ Fragment-Host: org.openhab.binding.modbus org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -75,4 +74,5 @@ Fragment-Host: org.openhab.binding.modbus net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.nest.tests/itest.bndrun b/itests/org.openhab.binding.nest.tests/itest.bndrun index 68df43967f27b..721fca207740f 100644 --- a/itests/org.openhab.binding.nest.tests/itest.bndrun +++ b/itests/org.openhab.binding.nest.tests/itest.bndrun @@ -84,7 +84,6 @@ Fragment-Host: org.openhab.binding.nest org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ com.fasterxml.woodstox.woodstox-core;version='[6.2.6,6.2.7)',\ org.apache.aries.jax.rs.whiteboard;version='[2.0.1,2.0.2)',\ org.apache.cxf.cxf-core;version='[3.4.5,3.4.6)',\ @@ -104,4 +103,5 @@ Fragment-Host: org.openhab.binding.nest net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.ntp.tests/itest.bndrun b/itests/org.openhab.binding.ntp.tests/itest.bndrun index 745c4789664f6..8d661f047d8c9 100644 --- a/itests/org.openhab.binding.ntp.tests/itest.bndrun +++ b/itests/org.openhab.binding.ntp.tests/itest.bndrun @@ -59,7 +59,6 @@ Fragment-Host: org.openhab.binding.ntp org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -70,4 +69,5 @@ Fragment-Host: org.openhab.binding.ntp net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index 6f15aaadeef8c..5099700998820 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -62,7 +62,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ com.sun.jna;version='[5.9.0,5.9.1)',\ com.sun.jna.platform;version='[5.9.0,5.9.1)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -73,4 +72,5 @@ Fragment-Host: org.openhab.binding.systeminfo net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.tradfri.tests/itest.bndrun b/itests/org.openhab.binding.tradfri.tests/itest.bndrun index 2e2d0c6d110d1..2f4651e75f6a4 100644 --- a/itests/org.openhab.binding.tradfri.tests/itest.bndrun +++ b/itests/org.openhab.binding.tradfri.tests/itest.bndrun @@ -64,7 +64,6 @@ Fragment-Host: org.openhab.binding.tradfri org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -76,4 +75,5 @@ Fragment-Host: org.openhab.binding.tradfri net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.binding.wemo.tests/itest.bndrun b/itests/org.openhab.binding.wemo.tests/itest.bndrun index 40cd8ce485885..c0824764f417c 100644 --- a/itests/org.openhab.binding.wemo.tests/itest.bndrun +++ b/itests/org.openhab.binding.wemo.tests/itest.bndrun @@ -72,7 +72,6 @@ Fragment-Host: org.openhab.binding.wemo org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -83,4 +82,5 @@ Fragment-Host: org.openhab.binding.wemo net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\ net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ - org.objenesis;version='[3.2.0,3.2.1)' + org.objenesis;version='[3.2.0,3.2.1)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun index 3f01089e37192..2e0949a1697fb 100644 --- a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun +++ b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun @@ -50,11 +50,11 @@ Fragment-Host: org.openhab.persistence.mapdb org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - biz.aQute.tester.junit-platform;version='[6.0.0,6.0.1)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ junit-jupiter-engine;version='[5.8.1,5.8.2)',\ junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ - junit-platform-launcher;version='[1.8.1,1.8.2)' + junit-platform-launcher;version='[1.8.1,1.8.2)',\ + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' diff --git a/pom.xml b/pom.xml index 5f326096b049c..d1053e574ad86 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ ${oh.java.version} 3.2.0-SNAPSHOT - 6.0.0 + 6.1.0 3.7.2 2.2.1 2.12.5 From d26aaae4d8a6d3c70151da92efbd217219360958 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 29 Nov 2021 00:29:40 +0100 Subject: [PATCH 144/361] [miio] add missing vacuum status codes (#11659) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- .../org/openhab/binding/miio/internal/robot/StatusType.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/StatusType.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/StatusType.java index 9956f4ce958cb..5a7835c8f75fb 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/StatusType.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/StatusType.java @@ -41,7 +41,9 @@ public enum StatusType { GOTO(16, "Go To"), ZONE(17, "Zone Clean"), ROOM(18, "Room Clean"), - FULL(100, "Full"); + RETURNING_HOME(22, "Returning Home"), + FULL(100, "Full"), + OFFLINE(101, "Device Offline"); private final int id; private final String description; From 2abba3705173fa53dc77174981ac3659eb98ec34 Mon Sep 17 00:00:00 2001 From: jlaur Date: Mon, 29 Nov 2021 08:16:08 +0100 Subject: [PATCH 145/361] [miele] Localization of state, program and phase (#11603) * Initial changes for state, program and phase localization. * Fix bridge configuration reload. * Extracted DeviceMetaData from MieleBridgeHandler. * Fix fallback to gateway text. * Consolidate getMieleEnum in DeviceMetaData. * Localize thing offline texts and increased accuracy. * Validate language during bridge initialization. * Interpret magic value for temperature. * Add missing i18n channel label/description strings. * Add missing washing machine phase texts in Dutch. * Add missing French dishwasher phase texts. Fixes #11602 Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miele/README.md | 21 +-- .../miele/internal/DeviceMetaData.java | 46 ++++++ .../binding/miele/internal/DeviceUtil.java | 65 ++++++++ .../miele/internal/MieleBindingConstants.java | 9 ++ .../miele/internal/MieleHandlerFactory.java | 33 ++-- .../internal/MieleTranslationProvider.java | 60 +++++++ .../handler/ApplianceChannelSelector.java | 14 +- .../handler/CoffeeMachineChannelSelector.java | 71 ++++---- .../handler/CoffeeMachineHandler.java | 7 +- .../internal/handler/DishWasherHandler.java | 6 +- .../handler/DishwasherChannelSelector.java | 91 +++++------ .../handler/ExtendedDeviceStateListener.java | 2 +- .../handler/FridgeChannelSelector.java | 42 ++--- .../handler/FridgeFreezerChannelSelector.java | 46 +++--- .../handler/FridgeFreezerHandler.java | 7 +- .../miele/internal/handler/FridgeHandler.java | 6 +- .../internal/handler/HobChannelSelector.java | 49 +++--- .../miele/internal/handler/HobHandler.java | 6 +- .../internal/handler/HoodChannelSelector.java | 39 ++--- .../miele/internal/handler/HoodHandler.java | 6 +- .../handler/MieleApplianceHandler.java | 41 ++++- .../internal/handler/MieleBridgeHandler.java | 80 ++++++---- .../internal/handler/OvenChannelSelector.java | 85 ++++------ .../miele/internal/handler/OvenHandler.java | 6 +- .../handler/TumbleDryerChannelSelector.java | 109 ++++++------- .../internal/handler/TumbleDryerHandler.java | 6 +- .../WashingMachineChannelSelector.java | 104 +++++------- .../handler/WashingMachineHandler.java | 7 +- .../resources/OH-INF/i18n/miele.properties | 151 ++++++++++++++++++ .../resources/OH-INF/i18n/miele_da.properties | 143 +++++++++++++++++ .../resources/OH-INF/i18n/miele_de.properties | 125 +++++++++++++++ .../resources/OH-INF/i18n/miele_fr.properties | 125 +++++++++++++++ .../resources/OH-INF/i18n/miele_nl.properties | 125 +++++++++++++++ .../resources/OH-INF/thing/washingmachine.xml | 2 +- .../main/resources/OH-INF/thing/xgw3000.xml | 4 + .../miele/internal/DeviceUtilTest.java | 31 ++++ 36 files changed, 1340 insertions(+), 430 deletions(-) create mode 100644 bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceMetaData.java create mode 100644 bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleTranslationProvider.java create mode 100644 bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_de.properties create mode 100644 bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_fr.properties create mode 100644 bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_nl.properties diff --git a/bundles/org.openhab.binding.miele/README.md b/bundles/org.openhab.binding.miele/README.md index 3856a68815e0b..0c72e1bf27bc9 100644 --- a/bundles/org.openhab.binding.miele/README.md +++ b/bundles/org.openhab.binding.miele/README.md @@ -128,15 +128,15 @@ Channels available for each appliance type are listed below. | Program | Description | |---------|-------------------------------------| -| 26 | Pots & Pans | -| 27 | Clean Machine | -| 28 | Economy | +| 26 | Intensive | +| 27 | Maintenance programme | +| 28 | ECO | | 30 | Normal | -| 32 | Sensor Wash | -| 34 | Energy Saver | -| 35 | China & Crystal | +| 32 | Automatic | +| 34 | SolarSave | +| 35 | Gentle | | 36 | Extra Quiet | -| 37 | SaniWash | +| 37 | Hygiene | | 38 | QuickPowerWash | | 42 | Tall items | @@ -282,6 +282,7 @@ See oven. | Program | Description | |---------|-------------------------------------| | 10 | Automatic Plus | +| 20 | Cottons | | 23 | Cottons hygiene | | 30 | Minimum iron | | 31 | Gentle minimum iron | @@ -314,11 +315,11 @@ See oven. | 513 | 1 | Programme running | | 514 | 2 | Drying | | 515 | 3 | Drying Machine iron | -| 516 | 4 | Drying Hand iron (1) | +| 516 | 4 | Drying Hand iron (2) | | 517 | 5 | Drying Normal | | 518 | 6 | Drying Normal+ | | 519 | 7 | Cooling down | -| 520 | 8 | Drying Hand iron (2) | +| 520 | 8 | Drying Hand iron (1) | | 522 | 10 | Finished | #### Washing Machine @@ -338,7 +339,7 @@ See oven. | finish | DateTime | Read | Time to finish the program running on the appliance | | door | Contact | Read | Current state of the door of the appliance | | switch | Switch | Write | Switch the appliance on or off | -| target | Number:Temperature | Read | Temperature of the selected program | +| target | Number:Temperature | Read | Temperature of the selected program (10 °C = cold) | | spinningspeed | String | Read | Spinning speed in the program running on the appliance | | powerConsumption | Number:Power | Read | Power consumption by the currently running program on the appliance | | waterConsumption | Number:Volume | Read | Water consumption by the currently running program on the appliance | diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceMetaData.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceMetaData.java new file mode 100644 index 0000000000000..9d84b350cb104 --- /dev/null +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceMetaData.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.miele.internal; + +import java.util.Map.Entry; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * The {@link DeviceMetaData} class represents the Metadata node in the response JSON. + * + * @author Jacob Laursen - Initial contribution + */ +public class DeviceMetaData { + public String Filter; + public String description; + public String LocalizedID; + public String LocalizedValue; + public JsonObject MieleEnum; + public String access; + + public String getMieleEnum(String s) { + if (this.MieleEnum == null) { + return null; + } + + for (Entry enumEntry : this.MieleEnum.entrySet()) { + if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { + return enumEntry.getKey(); + } + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java index c80b28d38f0d4..31e168fc75871 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java @@ -12,9 +12,13 @@ */ package org.openhab.binding.miele.internal; +import static org.openhab.binding.miele.internal.MieleBindingConstants.*; + import java.nio.charset.StandardCharsets; +import java.util.Map; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; import org.openhab.core.library.unit.SIUnits; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; @@ -28,6 +32,15 @@ public class DeviceUtil { private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII); private static final String TEMPERATURE_UNDEFINED = "32768"; + private static final String TEMPERATURE_COLD = "-32760"; + private static final String TEXT_PREFIX = "miele."; + + private static final Map states = Map.ofEntries(Map.entry("1", "off"), Map.entry("2", "stand-by"), + Map.entry("3", "programmed"), Map.entry("4", "waiting-to-start"), Map.entry("5", "running"), + Map.entry("6", "paused"), Map.entry("7", "end"), Map.entry("8", "failure"), Map.entry("9", "abort"), + Map.entry("10", "idle"), Map.entry("11", "rinse-hold"), Map.entry("12", "service"), + Map.entry("13", "super-freezing"), Map.entry("14", "super-cooling"), Map.entry("15", "super-heating"), + Map.entry("144", "default"), Map.entry("145", "locked"), Map.entry("255", "not-connected")); /** * Convert byte array to hex representation. @@ -60,7 +73,59 @@ public static State getTemperatureState(String s) throws NumberFormatException { if (TEMPERATURE_UNDEFINED.equals(s)) { return UnDefType.UNDEF; } + if (TEMPERATURE_COLD.equals(s)) { + return new QuantityType<>(10, SIUnits.CELSIUS); + } int temperature = Integer.parseInt(s); return new QuantityType<>(temperature, SIUnits.CELSIUS); } + + /** + * Get state text for provided string taking into consideration {@link DeviceMetaData} + * as well as built-in/translated strings. + */ + public static State getStateTextState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return getTextState(s, dmd, translationProvider, states, MISSING_STATE_TEXT_PREFIX, ""); + } + + /** + * Get text for provided string taking into consideration {@link DeviceMetaData} + * as well as built-in/translated strings. + * + * @param s Raw string to be processed + * @param dmd {@link DeviceMetaData} possibly containing LocalizedValue and/or enum from gateway + * @param translationProvider {@link MieleTranslationProvider} for localization support + * @param valueMap Map of numeric values with corresponding text keys + * @param propertyPrefix Property prefix appended to text key (including dot) + * @param appliancePrefix Appliance prefix appended to text key (including dot) + * @return Text string as State + */ + public static State getTextState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider, + Map valueMap, String propertyPrefix, String appliancePrefix) { + if ("0".equals(s)) { + return UnDefType.UNDEF; + } + + String gatewayText = null; + if (dmd != null) { + if (dmd.LocalizedValue != null && !dmd.LocalizedValue.isEmpty()) { + gatewayText = dmd.LocalizedValue; + } else { + gatewayText = dmd.getMieleEnum(s); + } + } + + String value = valueMap.get(s); + if (value != null) { + String key = TEXT_PREFIX + propertyPrefix + appliancePrefix + value; + return new StringType( + translationProvider.getText(key, gatewayText != null ? gatewayText : propertyPrefix + s)); + } + + if (gatewayText != null) { + return new StringType(gatewayText); + } + + return new StringType(propertyPrefix + s); + } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleBindingConstants.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleBindingConstants.java index 0ac74412f827b..65e693f031c90 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleBindingConstants.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleBindingConstants.java @@ -97,12 +97,21 @@ public class MieleBindingConstants { public static final int STATE_NOT_CONNECTED = 255; // Miele missing string prefixes + public static final String MISSING_STATE_TEXT_PREFIX = "state."; public static final String MISSING_PROGRAM_TEXT_PREFIX = "program."; public static final String MISSING_PHASE_TEXT_PREFIX = "phase."; + // Miele appliance localization text prefixes + public static final String MIELE_COFFEE_MACHINE_TEXT_PREFIX = "coffeemachine."; + public static final String MIELE_DISHWASHER_TEXT_PREFIX = "dishwasher."; + public static final String MIELE_OVEN_TEXT_PREFIX = "oven."; + public static final String MIELE_TUMBLE_DRYER_TEXT_PREFIX = "tumbledryer."; + public static final String MIELE_WASHING_MACHINE_TEXT_PREFIX = "washingmachine."; + // Bridge config properties public static final String HOST = "ipAddress"; public static final String INTERFACE = "interface"; public static final String USER_NAME = "userName"; public static final String PASSWORD = "password"; + public static final String LANGUAGE = "language"; } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java index 4754db07a39b8..e824716f912b6 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleHandlerFactory.java @@ -35,6 +35,8 @@ import org.openhab.binding.miele.internal.handler.WashingMachineHandler; import org.openhab.core.config.core.Configuration; import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -43,7 +45,10 @@ import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; /** * The {@link MieleHandlerFactory} is responsible for creating things and thing @@ -59,8 +64,18 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory { MieleApplianceHandler.SUPPORTED_THING_TYPES.stream()) .collect(Collectors.toSet()); + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; + private Map> discoveryServiceRegs = new HashMap<>(); + @Activate + public MieleHandlerFactory(final @Reference TranslationProvider i18nProvider, + final @Reference LocaleProvider localeProvider, ComponentContext componentContext) { + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; + } + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); @@ -89,31 +104,31 @@ protected ThingHandler createHandler(Thing thing) { return handler; } else if (MieleApplianceHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) { if (thing.getThingTypeUID().equals(THING_TYPE_HOOD)) { - return new HoodHandler(thing); + return new HoodHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_FRIDGEFREEZER)) { - return new FridgeFreezerHandler(thing); + return new FridgeFreezerHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_FRIDGE)) { - return new FridgeHandler(thing); + return new FridgeHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_OVEN)) { - return new OvenHandler(thing); + return new OvenHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_HOB)) { - return new HobHandler(thing); + return new HobHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_WASHINGMACHINE)) { - return new WashingMachineHandler(thing); + return new WashingMachineHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_DRYER)) { - return new TumbleDryerHandler(thing); + return new TumbleDryerHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_DISHWASHER)) { - return new DishWasherHandler(thing); + return new DishWasherHandler(thing, i18nProvider, localeProvider); } if (thing.getThingTypeUID().equals(THING_TYPE_COFFEEMACHINE)) { - return new CoffeeMachineHandler(thing); + return new CoffeeMachineHandler(thing, i18nProvider, localeProvider); } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleTranslationProvider.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleTranslationProvider.java new file mode 100644 index 0000000000000..fc46299cd37df --- /dev/null +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleTranslationProvider.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.miele.internal; + +import java.util.Locale; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +/** + * {@link MieleTranslationProvider} provides i18n message lookup + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class MieleTranslationProvider { + + private final Bundle bundle; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; + @Nullable + private final Locale locale; + + public MieleTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider) { + this.bundle = FrameworkUtil.getBundle(this.getClass()); + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; + this.locale = null; + } + + public MieleTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider, Locale locale) { + this.bundle = FrameworkUtil.getBundle(this.getClass()); + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; + this.locale = locale; + } + + public String getText(String key, String defaultText, @Nullable Object... arguments) { + String text = i18nProvider.getText(bundle, key, defaultText, + locale != null ? locale : localeProvider.getLocale(), arguments); + if (text == null) { + return defaultText; + } + return text; + } +} diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ApplianceChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ApplianceChannelSelector.java index 9ed9a638d2046..ed58dc4ed6f84 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ApplianceChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ApplianceChannelSelector.java @@ -12,7 +12,8 @@ */ package org.openhab.binding.miele.internal.handler; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceMetaData; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.types.State; /** @@ -51,6 +52,17 @@ public interface ApplianceChannelSelector { */ boolean isExtendedState(); + /** + * Returns a State for the given string, taking into + * account the metadata provided as well as text + * translations for corresponding numeric values. + * + * @param s - the value to be used to instantiate the State + * @param dmd - the device meta data + * @param translationProvider {@link MieleTranslationProvider} instance + */ + State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider); + /** * Returns a State for the given string, taking into * account the metadata provided. The meta data is sent by diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineChannelSelector.java index bde856833f8b1..f6b00d5cc1e1b 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineChannelSelector.java @@ -17,9 +17,10 @@ import java.lang.reflect.Method; import java.util.Collections; import java.util.Map; -import java.util.Map.Entry; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceUtil; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; @@ -30,8 +31,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for coffee machines * @@ -42,35 +41,46 @@ public enum CoffeeMachineChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { - State state = getTextState(s, dmd, programs, MISSING_PROGRAM_TEXT_PREFIX); + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getTextState(s, dmd, translationProvider, programs, MISSING_PROGRAM_TEXT_PREFIX, + MIELE_COFFEE_MACHINE_TEXT_PREFIX); if (state != null) { return state; } - return super.getState(s, dmd); + return super.getState(s, dmd, translationProvider); } }, PROGRAM(null, PROGRAM_CHANNEL_ID, DecimalType.class, false), PROGRAMTYPE("programType", "type", StringType.class, false), PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { - State state = getTextState(s, dmd, phases, MISSING_PHASE_TEXT_PREFIX); + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getTextState(s, dmd, translationProvider, phases, MISSING_PHASE_TEXT_PREFIX, + MIELE_COFFEE_MACHINE_TEXT_PREFIX); if (state != null) { return state; } - return super.getState(s, dmd); + return super.getState(s, dmd, translationProvider); } }, PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false), // lightingStatus signalFailure signalInfo DOOR("signalDoor", "door", OpenClosedType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("OPEN"); } @@ -128,10 +138,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -158,34 +173,4 @@ public State getState(String s) { return null; } - - public State getTextState(String s, DeviceMetaData dmd, Map valueMap, String prefix) { - if ("0".equals(s)) { - return UnDefType.UNDEF; - } - - if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) { - String text = valueMap.get(s); - if (text != null) { - return getState(text); - } - if (dmd == null || dmd.LocalizedValue == null) { - return getState(prefix + s); - } - } - - return null; - } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineHandler.java index cff9f134c5cc7..a1d94851971dd 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID; import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_COFFEE_SYSTEM; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -37,8 +39,9 @@ public class CoffeeMachineHandler extends MieleApplianceHandler programs = Map.ofEntries(entry("26", "Pots & Pans"), - entry("27", "Clean Machine"), entry("28", "Economy"), entry("30", "Normal"), entry("32", "Sensor Wash"), - entry("34", "Energy Saver"), entry("35", "China & Crystal"), entry("36", "Extra Quiet"), - entry("37", "SaniWash"), entry("38", "QuickPowerWash"), entry("42", "Tall items")); + private static final Map programs = Map.ofEntries(entry("26", "intensive"), + entry("27", "maintenance-programme"), entry("28", "eco"), entry("30", "normal"), entry("32", "automatic"), + entry("34", "solarsave"), entry("35", "gentle"), entry("36", "extra-quiet"), entry("37", "hygiene"), + entry("38", "quickpowerwash"), entry("42", "tall-items")); - private static final Map phases = Map.ofEntries(entry("2", "Pre-Wash"), entry("3", "Main Wash"), - entry("4", "Rinses"), entry("6", "Final rinse"), entry("7", "Drying"), entry("8", "Finished")); + private static final Map phases = Map.ofEntries(entry("2", "pre-wash"), entry("3", "main-wash"), + entry("4", "rinses"), entry("6", "final-rinse"), entry("7", "drying"), entry("8", "finished")); private final String mieleID; private final String channelID; @@ -198,10 +208,15 @@ public boolean isExtendedState() { return isExtendedState; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -228,34 +243,4 @@ public State getState(String s) { return null; } - - public State getTextState(String s, DeviceMetaData dmd, Map valueMap, String prefix) { - if ("0".equals(s)) { - return UnDefType.UNDEF; - } - - if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) { - String text = valueMap.get(s); - if (text != null) { - return getState(text); - } - if (dmd == null || dmd.LocalizedValue == null) { - return getState(prefix + s); - } - } - - return null; - } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ExtendedDeviceStateListener.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ExtendedDeviceStateListener.java index f34623d677890..df5ec2b5bed3a 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ExtendedDeviceStateListener.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ExtendedDeviceStateListener.java @@ -16,7 +16,7 @@ * Appliance handlers can implement the {@link ExtendedDeviceStateListener} interface * to extract additional information from the ExtendedDeviceState property. * - * @author Jacob Laursen - Added power/water consumption channels + * @author Jacob Laursen - Initial contribution */ public interface ExtendedDeviceStateListener { void onApplianceExtendedStateChanged(byte[] extendedDeviceState); diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeChannelSelector.java index c97cffd0fc527..7d90b846a940b 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeChannelSelector.java @@ -15,10 +15,10 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.lang.reflect.Method; -import java.util.Map.Entry; +import org.openhab.binding.miele.internal.DeviceMetaData; import org.openhab.binding.miele.internal.DeviceUtil; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; @@ -30,8 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for fridges * @@ -42,25 +40,34 @@ public enum FridgeChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), SUPERCOOL(null, SUPERCOOL_CHANNEL_ID, OnOffType.class, false), FRIDGECURRENTTEMP("currentTemperature", "current", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, FRIDGETARGETTEMP("targetTemperature", "target", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, DOOR("signalDoor", "door", OpenClosedType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("OPEN"); } @@ -113,10 +120,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -152,16 +164,4 @@ public State getTemperatureState(String s) { return UnDefType.UNDEF; } } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerChannelSelector.java index 14d332dc0a1dc..d81db220b288d 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerChannelSelector.java @@ -15,10 +15,10 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.lang.reflect.Method; -import java.util.Map.Entry; +import org.openhab.binding.miele.internal.DeviceMetaData; import org.openhab.binding.miele.internal.DeviceUtil; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; @@ -30,8 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for fridges with * a freezer compartment @@ -43,7 +41,16 @@ public enum FridgeFreezerChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), FREEZERSTATE("freezerState", "freezerstate", StringType.class, false), FRIDGESTATE("fridgeState", "fridgestate", StringType.class, false), @@ -51,32 +58,32 @@ public enum FridgeFreezerChannelSelector implements ApplianceChannelSelector { SUPERFREEZE(null, SUPERFREEZE_CHANNEL_ID, OnOffType.class, false), FREEZERCURRENTTEMP("freezerCurrentTemperature", "freezercurrent", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, FREEZERTARGETTEMP("freezerTargetTemperature", "freezertarget", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, FRIDGECURRENTTEMP("fridgeCurrentTemperature", "fridgecurrent", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, FRIDGETARGETTEMP("fridgeTargetTemperature", "fridgetarget", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, DOOR("signalDoor", "door", OpenClosedType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("OPEN"); } @@ -130,10 +137,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -169,16 +181,4 @@ public State getTemperatureState(String s) { return UnDefType.UNDEF; } } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerHandler.java index be9d5926cfbd1..82be8695190a2 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceProperty; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -37,8 +39,9 @@ public class FridgeFreezerHandler extends MieleApplianceHandler private final Logger logger = LoggerFactory.getLogger(FridgeHandler.class); - public FridgeHandler(Thing thing) { - super(thing, FridgeChannelSelector.class, MIELE_DEVICE_CLASS_FRIDGE); + public FridgeHandler(Thing thing, TranslationProvider i18nProvider, LocaleProvider localeProvider) { + super(thing, i18nProvider, localeProvider, FridgeChannelSelector.class, MIELE_DEVICE_CLASS_FRIDGE); } @Override diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobChannelSelector.java index abe82e7c86d65..9080efcae75c3 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobChannelSelector.java @@ -15,9 +15,10 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.lang.reflect.Method; -import java.util.Map.Entry; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceUtil; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.StringType; import org.openhab.core.types.State; @@ -25,8 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for hobs * @@ -37,13 +36,22 @@ public enum HobChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), PLATES("plateNumbers", "plates", DecimalType.class, true), PLATE1_POWER("plate1PowerStep", "plate1power", DecimalType.class, false), PLATE1_HEAT("plate1RemainingHeat", "plate1heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { // If there is remaining heat, the device metadata contains some informative string which can not be // converted into a DecimalType. We therefore ignore the metadata and return the device property value as a // State @@ -54,7 +62,7 @@ public State getState(String s, DeviceMetaData dmd) { PLATE2_POWER("plate2PowerStep", "plate2power", DecimalType.class, false), PLATE2_HEAT("plate2RemainingHeat", "plate2heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, @@ -62,7 +70,7 @@ public State getState(String s, DeviceMetaData dmd) { PLATE3_POWER("plate3PowerStep", "plate3power", DecimalType.class, false), PLATE3_HEAT("plate3RemainingHeat", "plate3heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, @@ -70,7 +78,7 @@ public State getState(String s, DeviceMetaData dmd) { PLATE4_POWER("plate4PowerStep", "plate4power", DecimalType.class, false), PLATE4_HEAT("plate4RemainingHeat", "plate4heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, @@ -78,7 +86,7 @@ public State getState(String s, DeviceMetaData dmd) { PLATE5_POWER("plate5PowerStep", "plate5power", DecimalType.class, false), PLATE5_HEAT("plate5RemainingHeat", "plate5heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, @@ -86,7 +94,7 @@ public State getState(String s, DeviceMetaData dmd) { PLATE6_POWER("plate6PowerStep", "plate6power", DecimalType.class, false), PLATE6_HEAT("plate6RemainingHeat", "plate6heat", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, @@ -131,10 +139,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -161,16 +174,4 @@ public State getState(String s) { return null; } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobHandler.java index bbbde6f630030..ad6ac3efc6dc2 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobHandler.java @@ -14,6 +14,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_HOB; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.types.Command; @@ -27,8 +29,8 @@ */ public class HobHandler extends MieleApplianceHandler { - public HobHandler(Thing thing) { - super(thing, HobChannelSelector.class, MIELE_DEVICE_CLASS_HOB); + public HobHandler(Thing thing, TranslationProvider i18nProvider, LocaleProvider localeProvider) { + super(thing, i18nProvider, localeProvider, HobChannelSelector.class, MIELE_DEVICE_CLASS_HOB); } @Override diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodChannelSelector.java index 623c9830d335c..b216bb8fe9bde 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodChannelSelector.java @@ -15,9 +15,10 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.lang.reflect.Method; -import java.util.Map.Entry; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceUtil; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StringType; @@ -27,8 +28,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for ventilation hoods * @@ -39,13 +38,22 @@ public enum HoodChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), VENTILATION("ventilationPower", "ventilation", DecimalType.class, false), LIGHT("lightingStatus", "light", OnOffType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("ON"); } @@ -98,10 +106,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -128,16 +141,4 @@ public State getState(String s) { return null; } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodHandler.java index 2211e0d26c848..bdc9350b3222a 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID; import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_HOOD; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -37,8 +39,8 @@ public class HoodHandler extends MieleApplianceHandler { private final Logger logger = LoggerFactory.getLogger(HoodHandler.class); - public HoodHandler(Thing thing) { - super(thing, HoodChannelSelector.class, MIELE_DEVICE_CLASS_HOOD); + public HoodHandler(Thing thing, TranslationProvider i18nProvider, LocaleProvider localeProvider) { + super(thing, i18nProvider, localeProvider, HoodChannelSelector.class, MIELE_DEVICE_CLASS_HOOD); } @Override diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java index 9c84e1a912a3e..c0b4d4f9d866f 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java @@ -15,18 +15,23 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*; import java.util.HashMap; +import java.util.IllformedLocaleException; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNull; +import org.openhab.binding.miele.internal.DeviceMetaData; import org.openhab.binding.miele.internal.DeviceUtil; import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceClassObject; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceProperty; import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.HomeDevice; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -71,13 +76,19 @@ public abstract class MieleApplianceHandler & ApplianceChannel protected String applianceId; protected MieleBridgeHandler bridgeHandler; + protected TranslationProvider i18nProvider; + protected LocaleProvider localeProvider; + protected MieleTranslationProvider translationProvider; private Class selectorType; protected String modelID; protected Map metaDataCache = new HashMap<>(); - public MieleApplianceHandler(Thing thing, Class selectorType, String modelID) { + public MieleApplianceHandler(Thing thing, TranslationProvider i18nProvider, LocaleProvider localeProvider, + Class selectorType, String modelID) { super(thing); + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; this.selectorType = selectorType; this.modelID = modelID; } @@ -129,6 +140,25 @@ public void onBridgeConnectionResumed() { if (bridge != null && getMieleBridgeHandler() != null) { ThingStatusInfo statusInfo = bridge.getStatusInfo(); updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription()); + initializeTranslationProvider(bridge); + } + } + + private void initializeTranslationProvider(Bridge bridge) { + Locale locale = null; + String language = (String) bridge.getConfiguration().get(LANGUAGE); + if (language != null && !language.isBlank()) { + try { + locale = new Locale.Builder().setLanguageTag(language).build(); + } catch (IllformedLocaleException e) { + logger.error("Invalid language configured: {}", e.getMessage()); + } + } + if (locale == null) { + logger.debug("No language configured, using system language."); + this.translationProvider = new MieleTranslationProvider(i18nProvider, localeProvider); + } else { + this.translationProvider = new MieleTranslationProvider(i18nProvider, localeProvider, locale); } } @@ -240,7 +270,7 @@ protected void onAppliancePropertyChanged(DeviceProperty dp) { ChannelUID theChannelUID = new ChannelUID(getThing().getUID(), selector.getChannelID()); if (dp.Value != null) { - State state = selector.getState(dpValue, dmd); + State state = selector.getState(dpValue, dmd, this.translationProvider); logger.trace("Update state of {} with getState '{}'", theChannelUID, state); updateState(theChannelUID, state); updateRawChannel(dp.Name, dpValue); @@ -249,10 +279,11 @@ protected void onAppliancePropertyChanged(DeviceProperty dp) { } } else { logger.debug("Updating the property '{}' of '{}' to '{}'", selector.getChannelID(), - getThing().getUID(), selector.getState(dpValue, dmd).toString()); + getThing().getUID(), selector.getState(dpValue, dmd, this.translationProvider).toString()); @NonNull Map<@NonNull String, @NonNull String> properties = editProperties(); - properties.put(selector.getChannelID(), selector.getState(dpValue, dmd).toString()); + properties.put(selector.getChannelID(), + selector.getState(dpValue, dmd, this.translationProvider).toString()); updateProperties(properties); } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java index 78ea4e8bc6233..47849b1f4c590 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java @@ -31,8 +31,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.IllformedLocaleException; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Random; @@ -50,6 +52,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier; import org.openhab.core.common.NamedThreadFactory; +import org.openhab.core.config.core.Configuration; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -209,15 +212,6 @@ public class DeviceProperty { } } - public class DeviceMetaData { - public String Filter; - public String description; - public String LocalizedID; - public String LocalizedValue; - public JsonObject MieleEnum; - public String access; - } - public MieleBridgeHandler(Bridge bridge) { super(bridge); } @@ -226,31 +220,59 @@ public MieleBridgeHandler(Bridge bridge) { public void initialize() { logger.debug("Initializing the Miele bridge handler."); - if (getConfig().get(HOST) != null && getConfig().get(INTERFACE) != null) { - if (IP_PATTERN.matcher((String) getConfig().get(HOST)).matches() - && IP_PATTERN.matcher((String) getConfig().get(INTERFACE)).matches()) { - try { - url = new URL("http://" + (String) getConfig().get(HOST) + "/remote/json-rpc"); - } catch (MalformedURLException e) { - logger.debug("An exception occurred while defining an URL :'{}'", e.getMessage()); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage()); - return; - } + if (!validateConfig(getConfig())) { + return; + } - // for future usage - no headers to be set for now - headers = new HashMap<>(); + try { + url = new URL("http://" + (String) getConfig().get(HOST) + "/remote/json-rpc"); + } catch (MalformedURLException e) { + logger.debug("An exception occurred while defining an URL :'{}'", e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage()); + return; + } + + // for future usage - no headers to be set for now + headers = new HashMap<>(); + + onUpdate(); + lastBridgeConnectionState = false; + updateStatus(ThingStatus.UNKNOWN); + } - onUpdate(); - updateStatus(ThingStatus.UNKNOWN); - } else { + private boolean validateConfig(Configuration config) { + if (config.get(HOST) == null || ((String) config.get(HOST)).isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "@text/offline.configuration-error.ip-address-not-set"); + return false; + } + if (config.get(INTERFACE) == null || ((String) config.get(INTERFACE)).isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "@text/offline.configuration-error.ip-multicast-interface-not-set"); + return false; + } + if (!IP_PATTERN.matcher((String) config.get(HOST)).matches()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "@text/offline.configuration-error.invalid-ip-gateway [\"" + config.get(HOST) + "\"]"); + return false; + } + if (!IP_PATTERN.matcher((String) config.get(INTERFACE)).matches()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "@text/offline.configuration-error.invalid-ip-multicast-interface [\"" + config.get(INTERFACE) + + "\"]"); + return false; + } + String language = (String) config.get(LANGUAGE); + if (language != null && !language.isBlank()) { + try { + new Locale.Builder().setLanguageTag(language).build(); + } catch (IllformedLocaleException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, - "Invalid IP address for the Miele@Home gateway or multicast interface:" + getConfig().get(HOST) - + "/" + getConfig().get(INTERFACE)); + "@text/offline.configuration-error.invalid-language [\"" + language + "\"]"); + return false; } - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, - "Cannot connect to the Miele gateway. host IP address or multicast interface are not set."); } + return true; } private Runnable pollingRunnable = new Runnable() { diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenChannelSelector.java index f6814a8163a9a..3bd6a1b50b1a0 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenChannelSelector.java @@ -19,11 +19,11 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; -import java.util.Map.Entry; import java.util.TimeZone; +import org.openhab.binding.miele.internal.DeviceMetaData; import org.openhab.binding.miele.internal.DeviceUtil; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; @@ -36,8 +36,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for ovens * @@ -49,25 +47,35 @@ public enum OvenChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false), PROGRAM(null, PROGRAM_CHANNEL_ID, DecimalType.class, false), PROGRAMTYPE("programType", "type", StringType.class, false), PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { - State state = getTextState(s, dmd, phases, MISSING_PHASE_TEXT_PREFIX); + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getTextState(s, dmd, translationProvider, phases, MISSING_PHASE_TEXT_PREFIX, + MIELE_OVEN_TEXT_PREFIX); if (state != null) { return state; } - return super.getState(s, dmd); + return super.getState(s, dmd, translationProvider); } }, PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false), START_TIME("startTime", "start", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -81,7 +89,7 @@ public State getState(String s, DeviceMetaData dmd) { }, DURATION("duration", "duration", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -95,7 +103,7 @@ public State getState(String s, DeviceMetaData dmd) { }, ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -109,7 +117,7 @@ public State getState(String s, DeviceMetaData dmd) { }, FINISH_TIME("finishTime", "finish", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -123,32 +131,32 @@ public State getState(String s, DeviceMetaData dmd) { }, TARGET_TEMP("targetTemperature", "target", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, MEASURED_TEMP("measuredTemperature", "measured", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, DEVICE_TEMP_ONE("deviceTemperature1", "temp1", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, DEVICE_TEMP_TWO("deviceTemperature2", "temp2", QuantityType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getTemperatureState(s); } }, DOOR("signalDoor", "door", OpenClosedType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("OPEN"); } @@ -165,9 +173,9 @@ public State getState(String s, DeviceMetaData dmd) { private final Logger logger = LoggerFactory.getLogger(OvenChannelSelector.class); - private static final Map phases = Map.ofEntries(entry("1", "Heating"), entry("2", "Temp. hold"), - entry("3", "Door Open"), entry("4", "Pyrolysis"), entry("7", "Lighting"), entry("8", "Searing phase"), - entry("10", "Defrost"), entry("11", "Cooling down"), entry("12", "Energy save phase")); + private static final Map phases = Map.ofEntries(entry("1", "heating"), entry("2", "temp-hold"), + entry("3", "door-open"), entry("4", "pyrolysis"), entry("7", "lighting"), entry("8", "searing-phase"), + entry("10", "defrost"), entry("11", "cooling-down"), entry("12", "energy-save-phase")); private final String mieleID; private final String channelID; @@ -206,10 +214,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -245,34 +258,4 @@ public State getTemperatureState(String s) { return UnDefType.UNDEF; } } - - public State getTextState(String s, DeviceMetaData dmd, Map valueMap, String prefix) { - if ("0".equals(s)) { - return UnDefType.UNDEF; - } - - if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) { - String text = valueMap.get(s); - if (text != null) { - return getState(text); - } - if (dmd == null || dmd.LocalizedValue == null) { - return getState(prefix + s); - } - } - - return null; - } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenHandler.java index 13799659e9ad3..8f3275b26159c 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID; import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_OVEN; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -38,8 +40,8 @@ public class OvenHandler extends MieleApplianceHandler { private final Logger logger = LoggerFactory.getLogger(OvenHandler.class); - public OvenHandler(Thing thing) { - super(thing, OvenChannelSelector.class, MIELE_DEVICE_CLASS_OVEN); + public OvenHandler(Thing thing, TranslationProvider i18nProvider, LocaleProvider localeProvider) { + super(thing, i18nProvider, localeProvider, OvenChannelSelector.class, MIELE_DEVICE_CLASS_OVEN); } @Override diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerChannelSelector.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerChannelSelector.java index 1a375da9e4447..b17761cfcc2d7 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerChannelSelector.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerChannelSelector.java @@ -19,10 +19,11 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; -import java.util.Map.Entry; import java.util.TimeZone; -import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceMetaData; +import org.openhab.binding.miele.internal.DeviceUtil; +import org.openhab.binding.miele.internal.MieleTranslationProvider; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; @@ -34,8 +35,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonElement; - /** * The {@link ApplianceChannelSelector} for tumble dryers * @@ -47,34 +46,45 @@ public enum TumbleDryerChannelSelector implements ApplianceChannelSelector { PRODUCT_TYPE("productTypeId", "productType", StringType.class, true), DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true), - STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false), + STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) { + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getStateTextState(s, dmd, translationProvider); + if (state != null) { + return state; + } + return super.getState(s, dmd, translationProvider); + } + }, STATE(null, STATE_CHANNEL_ID, DecimalType.class, false), PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { - State state = getTextState(s, dmd, programs, MISSING_PROGRAM_TEXT_PREFIX); + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getTextState(s, dmd, translationProvider, programs, MISSING_PROGRAM_TEXT_PREFIX, + MIELE_TUMBLE_DRYER_TEXT_PREFIX); if (state != null) { return state; } - return super.getState(s, dmd); + return super.getState(s, dmd, translationProvider); } }, PROGRAM(null, PROGRAM_CHANNEL_ID, DecimalType.class, false), PROGRAMTYPE("programType", "type", StringType.class, false), PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { - State state = getTextState(s, dmd, phases, MISSING_PHASE_TEXT_PREFIX); + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + State state = DeviceUtil.getTextState(s, dmd, translationProvider, phases, MISSING_PHASE_TEXT_PREFIX, + MIELE_TUMBLE_DRYER_TEXT_PREFIX); if (state != null) { return state; } - return super.getState(s, dmd); + return super.getState(s, dmd, translationProvider); } }, PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false), START_TIME("startTime", "start", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -88,7 +98,7 @@ public State getState(String s, DeviceMetaData dmd) { }, DURATION("duration", "duration", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -102,7 +112,7 @@ public State getState(String s, DeviceMetaData dmd) { }, ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -116,7 +126,7 @@ public State getState(String s, DeviceMetaData dmd) { }, FINISH_TIME("finishTime", "finish", DateTimeType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { Date date = new Date(); SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); @@ -130,14 +140,14 @@ public State getState(String s, DeviceMetaData dmd) { }, DRYING_STEP("dryingStep", "step", DecimalType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { return getState(s); } }, DOOR("signalDoor", "door", OpenClosedType.class, false) { @Override - public State getState(String s, DeviceMetaData dmd) { + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { if ("true".equals(s)) { return getState("OPEN"); } @@ -153,20 +163,20 @@ public State getState(String s, DeviceMetaData dmd) { private final Logger logger = LoggerFactory.getLogger(TumbleDryerChannelSelector.class); - private static final Map programs = Map.ofEntries(entry("10", "Automatic Plus"), - entry("23", "Cottons hygiene"), entry("30", "Minimum iron"), entry("31", "Gentle minimum iron"), - entry("40", "Woollens handcare"), entry("50", "Delicates"), entry("60", "Warm Air"), - entry("70", "Cool air"), entry("80", "Express"), entry("90", "Cottons"), entry("100", "Gentle smoothing"), - entry("120", "Proofing"), entry("130", "Denim"), entry("131", "Gentle denim"), entry("140", "Shirts"), - entry("141", "Gentle shirts"), entry("150", "Sportswear"), entry("160", "Outerwear"), - entry("170", "Silks handcare"), entry("190", "Standard pillows"), entry("220", "Basket programme"), - entry("240", "Smoothing"), entry("65000", "Cottons, auto load control"), - entry("65001", "Minimum iron, auto load control")); - - private static final Map phases = Map.ofEntries(entry("1", "Programme running"), - entry("2", "Drying"), entry("3", "Drying Machine iron"), entry("4", "Drying Hand iron"), - entry("5", "Drying Normal"), entry("6", "Drying Normal+"), entry("7", "Cooling down"), - entry("8", "Drying Hand iron"), entry("10", "Finished")); + private static final Map programs = Map.ofEntries(entry("10", "automatic-plus"), + entry("20", "cottons"), entry("23", "cottons-hygiene"), entry("30", "minimum-iron"), + entry("31", "gentle-minimum-iron"), entry("40", "woollens-handcare"), entry("50", "delicates"), + entry("60", "warm-air"), entry("70", "cool-air"), entry("80", "express"), entry("90", "cottons-eco"), + entry("100", "gentle-smoothing"), entry("120", "proofing"), entry("130", "denim"), + entry("131", "gentle-denim"), entry("140", "shirts"), entry("141", "gentle-shirts"), + entry("150", "sportswear"), entry("160", "outerwear"), entry("170", "silks-handcare"), + entry("190", "standard-pillows"), entry("220", "basket-programme"), entry("240", "smoothing"), + entry("65000", "cottons-auto-load-control"), entry("65001", "minimum-iron-auto-load-control")); + + private static final Map phases = Map.ofEntries(entry("1", "programme-running"), + entry("2", "drying"), entry("3", "drying-machine-iron"), entry("4", "drying-hand-iron"), + entry("5", "drying-normal"), entry("6", "drying-normal-plus"), entry("7", "cooling-down"), + entry("8", "drying-hand-iron"), entry("10", "finished")); private final String mieleID; private final String channelID; @@ -206,10 +216,15 @@ public boolean isExtendedState() { return false; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -236,34 +251,4 @@ public State getState(String s) { return null; } - - public State getTextState(String s, DeviceMetaData dmd, Map valueMap, String prefix) { - if ("0".equals(s)) { - return UnDefType.UNDEF; - } - - if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) { - String text = valueMap.get(s); - if (text != null) { - return getState(text); - } - if (dmd == null || dmd.LocalizedValue == null) { - return getState(prefix + s); - } - } - - return null; - } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerHandler.java index 7e56d6381fc5e..e6482af4cfef0 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerHandler.java @@ -15,6 +15,8 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID; import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_TUMBLE_DRYER; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -38,8 +40,8 @@ public class TumbleDryerHandler extends MieleApplianceHandler programs = Map.ofEntries(entry("1", "Cottons"), entry("3", "Minimum iron"), - entry("4", "Delicates"), entry("8", "Woollens"), entry("9", "Silks"), entry("17", "Starch"), - entry("18", "Rinse"), entry("21", "Drain/Spin"), entry("22", "Curtains"), entry("23", "Shirts"), - entry("24", "Denim"), entry("27", "Proofing"), entry("29", "Sportswear"), entry("31", "Automatic Plus"), - entry("37", "Outerwear"), entry("39", "Pillows"), entry("50", "Dark Garments"), entry("53", "First wash"), - entry("75", "Steam care"), entry("76", "Freshen up"), entry("91", "Maintenance wash"), - entry("95", "Down duvets"), entry("122", "Express 20"), entry("129", "Down filled items"), - entry("133", "Cottons Eco"), entry("146", "QuickPowerWash"), entry("65532", "Mix")); + private static final Map programs = Map.ofEntries(entry("1", "cottons"), entry("3", "minimum-iron"), + entry("4", "delicates"), entry("8", "woollens"), entry("9", "silks"), entry("17", "starch"), + entry("18", "rinse"), entry("21", "drain-spin"), entry("22", "curtains"), entry("23", "shirts"), + entry("24", "denim"), entry("27", "proofing"), entry("29", "sportswear"), entry("31", "automatic-plus"), + entry("37", "outerwear"), entry("39", "pillows"), entry("50", "dark-garments"), entry("53", "first-wash"), + entry("75", "steam-care"), entry("76", "freshen-up"), entry("91", "maintenance-wash"), + entry("95", "down-duvets"), entry("122", "express-20"), entry("129", "down-filled-items"), + entry("133", "cottons-eco"), entry("146", "quickpowerwash"), entry("65532", "mix")); - private static final Map phases = Map.ofEntries(entry("1", "Pre-wash"), entry("4", "Washing"), - entry("5", "Rinses"), entry("7", "Clean"), entry("9", "Drain"), entry("10", "Spin"), - entry("11", "Anti-crease"), entry("12", "Finished")); + private static final Map phases = Map.ofEntries(entry("1", "pre-wash"), entry("4", "washing"), + entry("5", "rinses"), entry("7", "clean"), entry("9", "drain"), entry("10", "spin"), + entry("11", "anti-crease"), entry("12", "finished")); private final String mieleID; private final String channelID; @@ -224,10 +233,15 @@ public boolean isExtendedState() { return isExtendedState; } + @Override + public State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) { + return this.getState(s, dmd); + } + @Override public State getState(String s, DeviceMetaData dmd) { if (dmd != null) { - String localizedValue = getMieleEnum(s, dmd); + String localizedValue = dmd.getMieleEnum(s); if (localizedValue == null) { localizedValue = dmd.LocalizedValue; } @@ -263,34 +277,4 @@ public State getTemperatureState(String s) { return UnDefType.UNDEF; } } - - public State getTextState(String s, DeviceMetaData dmd, Map valueMap, String prefix) { - if ("0".equals(s)) { - return UnDefType.UNDEF; - } - - if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) { - String text = valueMap.get(s); - if (text != null) { - return getState(text); - } - if (dmd == null || dmd.LocalizedValue == null) { - return getState(prefix + s); - } - } - - return null; - } - - public String getMieleEnum(String s, DeviceMetaData dmd) { - if (dmd.MieleEnum != null) { - for (Entry enumEntry : dmd.MieleEnum.entrySet()) { - if (enumEntry.getValue().getAsString().trim().equals(s.trim())) { - return enumEntry.getKey(); - } - } - } - - return null; - } } diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineHandler.java index 4c330cb07bc82..e5b3cd9c7821b 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineHandler.java @@ -19,6 +19,8 @@ import java.math.BigDecimal; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.unit.Units; @@ -49,8 +51,9 @@ public class WashingMachineHandler extends MieleApplianceHandler - Temperature of the selected program + Temperature of the selected program (10 °C = cold) diff --git a/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/xgw3000.xml b/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/xgw3000.xml index 58d9ca23cbac4..2063c0d4149da 100644 --- a/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/xgw3000.xml +++ b/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/xgw3000.xml @@ -38,6 +38,10 @@ Password for the registered Miele@home user. + + + Language for state, program and phase texts. Leave blank for system language. + diff --git a/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java b/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java index d159dd5416f90..61599c5d60573 100644 --- a/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java +++ b/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java @@ -13,6 +13,8 @@ package org.openhab.binding.miele.internal; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; import org.openhab.core.library.types.QuantityType; @@ -58,6 +60,11 @@ public void getTemperatureStateMagicValueReturnsUndefined() throws NumberFormatE assertEquals(UnDefType.UNDEF, DeviceUtil.getTemperatureState("32768")); } + @Test + public void getTemperatureStateColdValueReturns10Degrees() throws NumberFormatException { + assertEquals(new QuantityType<>(10, SIUnits.CELSIUS), DeviceUtil.getTemperatureState("-32760")); + } + @Test public void getTemperatureStateNonNumericValueThrowsNumberFormatException() { assertThrows(NumberFormatException.class, () -> DeviceUtil.getTemperatureState("A")); @@ -67,4 +74,28 @@ public void getTemperatureStateNonNumericValueThrowsNumberFormatException() { public void getTemperatureStateNullValueThrowsNumberFormatException() { assertThrows(NumberFormatException.class, () -> DeviceUtil.getTemperatureState(null)); } + + @Test + public void getStateTextStateProviderHasPrecedence() { + assertEquals("I brug", this.getStateTextState("5", "Running", "miele.state.running", "I brug")); + } + + @Test + public void getStateTextStateGatewayTextIsReturnedWhenKeyIsUnknown() { + assertEquals("Running", this.getStateTextState("-1", "Running", "key.unknown", "I brug")); + } + + @Test + public void getStateTextStateKeyIsReturnedWhenUnknownByGatewayAndProvider() { + assertEquals("state.99", this.getStateTextState("99", null, "key.unknown", "I brug")); + } + + private String getStateTextState(String value, String localizedValue, String mockedKey, String mockedValue) { + var metaData = new DeviceMetaData(); + metaData.LocalizedValue = localizedValue; + var translationProvider = mock(MieleTranslationProvider.class); + when(translationProvider.getText(mockedKey, metaData.LocalizedValue)).thenReturn(mockedValue); + + return DeviceUtil.getStateTextState(value, metaData, translationProvider).toString(); + } } From d5d2694ce9e61e4925b4f2d892f1af2f24d37a17 Mon Sep 17 00:00:00 2001 From: Florian Hotze Date: Mon, 29 Nov 2021 09:44:26 +0100 Subject: [PATCH 146/361] [jsscripting] Improve docs with Actions (#11624) Updated the documentation with: * Core Actions * Cloud Notification Actions * Persistence Extensions * Ephemeris Actions * Types and Units Instead of the single "imports", the default scope (openhab-core/DefaultScriptScopeProvider.java) is used. It's imported as `openhab`, services are under `openhab.service`. As the helper library is on the way (openhab/openhab-js): * Added note about console.log and logging in general. * Added note that the lib is on the way. Signed-off-by: Florian Hotze Signed-off-by: Michael Schmidt --- .../README.md | 225 +++++++++++++++++- 1 file changed, 216 insertions(+), 9 deletions(-) diff --git a/bundles/org.openhab.automation.jsscripting/README.md b/bundles/org.openhab.automation.jsscripting/README.md index 23b1dcd9bd128..77ae84528f03b 100644 --- a/bundles/org.openhab.automation.jsscripting/README.md +++ b/bundles/org.openhab.automation.jsscripting/README.md @@ -1,6 +1,21 @@ # JavaScript Scripting This add-on provides support for JavaScript (ECMAScript 2021+) that can be used as a scripting language within automation rules. +JavaScript scripts provide access to almost all the functionality in an openHAB runtime environment. + +- [Creating JavaScript Scripts](#creating-javascript-scripts) +- [Logging](#logging) +- [Core Actions](#core-actions) + - [itemRegistry](#itemregistry) + - [Event Bus Actions](#event-bus-actions) + - [Exec Actions](#exec-actions) + - [HTTP Actions](#http-actions) + - [Timers](#timers) + - [Scripts Actions](#scripts-actions) +- [Cloud Notification Actions](#cloud-notification-actions) +- [Persistence Extensions](#persistence-extensions) +- [Ephemeris Actions](#ephemeris-actions) +- [Types and Units](#types-and-units) ## Creating JavaScript Scripts @@ -21,23 +36,215 @@ log:set DEBUG org.openhab.core.automation For more information on the available APIs in scripts see the [JSR223 Scripting]({{base}}/configuration/jsr223.html) documentation. -## Script Examples +The following examples show how to access common openHAB functionalities. + +## Logging -JavaScript scripts provide access to almost all the functionality in an openHAB runtime environment. As a simple example, the following script logs "Hello, World!". Note that `console.log` will usually not work since the output has no terminal to display the text. +__Please note:__ Support for `console.log` will likely be added together with a logging API in the [helper library](https://github.com/openhab/openhab-js). The openHAB server uses the [SLF4J](https://www.slf4j.org/) library for logging. -```js -const LoggerFactory = Java.type('org.slf4j.LoggerFactory'); - -LoggerFactory.getLogger("org.openhab.core.automation.examples").info("Hello world!"); +```javascript +let logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + this.ruleUID); +logger.info('Hello world!'); +logger.warn('Successfully logged warning.'); +logger.error('Successfully logged error.'); ``` -Depending on the openHAB logging configuration, you may need to prefix logger names with `org.openhab.core.automation` for them to show up in the log file (or you modify the logging configuration). - The script uses the [LoggerFactory](https://www.slf4j.org/apidocs/org/slf4j/Logger.html) to obtain a named logger and then logs a message like: ```text - ... [INFO ] [.openhab.core.automation.examples:-2 ] - Hello world! + ... [INFO ] [org.openhab.rule. ] - Hello world! + ... [WARN ] [org.openhab.rule. ] - Successfully logged warning. + ... [ERROR] [org.openhab.rule. ] - Successfully logged error. +``` + +## Core Actions + +The openHAB services, which are pre-included in the integrated JavaScript engine, must explicitely be imported. + +__Please note:__ The [helper library](https://github.com/openhab/openhab-js) is on the way and will become the preferred API to work with openHAB. + +```javascript +let openhab = require('@runtime'); +``` + +### itemRegistry + +```javascript +let state = openhab.itemRegistry.getItem(itemName).getState(); +``` + +You can use `toString()` to convert an item's state to string or `toBigDecimal()` to convert to number. + +### Event Bus Actions + +```javascript +openhab.events.sendCommand(itemName, command); +openhab.events.postUpdate(itemName, state); +``` + +`command` and `state` can be a string `'string'` or a number depending on the item. + +### Exec Actions + +Execute a command line. + +```javascript +openhab.Exec = Java.type('org.openhab.core.model.script.actions.Exec'); +let Duration = Java.type('java.time.Duration'); + +// Execute command line. +openhab.Exec.executeCommandLine('echo', 'Hello World!'); + +// Execute command line with timeout. +openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); + +// Get response from command line. +let response = openhab.Exec.executeCommandLine('echo', 'Hello World!'); + +// Get response from command line with timeout. +response = openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); +``` + +### HTTP Actions + +For available actions have a look at the [HTTP Actions Docs](https://www.openhab.org/docs/configuration/actions.html#http-actions). + +```javascript +openhab.HTTP = Java.type('org.openhab.core.model.script.actions.HTTP'); + +// Example GET Request +var response = openhab.HTTP.sendHttpGetRequest(''); +``` + +Replace `` with the request url. + +### Timers + +```javascript +let ZonedDateTime = Java.type('java.time.ZonedDateTime'); +let now = ZonedDateTime.now(); +openhab.ScriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution'); + +// Function to run when the timer goes off. +function timerOver () { + logger.info('The timer is over.'); +} + +// Create the Timer. +this.myTimer = openhab.ScriptExecution.createTimer(now.plusSeconds(10), timerOver); + +// Cancel the timer. +this.myTimer.cancel(); + +// Check whether the timer is active. Returns true if the timer is active and will be executed as scheduled. +let active = this.myTimer.isActive(); + +// Reschedule the timer. +this.myTimer.reschedule(now.plusSeconds(5)); +``` + +### Scripts Actions + +Call scripts created in the UI (Settings -> Scripts) with or without parameters. + +```javascript +openhab.scriptExtension = Java.type('org.openhab.core.automation.module.script.ScriptExtensionProvider'); +let bundleContext = Java.type('org.osgi.framework.FrameworkUtil').getBundle(openhab.scriptExtension.class).getBundleContext(); +openhab.RuleManager = bundleContext.getService(bundleContext.getServiceReference('org.openhab.core.automation.RuleManager')); + +// Simple call. +openhab.RuleManager.runNow(''); + +// Advanced call with arguments. +let map = new java.util.HashMap(); +map.put('identifier1', 'value1'); +map.put('identifier2', 'value2'); +// Second argument is whether to consider the conditions, third is a Map (a way to pass data). +openhab.RuleManager.runNow('', true, map); +``` + +Replace `` with your script's (unique-)id. + +## Cloud Notification Actions + +Notification actions may be placed in Rules to send alerts to mobile devices registered with an [openHAB Cloud instance](https://github.com/openhab/openhab-cloud) such as [myopenHAB.org](https://myopenhab.org/). + +For available actions have a look at the [Cloud Notification Actions Docs](https://www.openhab.org/docs/configuration/actions.html#cloud-notification-actions). + +```javascript +openhab.NotificationAction = Java.type('org.openhab.io.openhabcloud.NotificationAction') + +// Example +openhab.NotificationAction.sendNotification('', ''); // to a single myopenHAB user identified by e-mail +openhab.NotificationAction.sendBroadcastNotification(''); // to all myopenHAB users +``` + +Replace `` with the e-mail address of the user. +Replace `` with the notification text. + +## Persistence Extensions + +For available commands have a look at [Persistence Extensions in Scripts ans Rules](https://www.openhab.org/docs/configuration/persistence.html#persistence-extensions-in-scripts-and-rules). + +For deeper information have a look at the [Persistence Extensions JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/persistence/extensions/persistenceextensions). + +```javascript +openhab.PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions'); +let ZonedDateTime = Java.type('java.time.ZonedDateTime'); +let now = ZonedDateTime.now(); + +// Example +var avg = openhab.PersistenceExtensions.averageSince(itemRegistry.getItem(''), now.minusMinutes(5), "influxdb"); ``` + +Replace `` with the persistence service to use. +Replace `` with the itemname. + +## Ephemeris Actions + +Ephemeris is a way to determine what type of day today or a number of days before or after today is. For example, a way to determine if today is a weekend, a bank holiday, someone’s birthday, trash day, etc. + +For available actions, have a look at the [Ephemeris Actions Docs](https://www.openhab.org/docs/configuration/actions.html#ephemeris). + +For deeper information have a look at the [Ephemeris JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris). + +```javascript +openhab.Ephemeris = Java.type('org.openhab.core.model.script.actions.Ephemeris'); + +// Example +let weekend = openhab.Ephemeris.isWeekend(); +``` + +## Types and Units + +Import types from openHAB Core for type conversion and more. +Import Units from openHAB Core for unit conversion and more. + +```javascript +openhab.typeOrUnit = Java.type('org.openhab.core.library.types.typeOrUnit'); + +// Example +openhab.HSBType = Java.type('org.openhab.core.library.types.HSBType'); +let hsb = openhab.HSBType.fromRGB(4, 6, 9); +``` + +Available types are: +* `QuantityType` +* `StringListType` +* `RawType` +* `DateTimeType` +* `DecimalType` +* `HSBType` +* `PercentType` +* `PointType` +* `StringType` + +Available untis are: +* `SIUnits` +* `ImperialUnits` +* `MetricPrefix` +* `Units` +* `BinaryPrefix` From b544e1c8e953086aaa7648ed1d535b3321111409 Mon Sep 17 00:00:00 2001 From: paphko Date: Mon, 29 Nov 2021 09:45:29 +0100 Subject: [PATCH 147/361] [anel] Initial contribution of the Anel NET-PwrCtrl binding for OH3 (#10952) * Initial contribution of the Anel NET-PwrCtrl binding for OH3. Signed-off-by: Patrick Koenemann * Adjustments based on code review. Signed-off-by: Patrick Koenemann * Further adjustments according to second review. Signed-off-by: Patrick Koenemann * Checkstyle warnings revmoed. Signed-off-by: Patrick Koenemann Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + bundles/org.openhab.binding.anel/NOTICE | 13 + bundles/org.openhab.binding.anel/README.md | 231 ++++++++++++ bundles/org.openhab.binding.anel/pom.xml | 17 + .../src/main/feature/feature.xml | 9 + .../anel/internal/AnelConfiguration.java | 67 ++++ .../binding/anel/internal/AnelHandler.java | 356 ++++++++++++++++++ .../anel/internal/AnelHandlerFactory.java | 48 +++ .../anel/internal/AnelUdpConnector.java | 263 +++++++++++++ .../binding/anel/internal/IAnelConstants.java | 123 ++++++ .../internal/auth/AnelAuthentication.java | 98 +++++ .../discovery/AnelDiscoveryService.java | 210 +++++++++++ .../internal/state/AnelCommandHandler.java | 116 ++++++ .../anel/internal/state/AnelState.java | 308 +++++++++++++++ .../anel/internal/state/AnelStateUpdater.java | 216 +++++++++++ .../main/resources/OH-INF/binding/binding.xml | 9 + .../main/resources/OH-INF/config/config.xml | 39 ++ .../resources/OH-INF/thing/thing-types.xml | 201 ++++++++++ .../anel/internal/AnelAuthenticationTest.java | 94 +++++ .../anel/internal/AnelCommandHandlerTest.java | 179 +++++++++ .../binding/anel/internal/AnelStateTest.java | 185 +++++++++ .../anel/internal/AnelStateUpdaterTest.java | 142 +++++++ .../anel/internal/AnelUdpConnectorTest.java | 185 +++++++++ .../anel/internal/IAnelTestStatus.java | 47 +++ bundles/pom.xml | 1 + 26 files changed, 3163 insertions(+) create mode 100644 bundles/org.openhab.binding.anel/NOTICE create mode 100644 bundles/org.openhab.binding.anel/README.md create mode 100644 bundles/org.openhab.binding.anel/pom.xml create mode 100644 bundles/org.openhab.binding.anel/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelCommandHandler.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java create mode 100644 bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java create mode 100644 bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.anel/src/main/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelCommandHandlerTest.java create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelUdpConnectorTest.java create mode 100644 bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/IAnelTestStatus.java diff --git a/CODEOWNERS b/CODEOWNERS index 01218617ee8e9..8083097c0b57a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -23,6 +23,7 @@ /bundles/org.openhab.binding.ambientweather/ @mhilbush /bundles/org.openhab.binding.amplipi/ @kaikreuzer /bundles/org.openhab.binding.androiddebugbridge/ @GiviMAD +/bundles/org.openhab.binding.anel/ @paphko /bundles/org.openhab.binding.astro/ @gerrieg /bundles/org.openhab.binding.atlona/ @tmrobert8 /bundles/org.openhab.binding.autelis/ @digitaldan diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index e66376115f29d..55e21c009e719 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -106,6 +106,11 @@ org.openhab.binding.androiddebugbridge ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.anel + ${project.version} + org.openhab.addons.bundles org.openhab.binding.astro diff --git a/bundles/org.openhab.binding.anel/NOTICE b/bundles/org.openhab.binding.anel/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.anel/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/openhab-addons diff --git a/bundles/org.openhab.binding.anel/README.md b/bundles/org.openhab.binding.anel/README.md new file mode 100644 index 0000000000000..e2189cb5c8f1a --- /dev/null +++ b/bundles/org.openhab.binding.anel/README.md @@ -0,0 +1,231 @@ +# Anel NET-PwrCtrl Binding + +Monitor and control Anel NET-PwrCtrl devices. + +NET-PwrCtrl devices are power sockets / relays that can be configured via browser but they can also be controlled over the network, e.g. with an Android or iPhone app - and also with openHAB via this binding. +Some NET-PwrCtrl devices also have 8 I/O ports which can either be used to directly switch the sockets / relays, or they can be used as general input / output switches in openHAB. + + +## Supported Things + +There are three kinds of devices ([overview on manufacturer's homepage](https://en.anel.eu/?src=/produkte/produkte.htm)): + +| [Anel NET-PwrCtrl HUT](https://en.anel.eu/?src=/produkte/hut_2/hut_2.htm)
( _advanced-firmware_ ) | [Anel NET-PwrCtrl IO](https://en.anel.eu/?src=/produkte/io/io.htm)
( _advanced-firmware_ ) | [Anel NET-PwrCtrl HOME](https://de.anel.eu/?src=produkte/home/home.htm)
( _home_ )
(only German version) | +| --- | --- | --- | +| [![Anel NET-PwrCtrl HUT 2](https://de.anel.eu/image/leisten/HUT2LV-P_500.jpg)](https://de.anel.eu/?src=produkte/hut_2/hut_2.htm) | [![Anel NET-PwrCtrl IO](https://de.anel.eu/image/leisten/IO-Stecker.png)](https://de.anel.eu/?src=produkte/io/io.htm) | [![Anel NET-PwrCtrl HOME](https://de.anel.eu/image/leisten/HOME-DE-500.gif)](https://de.anel.eu/?src=produkte/home/home.htm) | + +Thing type IDs: + +* *home*: The smallest device, the _HOME_, is the only one with only three power sockets and only available in Germany. +* *simple-firmware*: The _PRO_ and _REDUNDANT_ have eight power sockets and a similar (simplified) firmware as the _HOME_. +* *advanced-firmware*: All others (_ADV_, _IO_, and the different _HUT_ variants) have eight power sockets / relays, eight IO ports, and an advanced firmware. + +An [additional sensor](https://en.anel.eu/?src=/produkte/sensor_1/sensor_1.htm) may be used for monitoring temperature, humidity, and brightness. +The sensor can be attached to a _HUT_ device via an Ethernet cable (max length is 50m). + + +## Discovery + +Devices can be discovered automatically if their UDP ports are configured as follows: + +* 75 / 77 (default) +* 750 / 770 +* 7500 / 7700 +* 7750 / 7770 + +If a device is found for a specific port (excluding the default port), the subsequent port is also scanned, e.g. 7500/7700 → 7501/7701 → 7502/7702 → etc. + +Depending on the network switch and router devices, discovery may or may not work on wireless networks. +It should work reliably though on local wired networks. + + +## Thing Configuration + +Each Thing requires the following configuration parameters. + +| Parameter | Type | Default | Required | Description | +|-----------------------|---------|-------------|----------|-------------| +| Hostname / IP address | String | net-control | yes | Hostname or IP address of the device | +| Send Port | Integer | 75 | yes | UDP port to send data to the device (in the anel web UI, it's the receive port!) | +| Receive Port | Integer | 77 | yes | UDP port to receive data from the device (in the anel web UI, it's the send port!) | +| User | String | user7 | yes | User to access the device (make sure it has rights to change relay / IO states!) | +| Password | String | anel | yes | Password of the given user | + +For multiple devices, please use exclusive UDP ports for each device. +Ports above 1024 are recommended because they are outside the range of system ports. + +Possible entries in your thing file could be (thing types _home_, _simple-firmware_, and _advanced-firmware_ are explained above in _Supported Things_): + +``` +anel:home:mydevice1 [hostname="192.168.0.101", udpSendPort=7500, udpReceivePort=7700, user="user7", password="anel"] +anel:simple-firmware:mydevice2 [hostname="192.168.0.102", udpSendPort=7501, udpReceivePort=7701, user="user7", password="anel"] +anel:advanced-firmware:mydevice3 [hostname="192.168.0.103", udpSendPort=7502, udpReceivePort=7702, user="user7", password="anel"] +anel:advanced-firmware:mydevice4 [hostname="192.168.0.104", udpSendPort=7503, udpReceivePort=7703, user="user7", password="anel"] +``` + + +## Channels + +Depending on the thing type, the following channels are available. + +| Channel ID | Item Type | Supported Things | Read Only | Description | +|--------------------|--------------------|-------------------|-----------|-------------| +| prop#name | String | all | yes | Name of the device | +| prop#temperature | Number:Temperature | simple / advanced | yes | Temperature of the integrated sensor | +| sensor#temperature | Number:Temperature | advanced | yes | Temperature of the optional external sensor | +| sensor#humidity | Number | advanced | yes | Humidity of the optional external sensor | +| sensor#brightness | Number | advanced | yes | Brightness of the optional external sensor | +| r1#name | String | all | yes | Name of relay / socket 1 | +| r2#name | String | all | yes | Name of relay / socket 2 | +| r3#name | String | all | yes | Name of relay / socket 3 | +| r4#name | String | simple / advanced | yes | Name of relay / socket 4 | +| r5#name | String | simple / advanced | yes | Name of relay / socket 5 | +| r6#name | String | simple / advanced | yes | Name of relay / socket 6 | +| r7#name | String | simple / advanced | yes | Name of relay / socket 7 | +| r8#name | String | simple / advanced | yes | Name of relay / socket 8 | +| r1#state | Switch | all | no * | State of relay / socket 1 | +| r2#state | Switch | all | no * | State of relay / socket 2 | +| r3#state | Switch | all | no * | State of relay / socket 3 | +| r4#state | Switch | simple / advanced | no * | State of relay / socket 4 | +| r5#state | Switch | simple / advanced | no * | State of relay / socket 5 | +| r6#state | Switch | simple / advanced | no * | State of relay / socket 6 | +| r7#state | Switch | simple / advanced | no * | State of relay / socket 7 | +| r8#state | Switch | simple / advanced | no * | State of relay / socket 8 | +| r1#locked | Switch | all | yes | Whether or not relay / socket 1 is locked | +| r2#locked | Switch | all | yes | Whether or not relay / socket 2 is locked | +| r3#locked | Switch | all | yes | Whether or not relay / socket 3 is locked | +| r4#locked | Switch | simple / advanced | yes | Whether or not relay / socket 4 is locked | +| r5#locked | Switch | simple / advanced | yes | Whether or not relay / socket 5 is locked | +| r6#locked | Switch | simple / advanced | yes | Whether or not relay / socket 6 is locked | +| r7#locked | Switch | simple / advanced | yes | Whether or not relay / socket 7 is locked | +| r8#locked | Switch | simple / advanced | yes | Whether or not relay / socket 8 is locked | +| io1#name | String | advanced | yes | Name of IO port 1 | +| io2#name | String | advanced | yes | Name of IO port 2 | +| io3#name | String | advanced | yes | Name of IO port 3 | +| io4#name | String | advanced | yes | Name of IO port 4 | +| io5#name | String | advanced | yes | Name of IO port 5 | +| io6#name | String | advanced | yes | Name of IO port 6 | +| io7#name | String | advanced | yes | Name of IO port 7 | +| io8#name | String | advanced | yes | Name of IO port 8 | +| io1#state | Switch | advanced | no ** | State of IO port 1 | +| io2#state | Switch | advanced | no ** | State of IO port 2 | +| io3#state | Switch | advanced | no ** | State of IO port 3 | +| io4#state | Switch | advanced | no ** | State of IO port 4 | +| io5#state | Switch | advanced | no ** | State of IO port 5 | +| io6#state | Switch | advanced | no ** | State of IO port 6 | +| io7#state | Switch | advanced | no ** | State of IO port 7 | +| io8#state | Switch | advanced | no ** | State of IO port 8 | +| io1#mode | Switch | advanced | yes | Mode of port 1: _ON_ = input, _OFF_ = output | +| io2#mode | Switch | advanced | yes | Mode of port 2: _ON_ = input, _OFF_ = output | +| io3#mode | Switch | advanced | yes | Mode of port 3: _ON_ = input, _OFF_ = output | +| io4#mode | Switch | advanced | yes | Mode of port 4: _ON_ = input, _OFF_ = output | +| io5#mode | Switch | advanced | yes | Mode of port 5: _ON_ = input, _OFF_ = output | +| io6#mode | Switch | advanced | yes | Mode of port 6: _ON_ = input, _OFF_ = output | +| io7#mode | Switch | advanced | yes | Mode of port 7: _ON_ = input, _OFF_ = output | +| io8#mode | Switch | advanced | yes | Mode of port 8: _ON_ = input, _OFF_ = output | + +\* Relay / socket state is read-only if it is locked; otherwise it is changeable.
+\** IO port state is read-only if its mode is _input_, it is changeable if its mode is _output_. + + +## Full Example + +`.things` file: + +``` +Thing anel:advanced-firmware:anel1 "Anel1" [hostname="192.168.0.100", udpSendPort=7500, udpReceivePort=7700, user="user7", password="anel"] +``` + +`.items` file: + +``` +// device properties +String anel1name "Anel1 Name" {channel="anel:advanced-firmware:anel1:prop#name"} +Number:Temperature anel1temperature "Anel1 Temperature" {channel="anel:advanced-firmware:anel1:prop#temperature"} + +// external sensor properties +Number:Temperature anel1sensorTemperature "Anel1 Sensor Temperature" {channel="anel:advanced-firmware:anel1:sensor#temperature"} +Number anel1sensorHumidity "Anel1 Sensor Humidity" {channel="anel:advanced-firmware:anel1:sensor#humidity"} +Number anel1sensorBrightness "Anel1 Sensor Brightness" {channel="anel:advanced-firmware:anel1:sensor#brightness"} + +// relay names and states +String anel1relay1name "Anel1 Relay1 name" {channel="anel:advanced-firmware:anel1:r1#name"} +Switch anel1relay1locked "Anel1 Relay1 locked" {channel="anel:advanced-firmware:anel1:r1#locked"} +Switch anel1relay1state "Anel1 Relay1" {channel="anel:advanced-firmware:anel1:r1#state"} +Switch anel1relay2state "Anel1 Relay2" {channel="anel:advanced-firmware:anel1:r2#state"} +Switch anel1relay3state "Anel1 Relay3" {channel="anel:advanced-firmware:anel1:r3#state"} +Switch anel1relay4state "Anel1 Relay4" {channel="anel:advanced-firmware:anel1:r4#state"} +Switch anel1relay5state "Light Bedroom" {channel="anel:advanced-firmware:anel1:r5#state"} +Switch anel1relay6state "Doorbell" {channel="anel:advanced-firmware:anel1:r6#state"} +Switch anel1relay7state "Socket TV" {channel="anel:advanced-firmware:anel1:r7#state"} +Switch anel1relay8state "Socket Terrace" {channel="anel:advanced-firmware:anel1:r8#state"} + +// IO port names and states +String anel1io1name "Anel1 IO1 name" {channel="anel:advanced-firmware:anel1:io1#name"} +Switch anel1io1mode "Anel1 IO1 mode" {channel="anel:advanced-firmware:anel1:io1#mode"} +Switch anel1io1state "Anel1 IO1" {channel="anel:advanced-firmware:anel1:io1#state"} +Switch anel1io2state "Anel1 IO2" {channel="anel:advanced-firmware:anel1:io2#state"} +Switch anel1io3state "Anel1 IO3" {channel="anel:advanced-firmware:anel1:io3#state"} +Switch anel1io4state "Anel1 IO4" {channel="anel:advanced-firmware:anel1:io4#state"} +Switch anel1io5state "Switch Bedroom" {channel="anel:advanced-firmware:anel1:io5#state"} +Switch anel1io6state "Doorbell" {channel="anel:advanced-firmware:anel1:io6#state"} +Switch anel1io7state "Switch Office" {channel="anel:advanced-firmware:anel1:io7#state"} +Switch anel1io8state "Reed Contact Door" {channel="anel:advanced-firmware:anel1:io8#state"} +``` + +`.sitemap` file: + +``` +sitemap anel label="Anel NET-PwrCtrl" { + Frame label="Device and Sensor" { + Text item=anel1name label="Anel1 Name" + Text item=anel1temperature label="Anel1 Temperature [%.1f °C]" + Text item=anel1sensorTemperature label="Anel1 Sensor Temperature [%.1f °C]" + Text item=anel1sensorHumidity label="Anel1 Sensor Humidity [%.1f]" + Text item=anel1sensorBrightness label="Anel1 Sensor Brightness [%.1f]" + } + Frame label="Relays" { + Text item=anel1relay1name label="Relay 1 name" labelcolor=[anel1relay1locked==ON="green",anel1relay1locked==OFF="maroon"] + Switch item=anel1relay1state + Switch item=anel1relay2state + Switch item=anel1relay3state + Switch item=anel1relay4state + Switch item=anel1relay5state + Switch item=anel1relay6state + Switch item=anel1relay7state + Switch item=anel1relay8state + } + Frame label="IO Ports" { + Text item=anel1io1name label="IO 1 name" labelcolor=[anel1io1mode==OFF="green",anel1io1mode==ON="maroon"] + Switch item=anel1io1state + Switch item=anel1io2state + Switch item=anel1io3state + Switch item=anel1io4state + Switch item=anel1io5state + Switch item=anel1io6state + Switch item=anel1io7state + Switch item=anel1io8state + } +} +``` + +The relay / IO port names are rarely useful because you probably set similar (static) labels for the state items.
+The locked state / IO mode is also rarely relevant in practice, because it typically doesn't change. + +`.rules` file: + +``` +rule "doorbell only at daytime" +when Item anel1io6state changed then + if (now.getHoursOfDay >= 6 && now.getHoursOfDay <= 22) { + anel1relay6state.sendCommand(if (anel1io6state.state != ON) ON else OFF) + } + someNotificationItem.sendCommand("Someone just rang the doorbell") +end +``` + + +## Reference Documentation + +The UDP protocol of Anel devices is explained [here](https://forum.anel.eu/viewtopic.php?f=16&t=207). + diff --git a/bundles/org.openhab.binding.anel/pom.xml b/bundles/org.openhab.binding.anel/pom.xml new file mode 100644 index 0000000000000..325a69c4de77e --- /dev/null +++ b/bundles/org.openhab.binding.anel/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.anel + + openHAB Add-ons :: Bundles :: Anel Binding + + diff --git a/bundles/org.openhab.binding.anel/src/main/feature/feature.xml b/bundles/org.openhab.binding.anel/src/main/feature/feature.xml new file mode 100644 index 0000000000000..a4b8497ba31d7 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.anel/${project.version} + + diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java new file mode 100644 index 0000000000000..a30f77f3dc9b6 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelConfiguration.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link AnelConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelConfiguration { + + public @Nullable String hostname; + public @Nullable String user; + public @Nullable String password; + /** Port to send data from openhab to device. */ + public int udpSendPort = IAnelConstants.DEFAULT_SEND_PORT; + /** Openhab receives messages via this port from device. */ + public int udpReceivePort = IAnelConstants.DEFAULT_RECEIVE_PORT; + + public AnelConfiguration() { + } + + public AnelConfiguration(@Nullable String hostname, @Nullable String user, @Nullable String password, int sendPort, + int receivePort) { + this.hostname = hostname; + this.user = user; + this.password = password; + this.udpSendPort = sendPort; + this.udpReceivePort = receivePort; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append("[hostname="); + builder.append(hostname); + builder.append(",user="); + builder.append(user); + builder.append(",password="); + builder.append(mask(password)); + builder.append(",udpSendPort="); + builder.append(udpSendPort); + builder.append(",udpReceivePort="); + builder.append(udpReceivePort); + builder.append("]"); + return builder.toString(); + } + + private @Nullable String mask(@Nullable String string) { + return string == null ? null : string.replaceAll(".", "X"); + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java new file mode 100644 index 0000000000000..8abc5c580eb67 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandler.java @@ -0,0 +1,356 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.anel.internal.auth.AnelAuthentication; +import org.openhab.binding.anel.internal.auth.AnelAuthentication.AuthMethod; +import org.openhab.binding.anel.internal.state.AnelCommandHandler; +import org.openhab.binding.anel.internal.state.AnelState; +import org.openhab.binding.anel.internal.state.AnelStateUpdater; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link AnelHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(AnelHandler.class); + + private final AnelCommandHandler commandHandler = new AnelCommandHandler(); + private final AnelStateUpdater stateUpdater = new AnelStateUpdater(); + + private @Nullable AnelConfiguration config; + private @Nullable AnelUdpConnector udpConnector; + + /** The most recent state of the Anel device. */ + private @Nullable AnelState state; + /** Cached authentication information (encrypted, if possible). */ + private @Nullable String authentication; + + private @Nullable ScheduledFuture periodicRefreshTask; + + private int sendingFailures = 0; + private int updateStateFailures = 0; + private int refreshRequestWithoutResponse = 0; + private boolean refreshRequested = false; // avoid multiple simultaneous refresh requests + + public AnelHandler(Thing thing) { + super(thing); + } + + @Override + public void initialize() { + config = getConfigAs(AnelConfiguration.class); + + updateStatus(ThingStatus.UNKNOWN); + + // background initialization + scheduler.execute(this::initializeConnection); + } + + private void initializeConnection() { + final AnelConfiguration config2 = config; + final String host = config2 == null ? null : config2.hostname; + if (config2 == null || host == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "Cannot initialize thing without configuration: " + config2); + return; + } + try { + final AnelUdpConnector newUdpConnector = new AnelUdpConnector(host, config2.udpReceivePort, + config2.udpSendPort, scheduler); + udpConnector = newUdpConnector; + + // establish connection and register listener + newUdpConnector.connect(this::handleStatusUpdate, true); + + // request initial state, 3 attempts + for (int attempt = 1; attempt <= IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS + && state == null; attempt++) { + try { + newUdpConnector.send(IAnelConstants.BROADCAST_DISCOVERY_MSG); + } catch (IOException e) { + // network or socket failure, also wait 2 sec and try again + } + + // answer expected within 50-600ms on a regular network; wait up to 2sec just to make sure + for (int delay = 0; delay < 10 && state == null; delay++) { + Thread.sleep(200); // wait 10 x 200ms = 2sec + } + } + + // set thing status (and set unique property) + final AnelState state2 = state; + if (state2 != null) { + updateStatus(ThingStatus.ONLINE); + + final String mac = state2.mac; + if (mac != null && !mac.isEmpty()) { + updateProperty(IAnelConstants.UNIQUE_PROPERTY_NAME, mac); + } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + "Device does not respond (check IP, ports, and network connection): " + config); + } + + // schedule refresher task to continuously check for device state + periodicRefreshTask = scheduler.scheduleWithFixedDelay(this::periodicRefresh, // + 0, IAnelConstants.REFRESH_INTERVAL_SEC, TimeUnit.SECONDS); + } catch (InterruptedException e) { + // OH shutdown - don't log anything, Framework will call dispose() + } catch (Exception e) { + logger.debug("Connection to '{}' failed", config, e); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, "Connection to '" + config + + "' failed unexpectedly with " + e.getClass().getSimpleName() + ": " + e.getMessage()); + dispose(); + } + } + + private void periodicRefresh() { + /* + * it's sufficient to send "wer da?" to the configured ip address. + * the listener should be able to process the response like any other response. + */ + final AnelUdpConnector udpConnector2 = udpConnector; + if (udpConnector2 != null && udpConnector2.isConnected()) { + /* + * Check whether or not the device sends a response at all. If not, after some unanswered refresh requests, + * we should change the thing status to COMM_ERROR. The refresh task should remain active so that the device + * has a chance to get back online as soon as it responds again. + */ + if (refreshRequestWithoutResponse > IAnelConstants.UNANSWERED_REFRESH_REQUESTS_TO_SET_THING_OFFLINE + && getThing().getStatus() == ThingStatus.ONLINE) { + final String msg = "Setting thing offline because it did not respond to the last " + + IAnelConstants.UNANSWERED_REFRESH_REQUESTS_TO_SET_THING_OFFLINE + " status requests: " + + config; + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, msg); + } + + try { + refreshRequestWithoutResponse++; + + udpConnector2.send(IAnelConstants.BROADCAST_DISCOVERY_MSG); + sendingFailures = 0; + } catch (Exception e) { + handleSendException(e); + } + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + final AnelUdpConnector udpConnector2 = udpConnector; + if (udpConnector2 == null || !udpConnector2.isConnected() || getThing().getStatus() != ThingStatus.ONLINE) { + // don't log initial refresh commands because they may occur before thing is online + if (!(command instanceof RefreshType)) { + logger.debug("Cannot handle command '{}' for channel '{}' because thing ({}) is not connected: {}", // + command, channelUID.getId(), getThing().getStatus(), config); + } + return; + } + + String anelCommand = null; + if (command instanceof RefreshType) { + final State update = stateUpdater.getChannelUpdate(channelUID.getId(), state); + if (update != null) { + updateState(channelUID, update); + } else if (!refreshRequested) { + // send broadcast request for refreshing the state; remember it to avoid multiple simultaneous requests + refreshRequested = true; + anelCommand = IAnelConstants.BROADCAST_DISCOVERY_MSG; + } else { + logger.debug( + "Channel {} received command {} which is ignored because another channel already requested the same command", + channelUID, command); + } + } else if (command instanceof OnOffType) { + final State lockedState; + synchronized (this) { // lock needed to update the state if needed + lockedState = commandHandler.getLockedState(state, channelUID.getId()); + if (lockedState == null) { + // command only possible if state is not locked + anelCommand = commandHandler.toAnelCommandAndUnsetState(state, channelUID.getId(), command, + getAuthentication()); + } + } + + if (lockedState != null) { + logger.debug("Channel {} received command {} but it is locked, so the state is reset to {}.", + channelUID, command, lockedState); + + updateState(channelUID, lockedState); + } else if (anelCommand == null) { + logger.warn( + "Channel {} received command {} which is (currently) not supported; please check channel configuration.", + channelUID, command); + } + } else { + logger.warn("Channel {} received command {} which is not supported", channelUID, command); + } + + if (anelCommand != null) { + logger.debug("Channel {} received command {} which is converted to: {}", channelUID, command, anelCommand); + + try { + udpConnector2.send(anelCommand); + sendingFailures = 0; + } catch (Exception e) { + handleSendException(e); + } + } + } + + private void handleSendException(Exception e) { + if (getThing().getStatus() == ThingStatus.ONLINE) { + if (sendingFailures++ == IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS) { + final String msg = "Setting thing offline because binding failed to send " + sendingFailures + + " messages to it: " + config; + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, msg); + } else if (sendingFailures < IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS) { + logger.warn("Failed to send message to: {}", config, e); + } + } // else: ignore exception for offline things + } + + private void handleStatusUpdate(@Nullable String newStatus) { + refreshRequestWithoutResponse = 0; + try { + if (newStatus != null && newStatus.contains(IAnelConstants.ERROR_CREDENTIALS)) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "Invalid username or password for " + config); + return; + } + if (newStatus != null && newStatus.contains(IAnelConstants.ERROR_INSUFFICIENT_RIGHTS)) { + final AnelConfiguration config2 = config; + if (config2 != null) { + logger.warn( + "User '{}' on device {} has insufficient rights to change the state of a relay or IO port; you can fix that in the Web-UI, 'Einstellungen / Settings' -> 'User'.", + config2.user, config2.hostname); + } + return; + } + + final AnelState recentState, newState; + synchronized (this) { // to make sure state is fully processed before replacing it + recentState = state; + if (newStatus != null && recentState != null && newStatus.equals(recentState.status) + && !hasUnsetState(recentState)) { + return; // no changes + } + newState = AnelState.of(newStatus); + + state = newState; // update most recent state + } + final Map updates = stateUpdater.getChannelUpdates(recentState, newState); + + if (getThing().getStatus() == ThingStatus.OFFLINE) { + updateStatus(ThingStatus.ONLINE); // we got a response! set thing online if it wasn't! + } + updateStateFailures = 0; // reset error counter, if necessary + + // report all state updates + if (!updates.isEmpty()) { + logger.debug("updating channel states: {}", updates); + + updates.forEach(this::updateState); + } + } catch (Exception e) { + if (getThing().getStatus() == ThingStatus.ONLINE) { + if (updateStateFailures++ == IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS) { + final String msg = "Setting thing offline because status updated failed " + updateStateFailures + + " times in a row for: " + config; + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, msg); + } else if (updateStateFailures < IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS) { + logger.warn("Status update failed for: {}", config, e); + } + } // else: ignore exception for offline things + } + } + + private boolean hasUnsetState(AnelState state) { + for (int i = 0; i < state.relayState.length; i++) { + if (state.relayState[i] == null) { + return true; + } + } + for (int i = 0; i < state.ioState.length; i++) { + if (state.ioName[i] != null && state.ioState[i] == null) { + return true; + } + } + return false; + } + + private String getAuthentication() { + // create and remember authentication string + final String currentAuthentication = authentication; + if (currentAuthentication != null) { + return currentAuthentication; + } + + final AnelState currentState = state; + if (currentState == null) { + // should never happen because initialization ensures that initial state is received + throw new IllegalStateException("Cannot send any command to device b/c it did not send any answer yet"); + } + + final AnelConfiguration currentConfig = config; + if (currentConfig == null) { + throw new IllegalStateException("Config must not be null!"); + } + + final String newAuthentication = AnelAuthentication.getUserPasswordString(currentConfig.user, + currentConfig.password, AuthMethod.of(currentState.status)); + authentication = newAuthentication; + return newAuthentication; + } + + @Override + public void dispose() { + final ScheduledFuture periodicRefreshTask2 = periodicRefreshTask; + if (periodicRefreshTask2 != null) { + periodicRefreshTask2.cancel(false); + periodicRefreshTask = null; + } + final AnelUdpConnector connector = udpConnector; + if (connector != null) { + udpConnector = null; + try { + connector.disconnect(); + } catch (Exception e) { + logger.debug("Failed to close socket connection for: {}", config, e); + } + } + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java new file mode 100644 index 0000000000000..96a5d9e5e979b --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelHandlerFactory.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.openhab.binding.anel.internal.IAnelConstants.SUPPORTED_THING_TYPES_UIDS; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link AnelHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.anel", service = ThingHandlerFactory.class) +public class AnelHandlerFactory extends BaseThingHandlerFactory { + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + if (supportsThingType(thing.getThingTypeUID())) { + return new AnelHandler(thing); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java new file mode 100644 index 0000000000000..c1fe5ecd126d6 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/AnelUdpConnector.java @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.common.NamedThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class handles the actual communication to ANEL devices. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelUdpConnector { + + /** Buffer for incoming UDP packages. */ + private static final int MAX_PACKET_SIZE = 512; + + private final Logger logger = LoggerFactory.getLogger(AnelUdpConnector.class); + + /** The device IP this connector is listening to / sends to. */ + private final String host; + + /** The port this connector is listening to. */ + private final int receivePort; + + /** The port this connector is sending to. */ + private final int sendPort; + + /** Service to spawn new threads for handling status updates. */ + private final ExecutorService executorService; + + /** Thread factory for UDP listening thread. */ + private final NamedThreadFactory listeningThreadFactory = new NamedThreadFactory(IAnelConstants.BINDING_ID, true); + + /** Socket for receiving UDP packages. */ + private @Nullable DatagramSocket receivingSocket = null; + /** Socket for sending UDP packages. */ + private @Nullable DatagramSocket sendingSocket = null; + + /** The listener that gets notified upon newly received messages. */ + private @Nullable Consumer listener; + + private int receiveFailures = 0; + private boolean listenerActive = false; + + /** + * Create a new connector to an Anel device via the given host and UDP + * ports. + * + * @param host + * The IP address / network name of the device. + * @param udpReceivePort + * The UDP port to listen for packages. + * @param udpSendPort + * The UDP port to send packages. + */ + public AnelUdpConnector(String host, int udpReceivePort, int udpSendPort, ExecutorService executorService) { + if (udpReceivePort <= 0) { + throw new IllegalArgumentException("Invalid udpReceivePort: " + udpReceivePort); + } + if (udpSendPort <= 0) { + throw new IllegalArgumentException("Invalid udpSendPort: " + udpSendPort); + } + if (host.trim().isEmpty()) { + throw new IllegalArgumentException("Missing host."); + } + this.host = host; + this.receivePort = udpReceivePort; + this.sendPort = udpSendPort; + this.executorService = executorService; + } + + /** + * Initialize socket connection to the UDP receive port for the given listener. + * + * @throws SocketException Is only thrown if logNotTHrowException = false. + * @throws InterruptedException Typically happens during shutdown. + */ + public void connect(Consumer listener, boolean logNotThrowExcpetion) + throws SocketException, InterruptedException { + if (receivingSocket == null) { + try { + receivingSocket = new DatagramSocket(receivePort); + sendingSocket = new DatagramSocket(); + this.listener = listener; + + /*- + * Due to the issue with 4 concurrently listening threads [1], we should follow Kais suggestion [2] + * to create our own listening daemonized thread. + * + * [1] https://community.openhab.org/t/anel-net-pwrctrl-binding-for-oh3/123378 + * [2] https://www.eclipse.org/forums/index.php/m/1775932/?#msg_1775429 + */ + listeningThreadFactory.newThread(this::listen).start(); + + // wait for the listening thread to be active + for (int i = 0; i < 20 && !listenerActive; i++) { + Thread.sleep(100); // wait at most 20 * 100ms = 2sec for the listener to be active + } + if (!listenerActive) { + logger.warn( + "Listener thread started but listener is not yet active after 2sec; something seems to be wrong with the JVM thread handling?!"); + } + } catch (SocketException e) { + if (logNotThrowExcpetion) { + logger.warn( + "Failed to open socket connection on port {} (maybe there is already another socket listener on that port?)", + receivePort, e); + } + + disconnect(); + + if (!logNotThrowExcpetion) { + throw e; + } + } + } else if (!Objects.equals(this.listener, listener)) { + throw new IllegalStateException("A listening thread is already running"); + } + } + + private void listen() { + try { + listenUnhandledInterruption(); + } catch (InterruptedException e) { + // OH shutdown - don't log anything, just quit + } + } + + private void listenUnhandledInterruption() throws InterruptedException { + logger.info("Anel NET-PwrCtrl listener started for: '{}:{}'", host, receivePort); + + final Consumer listener2 = listener; + final DatagramSocket socket2 = receivingSocket; + while (listener2 != null && socket2 != null && receivingSocket != null) { + try { + final DatagramPacket packet = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE); + + listenerActive = true; + socket2.receive(packet); // receive packet (blocking call) + listenerActive = false; + + final byte[] data = Arrays.copyOfRange(packet.getData(), 0, packet.getLength() - 1); + + if (data == null || data.length == 0) { + if (isConnected()) { + logger.debug("Nothing received, this may happen during shutdown or some unknown error"); + } + continue; + } + receiveFailures = 0; // message successfully received, unset failure counter + + /* useful for debugging without logger (e.g. in AnelUdpConnectorTest): */ + // System.out.println(String.format("%s [%s] received: %s", getClass().getSimpleName(), + // new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()), new String(data).trim())); + + // log & notify listener in new thread (so that listener loop continues immediately) + executorService.execute(() -> { + final String message = new String(data); + + logger.debug("Received data on port {}: {}", receivePort, message); + + listener2.accept(message); + }); + } catch (Exception e) { + listenerActive = false; + + if (receivingSocket == null) { + logger.debug("Socket closed; stopping listener on port {}.", receivePort); + } else { + // if we get 3 errors in a row, we should better add a delay to stop spamming the log! + if (receiveFailures++ > IAnelConstants.ATTEMPTS_WITH_COMMUNICATION_ERRORS) { + logger.debug( + "Unexpected error while listening on port {}; waiting 10sec before the next attempt to listen on that port.", + receivePort, e); + for (int i = 0; i < 50 && receivingSocket != null; i++) { + Thread.sleep(200); // 50 * 200ms = 10sec + } + } else { + logger.warn("Unexpected error while listening on port {}", receivePort, e); + } + } + } + } + } + + /** Close the socket connection. */ + public void disconnect() { + logger.debug("Anel NET-PwrCtrl listener stopped for: '{}:{}'", host, receivePort); + listener = null; + final DatagramSocket receivingSocket2 = receivingSocket; + if (receivingSocket2 != null) { + receivingSocket = null; + if (!receivingSocket2.isClosed()) { + receivingSocket2.close(); // this interrupts and terminates the listening thread + } + } + final DatagramSocket sendingSocket2 = sendingSocket; + if (sendingSocket2 != null) { + synchronized (this) { + if (Objects.equals(sendingSocket, sendingSocket2)) { + sendingSocket = null; + if (!sendingSocket2.isClosed()) { + sendingSocket2.close(); + } + } + } + } + } + + public void send(String msg) throws IOException { + logger.debug("Sending message '{}' to {}:{}", msg, host, sendPort); + if (msg.isEmpty()) { + throw new IllegalArgumentException("Message must not be empty"); + } + + final InetAddress ipAddress = InetAddress.getByName(host); + final byte[] bytes = msg.getBytes(); + final DatagramPacket packet = new DatagramPacket(bytes, bytes.length, ipAddress, sendPort); + + // make sure we are not interrupted by a disconnect while sending this message + synchronized (this) { + final DatagramSocket sendingSocket2 = sendingSocket; + if (sendingSocket2 != null) { + sendingSocket2.send(packet); + + /* useful for debugging without logger (e.g. in AnelUdpConnectorTest): */ + // System.out.println(String.format("%s [%s] sent: %s", getClass().getSimpleName(), + // new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()), msg)); + + logger.debug("Sending successful."); + } + } + } + + public boolean isConnected() { + return receivingSocket != null; + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java new file mode 100644 index 0000000000000..c8aacb6d0a420 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/IAnelConstants.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link IAnelConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public interface IAnelConstants { + + String BINDING_ID = "anel"; + + /** Message sent to Anel devices to detect new dfevices and to request the current state. */ + String BROADCAST_DISCOVERY_MSG = "wer da?"; + /** Expected prefix for all received Anel status messages. */ + String STATUS_RESPONSE_PREFIX = "NET-PwrCtrl"; + /** Separator of the received Anel status messages. */ + String STATUS_SEPARATOR = ":"; + + /** Status message String if the current user / password does not match. */ + String ERROR_CREDENTIALS = ":NoPass:Err"; + /** Status message String if the current user does not have enough rights. */ + String ERROR_INSUFFICIENT_RIGHTS = ":NoAccess:Err"; + + /** Property name to uniquely identify (discovered) things. */ + String UNIQUE_PROPERTY_NAME = "mac"; + + /** Default port used to send message to Anel devices. */ + int DEFAULT_SEND_PORT = 75; + /** Default port used to receive message from Anel devices. */ + int DEFAULT_RECEIVE_PORT = 77; + + /** Static refresh interval for heartbeat for Thing status. */ + int REFRESH_INTERVAL_SEC = 60; + + /** Thing is set OFFLINE after so many communication errors. */ + int ATTEMPTS_WITH_COMMUNICATION_ERRORS = 3; + + /** Thing is set OFFLINE if it did not respond to so many refresh requests. */ + int UNANSWERED_REFRESH_REQUESTS_TO_SET_THING_OFFLINE = 5; + + /** Thing Type UID for Anel Net-PwrCtrl HOME. */ + ThingTypeUID THING_TYPE_ANEL_HOME = new ThingTypeUID(BINDING_ID, "home"); + /** Thing Type UID for Anel Net-PwrCtrl PRO / POWER. */ + ThingTypeUID THING_TYPE_ANEL_SIMPLE = new ThingTypeUID(BINDING_ID, "simple-firmware"); + /** Thing Type UID for Anel Net-PwrCtrl ADV / IO / HUT. */ + ThingTypeUID THING_TYPE_ANEL_ADVANCED = new ThingTypeUID(BINDING_ID, "advanced-firmware"); + /** All supported Thing Type UIDs. */ + Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ANEL_HOME, THING_TYPE_ANEL_SIMPLE, + THING_TYPE_ANEL_ADVANCED); + + /** The device type is part of the status response and is mapped to the thing types. */ + Map DEVICE_TYPE_TO_THING_TYPE = Map.of( // + 'H', THING_TYPE_ANEL_HOME, // HOME + 'P', THING_TYPE_ANEL_SIMPLE, // PRO / POWER + 'h', THING_TYPE_ANEL_ADVANCED, // HUT (and variants, e.g. h3 for HUT3) + 'a', THING_TYPE_ANEL_ADVANCED, // ADV + 'i', THING_TYPE_ANEL_ADVANCED); // IO + + // All remaining constants are Channel ids + + String CHANNEL_NAME = "prop#name"; + String CHANNEL_TEMPERATURE = "prop#temperature"; + + List CHANNEL_RELAY_NAME = List.of("r1#name", "r2#name", "r3#name", "r4#name", "r5#name", "r6#name", + "r7#name", "r8#name"); + + // second character must be the index b/c it is parsed in AnelCommandHandler! + List CHANNEL_RELAY_STATE = List.of("r1#state", "r2#state", "r3#state", "r4#state", "r5#state", "r6#state", + "r7#state", "r8#state"); + + List CHANNEL_RELAY_LOCKED = List.of("r1#locked", "r2#locked", "r3#locked", "r4#locked", "r5#locked", + "r6#locked", "r7#locked", "r8#locked"); + + List CHANNEL_IO_NAME = List.of("io1#name", "io2#name", "io3#name", "io4#name", "io5#name", "io6#name", + "io7#name", "io8#name"); + + List CHANNEL_IO_MODE = List.of("io1#mode", "io2#mode", "io3#mode", "io4#mode", "io5#mode", "io6#mode", + "io7#mode", "io8#mode"); + + // third character must be the index b/c it is parsed in AnelCommandHandler! + List CHANNEL_IO_STATE = List.of("io1#state", "io2#state", "io3#state", "io4#state", "io5#state", + "io6#state", "io7#state", "io8#state"); + + String CHANNEL_SENSOR_TEMPERATURE = "sensor#temperature"; + String CHANNEL_SENSOR_HUMIDITY = "sensor#humidity"; + String CHANNEL_SENSOR_BRIGHTNESS = "sensor#brightness"; + + /** + * @param channelId A channel ID. + * @return The zero-based index of the relay or IO channel (0-7); -1 if it's not a relay + * or IO channel. + */ + static int getIndexFromChannel(String channelId) { + if (channelId.startsWith("r") && channelId.length() > 2) { + return Character.getNumericValue(channelId.charAt(1)) - 1; + } + if (channelId.startsWith("io") && channelId.length() > 2) { + return Character.getNumericValue(channelId.charAt(2)) - 1; + } + return -1; // not a relay or io channel + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java new file mode 100644 index 0000000000000..ea897e50c88ac --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/auth/AnelAuthentication.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal.auth; + +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * This class determines the authentication method from a status response of an ANEL device. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelAuthentication { + + public enum AuthMethod { + PLAIN, + BASE64, + XORBASE64; + + private static final Pattern NAME_AND_FIRMWARE_PATTERN = Pattern.compile(":NET-PWRCTRL_0?(\\d+\\.\\d)"); + private static final Pattern LAST_SEGMENT_FIRMWARE_PATTERN = Pattern.compile(":(\\d+\\.\\d)$"); + + private static final String MIN_FIRMWARE_BASE64 = "6.0"; + private static final String MIN_FIRMWARE_XOR_BASE64 = "6.1"; + + public static AuthMethod of(String status) { + if (status.isEmpty()) { + return PLAIN; // fallback + } + if (status.trim().endsWith(":xor") || status.contains(":xor:")) { + return XORBASE64; + } + final String firmwareVersion = getFirmwareVersion(status); + if (firmwareVersion == null) { + return PLAIN; + } + if (firmwareVersion.compareTo(MIN_FIRMWARE_XOR_BASE64) >= 0) { + return XORBASE64; // >= 6.1 + } + if (firmwareVersion.compareTo(MIN_FIRMWARE_BASE64) >= 0) { + return BASE64; // exactly 6.0 + } + return PLAIN; // fallback + } + + private static @Nullable String getFirmwareVersion(String fullStatusStringOrFirmwareVersion) { + final Matcher matcher1 = NAME_AND_FIRMWARE_PATTERN.matcher(fullStatusStringOrFirmwareVersion); + if (matcher1.find()) { + return matcher1.group(1); + } + final Matcher matcher2 = LAST_SEGMENT_FIRMWARE_PATTERN.matcher(fullStatusStringOrFirmwareVersion.trim()); + if (matcher2.find()) { + return matcher2.group(1); + } + return null; + } + } + + public static String getUserPasswordString(@Nullable String user, @Nullable String password, + @Nullable AuthMethod authMethod) { + final String userPassword = (user == null ? "" : user) + (password == null ? "" : password); + if (authMethod == null || authMethod == AuthMethod.PLAIN) { + return userPassword; + } + + if (authMethod == AuthMethod.BASE64 || password == null || password.isEmpty()) { + return Base64.getEncoder().encodeToString(userPassword.getBytes()); + } + + if (authMethod == AuthMethod.XORBASE64) { + final StringBuilder result = new StringBuilder(); + + // XOR + for (int c = 0; c < userPassword.length(); c++) { + result.append((char) (userPassword.charAt(c) ^ password.charAt(c % password.length()))); + } + + return Base64.getEncoder().encodeToString(result.toString().getBytes()); + } + + throw new UnsupportedOperationException("Unknown auth method: " + authMethod); + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java new file mode 100644 index 0000000000000..cead6e0286c42 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/discovery/AnelDiscoveryService.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal.discovery; + +import java.io.IOException; +import java.net.BindException; +import java.nio.channels.ClosedByInterruptException; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.anel.internal.AnelUdpConnector; +import org.openhab.binding.anel.internal.IAnelConstants; +import org.openhab.core.common.AbstractUID; +import org.openhab.core.common.NamedThreadFactory; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.net.NetUtil; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Discovery service for ANEL devices. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.anel") +public class AnelDiscoveryService extends AbstractDiscoveryService { + + private static final String PASSWORD = "anel"; + private static final String USER = "user7"; + private static final int[][] DISCOVERY_PORTS = { { 750, 770 }, { 7500, 7700 }, { 7750, 7770 } }; + private static final Set BROADCAST_ADDRESSES = new TreeSet<>(NetUtil.getAllBroadcastAddresses()); + + private static final int DISCOVER_DEVICE_TIMEOUT_SECONDS = 2; + + /** #BroadcastAddresses * DiscoverDeviceTimeout * (3 * #DiscoveryPorts) */ + private static final int DISCOVER_TIMEOUT_SECONDS = BROADCAST_ADDRESSES.size() * DISCOVER_DEVICE_TIMEOUT_SECONDS + * (3 * DISCOVERY_PORTS.length); + + private final Logger logger = LoggerFactory.getLogger(AnelDiscoveryService.class); + + private @Nullable Thread scanningThread = null; + + public AnelDiscoveryService() throws IllegalArgumentException { + super(IAnelConstants.SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS); + logger.debug( + "Anel NET-PwrCtrl discovery service instantiated for broadcast addresses {} with a timeout of {} seconds.", + BROADCAST_ADDRESSES, DISCOVER_TIMEOUT_SECONDS); + } + + @Override + protected void startScan() { + /* + * Start scan in background thread, otherwise progress is not shown in the web UI. + * Do not use the scheduler, otherwise further threads (for handling discovered things) are not started + * immediately but only after the scan is complete. + */ + final Thread thread = new NamedThreadFactory(IAnelConstants.BINDING_ID, true).newThread(this::doScan); + thread.start(); + scanningThread = thread; + } + + private void doScan() { + logger.debug("Starting scan of Anel devices via UDP broadcast messages..."); + + try { + for (final String broadcastAddress : BROADCAST_ADDRESSES) { + + // for each available broadcast network address try factory default ports first + scan(broadcastAddress, IAnelConstants.DEFAULT_SEND_PORT, IAnelConstants.DEFAULT_RECEIVE_PORT); + + // try reasonable ports... + for (int[] ports : DISCOVERY_PORTS) { + int sendPort = ports[0]; + int receivePort = ports[1]; + + // ...and continue if a device was found, maybe there is yet another device on the next port + while (scan(broadcastAddress, sendPort, receivePort) || sendPort == ports[0]) { + sendPort++; + receivePort++; + } + } + } + } catch (InterruptedException | ClosedByInterruptException e) { + return; // OH shutdown or scan was aborted + } catch (Exception e) { + logger.warn("Unexpected exception during anel device scan", e); + } finally { + scanningThread = null; + } + logger.debug("Scan finished."); + } + + /* @return Whether or not a device was found for the given broadcast address and port. */ + private boolean scan(String broadcastAddress, int sendPort, int receivePort) + throws IOException, InterruptedException { + logger.debug("Scanning {}:{}...", broadcastAddress, sendPort); + final AnelUdpConnector udpConnector = new AnelUdpConnector(broadcastAddress, receivePort, sendPort, scheduler); + + try { + final boolean[] deviceDiscovered = new boolean[] { false }; + udpConnector.connect(status -> { + // avoid the same device to be discovered multiple times for multiple responses + if (!deviceDiscovered[0]) { + boolean discoverDevice = true; + synchronized (this) { + if (deviceDiscovered[0]) { + discoverDevice = false; // already discovered by another thread + } else { + deviceDiscovered[0] = true; // we discover the device! + } + } + if (discoverDevice) { + // discover device outside synchronized-block + deviceDiscovered(status, sendPort, receivePort); + } + } + }, false); + + udpConnector.send(IAnelConstants.BROADCAST_DISCOVERY_MSG); + + // answer expected within 50-600ms on a regular network; wait up to 2sec just to make sure + for (int delay = 0; delay < 10 && !deviceDiscovered[0]; delay++) { + Thread.sleep(100 * DISCOVER_DEVICE_TIMEOUT_SECONDS); // wait 10 x 200ms = 2sec + } + + return deviceDiscovered[0]; + } catch (BindException e) { + // most likely socket is already in use, ignore this exception. + logger.debug( + "Invalid address {} or one of the ports {} or {} is already in use. Skipping scan of these ports.", + broadcastAddress, sendPort, receivePort); + } finally { + udpConnector.disconnect(); + } + return false; + } + + @Override + protected synchronized void stopScan() { + final Thread thread = scanningThread; + if (thread != null) { + thread.interrupt(); + } + super.stopScan(); + } + + private void deviceDiscovered(String status, int sendPort, int receivePort) { + final String[] segments = status.split(":"); + if (segments.length >= 16) { + final String name = segments[1].trim(); + final String ip = segments[2]; + final String macAddress = segments[5]; + final String deviceType = segments.length > 17 ? segments[17] : null; + final ThingTypeUID thingTypeUid = getThingTypeUid(deviceType, segments); + final ThingUID thingUid = new ThingUID(thingTypeUid + AbstractUID.SEPARATOR + macAddress.replace(".", "")); + + final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUid) // + .withThingType(thingTypeUid) // + .withProperty("hostname", ip) // AnelConfiguration.hostname + .withProperty("user", USER) // AnelConfiguration.user + .withProperty("password", PASSWORD) // AnelConfiguration.password + .withProperty("udpSendPort", sendPort) // AnelConfiguration.udpSendPort + .withProperty("udpReceivePort", receivePort) // AnelConfiguration.udbReceivePort + .withProperty(IAnelConstants.UNIQUE_PROPERTY_NAME, macAddress) // + .withLabel(name) // + .withRepresentationProperty(IAnelConstants.UNIQUE_PROPERTY_NAME) // + .build(); + + thingDiscovered(discoveryResult); + } + } + + private ThingTypeUID getThingTypeUid(@Nullable String deviceType, String[] segments) { + // device type is contained since firmware 6.0 + if (deviceType != null && !deviceType.isEmpty()) { + final char deviceTypeChar = deviceType.charAt(0); + final ThingTypeUID thingTypeUID = IAnelConstants.DEVICE_TYPE_TO_THING_TYPE.get(deviceTypeChar); + if (thingTypeUID != null) { + return thingTypeUID; + } + } + + if (segments.length < 20) { + // no information given, we should be save with return the simple firmware thing type + return IAnelConstants.THING_TYPE_ANEL_SIMPLE; + } else { + // more than 20 segments must include IO ports, hence it's an advanced firmware + return IAnelConstants.THING_TYPE_ANEL_ADVANCED; + } + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelCommandHandler.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelCommandHandler.java new file mode 100644 index 0000000000000..c2cc504b8e4cf --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelCommandHandler.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal.state; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.anel.internal.IAnelConstants; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.types.Command; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Convert an openhab command to an ANEL UDP command message. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelCommandHandler { + + private final Logger logger = LoggerFactory.getLogger(AnelCommandHandler.class); + + public @Nullable State getLockedState(@Nullable AnelState state, String channelId) { + if (IAnelConstants.CHANNEL_RELAY_STATE.contains(channelId)) { + if (state == null) { + return null; // assume unlocked + } + + final int index = IAnelConstants.getIndexFromChannel(channelId); + + final @Nullable Boolean locked = state.relayLocked[index]; + if (locked == null || !locked.booleanValue()) { + return null; // no lock information or unlocked + } + + final @Nullable Boolean lockedState = state.relayState[index]; + if (lockedState == null) { + return null; // no state information available + } + + return OnOffType.from(lockedState.booleanValue()); + } + + if (IAnelConstants.CHANNEL_IO_STATE.contains(channelId)) { + if (state == null) { + return null; // assume unlocked + } + + final int index = IAnelConstants.getIndexFromChannel(channelId); + + final @Nullable Boolean isInput = state.ioIsInput[index]; + if (isInput == null || !isInput.booleanValue()) { + return null; // no direction infmoration or output port + } + + final @Nullable Boolean ioState = state.ioState[index]; + if (ioState == null) { + return null; // no state information available + } + return OnOffType.from(ioState.booleanValue()); + } + return null; // all other channels are read-only! + } + + public @Nullable String toAnelCommandAndUnsetState(@Nullable AnelState state, String channelId, Command command, + String authentication) { + if (!(command instanceof OnOffType)) { + // only relay states and io states can be changed, all other channels are read-only + logger.warn("Anel binding only support ON/OFF and Refresh commands, not {}: {}", + command.getClass().getSimpleName(), command); + } else if (IAnelConstants.CHANNEL_RELAY_STATE.contains(channelId)) { + final int index = IAnelConstants.getIndexFromChannel(channelId); + + // unset anel state which enforces a channel state update + if (state != null) { + state.relayState[index] = null; + } + + @Nullable + final Boolean locked = state == null ? null : state.relayLocked[index]; + if (locked == null || !locked.booleanValue()) { + return String.format("Sw_%s%d%s", command.toString().toLowerCase(), index + 1, authentication); + } else { + logger.warn("Relay {} is locked; skipping command {}.", index + 1, command); + } + } else if (IAnelConstants.CHANNEL_IO_STATE.contains(channelId)) { + final int index = IAnelConstants.getIndexFromChannel(channelId); + + // unset anel state which enforces a channel state update + if (state != null) { + state.ioState[index] = null; + } + + @Nullable + final Boolean isInput = state == null ? null : state.ioIsInput[index]; + if (isInput == null || !isInput.booleanValue()) { + return String.format("IO_%s%d%s", command.toString().toLowerCase(), index + 1, authentication); + } else { + logger.warn("IO {} has direction input, not output; skipping command {}.", index + 1, command); + } + } + + return null; // all other channels are read-only + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java new file mode 100644 index 0000000000000..defc0975bb43d --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelState.java @@ -0,0 +1,308 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal.state; + +import java.util.Arrays; +import java.util.IllegalFormatException; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.anel.internal.IAnelConstants; + +/** + * Parser and data structure for the state of an Anel device. + *

+ * Documentation in Anel forum (German). + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelState { + + /** Pattern for temp, e.g. 26.4°C or -1°F */ + private static final Pattern PATTERN_TEMPERATURE = Pattern.compile("(\\-?\\d+(?:\\.\\d)?).[CF]"); + /** Pattern for switch state: [name],[state: 1=on,0=off] */ + private static final Pattern PATTERN_SWITCH_STATE = Pattern.compile("(.+),(0|1)"); + /** Pattern for IO state: [name],[1=input,0=output],[state: 1=on,0=off] */ + private static final Pattern PATTERN_IO_STATE = Pattern.compile("(.+),(0|1),(0|1)"); + + /** The raw status this state was created from. */ + public final String status; + + /** Device IP address; read-only. */ + public final @Nullable String ip; + /** Device name; read-only. */ + public final @Nullable String name; + /** Device mac address; read-only. */ + public final @Nullable String mac; + + /** Device relay names; read-only. */ + public final String[] relayName = new String[8]; + /** Device relay states; changeable. */ + public final Boolean[] relayState = new Boolean[8]; + /** Device relay locked status; read-only. */ + public final Boolean[] relayLocked = new Boolean[8]; + + /** Device IO names; read-only. */ + public final String[] ioName = new String[8]; + /** Device IO states; changeable if they are configured as input. */ + public final Boolean[] ioState = new Boolean[8]; + /** Device IO input states (true means changeable); read-only. */ + public final Boolean[] ioIsInput = new Boolean[8]; + + /** Device temperature (optional); read-only. */ + public final @Nullable String temperature; + + /** Sensor temperature, e.g. "20.61" (optional); read-only. */ + public final @Nullable String sensorTemperature; + /** Sensor Humidity, e.g. "40.7" (optional); read-only. */ + public final @Nullable String sensorHumidity; + /** Sensor Brightness, e.g. "7.0" (optional); read-only. */ + public final @Nullable String sensorBrightness; + + private static final AnelState INVALID_STATE = new AnelState(); + + public static AnelState of(@Nullable String status) { + if (status == null || status.isEmpty()) { + return INVALID_STATE; + } + return new AnelState(status); + } + + private AnelState() { + status = ""; + ip = null; + name = null; + mac = null; + temperature = null; + sensorTemperature = null; + sensorHumidity = null; + sensorBrightness = null; + } + + private AnelState(@Nullable String status) throws IllegalFormatException { + if (status == null || status.isEmpty()) { + throw new IllegalArgumentException("status must not be null or empty"); + } + this.status = status; + final String[] segments = status.split(IAnelConstants.STATUS_SEPARATOR); + if (!segments[0].equals(IAnelConstants.STATUS_RESPONSE_PREFIX)) { + throw new IllegalArgumentException( + "Data must start with '" + IAnelConstants.STATUS_RESPONSE_PREFIX + "' but it didn't: " + status); + } + if (segments.length < 16) { + throw new IllegalArgumentException("Data must have at least 16 segments but it didn't: " + status); + } + final List issues = new LinkedList<>(); + + // name, host, mac + name = segments[1].trim(); + ip = segments[2]; + mac = segments[5]; + + // 8 switches / relays + Integer lockedSwitches; + try { + lockedSwitches = Integer.parseInt(segments[14]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Segment 15 (" + segments[14] + ") is expected to be a number but it's not: " + status); + } + for (int i = 0; i < 8; i++) { + final Matcher matcher = PATTERN_SWITCH_STATE.matcher(segments[6 + i]); + if (matcher.matches()) { + relayName[i] = matcher.group(1); + relayState[i] = "1".equals(matcher.group(2)); + } else { + issues.add("Unexpected format for switch " + i + ": '" + segments[6 + i]); + relayName[i] = ""; + relayState[i] = false; + } + relayLocked[i] = (lockedSwitches & (1 << i)) > 0; + } + + // 8 IO ports (devices with IO ports have >=24 segments) + if (segments.length >= 24) { + for (int i = 0; i < 8; i++) { + final Matcher matcher = PATTERN_IO_STATE.matcher(segments[16 + i]); + if (matcher.matches()) { + ioName[i] = matcher.group(1); + ioIsInput[i] = "1".equals(matcher.group(2)); + ioState[i] = "1".equals(matcher.group(3)); + } else { + issues.add("Unexpected format for IO " + i + ": '" + segments[16 + i]); + ioName[i] = ""; + } + } + } + + // temperature + temperature = segments.length > 24 ? parseTemperature(segments[24], issues) : null; + + if (segments.length > 34 && "p".equals(segments[27])) { + // optional sensor (if device supports it and firmware >= 6.1) after power management + if (segments.length > 38 && "s".equals(segments[35])) { + sensorTemperature = segments[36]; + sensorHumidity = segments[37]; + sensorBrightness = segments[38]; + } else { + sensorTemperature = null; + sensorHumidity = null; + sensorBrightness = null; + } + } else if (segments.length > 31 && "n".equals(segments[27]) && "s".equals(segments[28])) { + // but sensor! (if device supports it and firmware >= 6.1) + sensorTemperature = segments[29]; + sensorHumidity = segments[30]; + sensorBrightness = segments[31]; + } else { + // firmware <= 6.0 or unknown format; skip rest + sensorTemperature = null; + sensorBrightness = null; + sensorHumidity = null; + } + + if (!issues.isEmpty()) { + throw new IllegalArgumentException(String.format("Anel status string contains %d issue%s: %s\n%s", // + issues.size(), issues.size() == 1 ? "" : "s", status, + issues.stream().collect(Collectors.joining("\n")))); + } + } + + private static @Nullable String parseTemperature(String temp, List issues) { + if (!temp.isEmpty()) { + final Matcher matcher = PATTERN_TEMPERATURE.matcher(temp); + if (matcher.matches()) { + return matcher.group(1); + } + issues.add("Unexpected format for temperature: " + temp); + } + return null; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + status + "]"; + } + + /* generated */ + @Override + @SuppressWarnings("null") + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((ip == null) ? 0 : ip.hashCode()); + result = prime * result + ((mac == null) ? 0 : mac.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + Arrays.hashCode(ioIsInput); + result = prime * result + Arrays.hashCode(ioName); + result = prime * result + Arrays.hashCode(ioState); + result = prime * result + Arrays.hashCode(relayLocked); + result = prime * result + Arrays.hashCode(relayName); + result = prime * result + Arrays.hashCode(relayState); + result = prime * result + ((temperature == null) ? 0 : temperature.hashCode()); + result = prime * result + ((sensorBrightness == null) ? 0 : sensorBrightness.hashCode()); + result = prime * result + ((sensorHumidity == null) ? 0 : sensorHumidity.hashCode()); + result = prime * result + ((sensorTemperature == null) ? 0 : sensorTemperature.hashCode()); + return result; + } + + /* generated */ + @Override + @SuppressWarnings("null") + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AnelState other = (AnelState) obj; + if (ip == null) { + if (other.ip != null) { + return false; + } + } else if (!ip.equals(other.ip)) { + return false; + } + if (!Arrays.equals(ioIsInput, other.ioIsInput)) { + return false; + } + if (!Arrays.equals(ioName, other.ioName)) { + return false; + } + if (!Arrays.equals(ioState, other.ioState)) { + return false; + } + if (mac == null) { + if (other.mac != null) { + return false; + } + } else if (!mac.equals(other.mac)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (sensorBrightness == null) { + if (other.sensorBrightness != null) { + return false; + } + } else if (!sensorBrightness.equals(other.sensorBrightness)) { + return false; + } + if (sensorHumidity == null) { + if (other.sensorHumidity != null) { + return false; + } + } else if (!sensorHumidity.equals(other.sensorHumidity)) { + return false; + } + if (sensorTemperature == null) { + if (other.sensorTemperature != null) { + return false; + } + } else if (!sensorTemperature.equals(other.sensorTemperature)) { + return false; + } + if (!Arrays.equals(relayLocked, other.relayLocked)) { + return false; + } + if (!Arrays.equals(relayName, other.relayName)) { + return false; + } + if (!Arrays.equals(relayState, other.relayState)) { + return false; + } + if (temperature == null) { + if (other.temperature != null) { + return false; + } + } else if (!temperature.equals(other.temperature)) { + return false; + } + return true; + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java new file mode 100644 index 0000000000000..1f208712fb578 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/java/org/openhab/binding/anel/internal/state/AnelStateUpdater.java @@ -0,0 +1,216 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal.state; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.anel.internal.IAnelConstants; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; + +/** + * Get updates for {@link AnelState}s. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelStateUpdater { + + public @Nullable State getChannelUpdate(String channelId, @Nullable AnelState state) { + if (state == null) { + return null; + } + + final int index = IAnelConstants.getIndexFromChannel(channelId); + if (index >= 0) { + if (IAnelConstants.CHANNEL_RELAY_NAME.contains(channelId)) { + return getStringState(state.relayName[index]); + } + if (IAnelConstants.CHANNEL_RELAY_STATE.contains(channelId)) { + return getSwitchState(state.relayState[index]); + } + if (IAnelConstants.CHANNEL_RELAY_LOCKED.contains(channelId)) { + return getSwitchState(state.relayLocked[index]); + } + + if (IAnelConstants.CHANNEL_IO_NAME.contains(channelId)) { + return getStringState(state.ioName[index]); + } + if (IAnelConstants.CHANNEL_IO_STATE.contains(channelId)) { + return getSwitchState(state.ioState[index]); + } + if (IAnelConstants.CHANNEL_IO_MODE.contains(channelId)) { + return getSwitchState(state.ioState[index]); + } + } else { + if (IAnelConstants.CHANNEL_NAME.equals(channelId)) { + return getStringState(state.name); + } + if (IAnelConstants.CHANNEL_TEMPERATURE.equals(channelId)) { + return getTemperatureState(state.temperature); + } + + if (IAnelConstants.CHANNEL_SENSOR_TEMPERATURE.equals(channelId)) { + return getTemperatureState(state.sensorTemperature); + } + if (IAnelConstants.CHANNEL_SENSOR_HUMIDITY.equals(channelId)) { + return getDecimalState(state.sensorHumidity); + } + if (IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS.equals(channelId)) { + return getDecimalState(state.sensorBrightness); + } + } + return null; + } + + public Map getChannelUpdates(@Nullable AnelState oldState, AnelState newState) { + if (oldState != null && newState.status.equals(oldState.status)) { + return Collections.emptyMap(); // definitely no change! + } + + final Map updates = new HashMap<>(); + + // name and device temperature + final State newName = getNewStringState(oldState == null ? null : oldState.name, newState.name); + if (newName != null) { + updates.put(IAnelConstants.CHANNEL_NAME, newName); + } + final State newTemperature = getNewTemperatureState(oldState == null ? null : oldState.temperature, + newState.temperature); + if (newTemperature != null) { + updates.put(IAnelConstants.CHANNEL_TEMPERATURE, newTemperature); + } + + // relay properties + for (int i = 0; i < 8; i++) { + final State newRelayName = getNewStringState(oldState == null ? null : oldState.relayName[i], + newState.relayName[i]); + if (newRelayName != null) { + updates.put(IAnelConstants.CHANNEL_RELAY_NAME.get(i), newRelayName); + } + + final State newRelayState = getNewSwitchState(oldState == null ? null : oldState.relayState[i], + newState.relayState[i]); + if (newRelayState != null) { + updates.put(IAnelConstants.CHANNEL_RELAY_STATE.get(i), newRelayState); + } + + final State newRelayLocked = getNewSwitchState(oldState == null ? null : oldState.relayLocked[i], + newState.relayLocked[i]); + if (newRelayLocked != null) { + updates.put(IAnelConstants.CHANNEL_RELAY_LOCKED.get(i), newRelayLocked); + } + } + + // IO properties + for (int i = 0; i < 8; i++) { + final State newIOName = getNewStringState(oldState == null ? null : oldState.ioName[i], newState.ioName[i]); + if (newIOName != null) { + updates.put(IAnelConstants.CHANNEL_IO_NAME.get(i), newIOName); + } + + final State newIOIsInput = getNewSwitchState(oldState == null ? null : oldState.ioIsInput[i], + newState.ioIsInput[i]); + if (newIOIsInput != null) { + updates.put(IAnelConstants.CHANNEL_IO_MODE.get(i), newIOIsInput); + } + + final State newIOState = getNewSwitchState(oldState == null ? null : oldState.ioState[i], + newState.ioState[i]); + if (newIOState != null) { + updates.put(IAnelConstants.CHANNEL_IO_STATE.get(i), newIOState); + } + } + + // sensor values + final State newSensorTemperature = getNewTemperatureState(oldState == null ? null : oldState.sensorTemperature, + newState.sensorTemperature); + if (newSensorTemperature != null) { + updates.put(IAnelConstants.CHANNEL_SENSOR_TEMPERATURE, newSensorTemperature); + } + final State newSensorHumidity = getNewDecimalState(oldState == null ? null : oldState.sensorHumidity, + newState.sensorHumidity); + if (newSensorHumidity != null) { + updates.put(IAnelConstants.CHANNEL_SENSOR_HUMIDITY, newSensorHumidity); + } + final State newSensorBrightness = getNewDecimalState(oldState == null ? null : oldState.sensorBrightness, + newState.sensorBrightness); + if (newSensorBrightness != null) { + updates.put(IAnelConstants.CHANNEL_SENSOR_BRIGHTNESS, newSensorBrightness); + } + + return updates; + } + + private @Nullable State getStringState(@Nullable String value) { + return value == null ? null : new StringType(value); + } + + private @Nullable State getDecimalState(@Nullable String value) { + return value == null ? null : new DecimalType(value); + } + + private @Nullable State getTemperatureState(@Nullable String value) { + if (value == null || value.trim().isEmpty()) { + return null; + } + final float floatValue = Float.parseFloat(value); + return QuantityType.valueOf(floatValue, SIUnits.CELSIUS); + } + + private @Nullable State getSwitchState(@Nullable Boolean value) { + return value == null ? null : OnOffType.from(value.booleanValue()); + } + + private @Nullable State getNewStringState(@Nullable String oldValue, @Nullable String newValue) { + return getNewState(oldValue, newValue, StringType::new); + } + + private @Nullable State getNewDecimalState(@Nullable String oldValue, @Nullable String newValue) { + return getNewState(oldValue, newValue, DecimalType::new); + } + + private @Nullable State getNewTemperatureState(@Nullable String oldValue, @Nullable String newValue) { + return getNewState(oldValue, newValue, value -> QuantityType.valueOf(Float.parseFloat(value), SIUnits.CELSIUS)); + } + + private @Nullable State getNewSwitchState(@Nullable Boolean oldValue, @Nullable Boolean newValue) { + return getNewState(oldValue, newValue, value -> OnOffType.from(value.booleanValue())); + } + + private @Nullable State getNewState(@Nullable T oldValue, @Nullable T newValue, + Function createState) { + if (oldValue == null) { + if (newValue == null) { + return null; // no change + } else { + return createState.apply(newValue); // from null to some value + } + } else if (newValue == null) { + return UnDefType.NULL; // from some value to null + } else if (oldValue.equals(newValue)) { + return null; // no change + } + return createState.apply(newValue); // from some value to another value + } +} diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..1635ce3daf4df --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + Anel NET-PwrCtrl Binding + This is the binding for Anel NET-PwrCtrl devices. + + diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/config/config.xml new file mode 100644 index 0000000000000..96dc873097bd2 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/config/config.xml @@ -0,0 +1,39 @@ + + + + + + network-address + + net-control + Hostname or IP address of the device + + + port-send + + 75 + UDP port to send data to the device (in the anel web UI, it's the receive port!) + + + port-receive + + 77 + UDP port to receive data from the device (in the anel web UI, it's the send port!) + + + user + + user7 + User to access the device (make sure it has rights to change relay / IO states!) + + + password + + anel + Password to access the device + + + diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..d9e45864579bb --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,201 @@ + + + + + + Anel device with 3 controllable outlets without IO ports. + + + + + + + + + + + + ANEL Elektronik AG + NET-PwrCtrl HOME + + macAddress + + + + + + + Anel device with 8 controllable outlets without IO ports. + + + + + + + + + + + + + + + + + ANEL Elektronik AG + NET-PwrCtrl PRO / POWER + + macAddress + + + + + + + Anel device with 8 controllable outlets / relays and possibly 8 IO ports. + + + + + + + + + + + + + + + + + + + + + + + + + + + + ANEL Elektronik AG + NET-PwrCtrl ADV / IO / HUT + + macAddress + + + + + + + Device properties + + + + + + + + A relay / socket + + + + + + + + + An Input / Output Port + + + + + + + + + + Optional sensor values + + + + + + + + + String + + The name of the Anel device + + + + Number:Temperature + + The value of the built-in temperature sensor of the Anel device + + + + + String + + The name of the relay / socket + + + + Switch + + Whether or not the relay is locked + + + + Switch + + The state of the relay / socket (read-only if locked!) + veto + + + + String + + The name of the I/O port + + + + Switch + + Whether the port is configured as input (true) or output (false) + + + + Switch + + The state of the I/O port (read-only for input ports) + veto + + + + Number:Temperature + + The temperature value of the optional sensor + + + + Number + + The humidity value of the optional sensor + + + + Number + + The brightness value of the optional sensor + + + + diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java new file mode 100644 index 0000000000000..ca81fed646ffe --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelAuthenticationTest.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.Base64; +import java.util.function.BiFunction; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.anel.internal.auth.AnelAuthentication; +import org.openhab.binding.anel.internal.auth.AnelAuthentication.AuthMethod; + +/** + * This class tests {@link AnelAuthentication}. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelAuthenticationTest { + + private static final String STATUS_HUT_V4 = "NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_04.0"; + private static final String STATUS_HUT_V5 = "NET-PwrCtrl:ANEL2 :192.168.0.244:255.255.255.0:192.168.0.1:0.4.163.10.9.107:Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.9*C:NET-PWRCTRL_05.0"; + private static final String STATUS_HOME_V4_6 = "NET-PwrCtrl:NET-CONTROL :192.168.0.244:255.255.255.0:192.168.0.1:0.5.163.21.4.71:Nr. 1,0:Nr. 2,1:Nr. 3,0:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,0:Nr. 8,0:248:80:NET-PWRCTRL_04.6:H:xor:"; + private static final String STATUS_UDP_SPEC_EXAMPLE_V7 = "NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_06.1:h:p:225.9:0.0004:50.056:0.04:0.00:0.0:1.0000:s:20.61:40.7:7.0:xor"; + private static final String STATUS_PRO_EXAMPLE_V4_5 = "172.25.3.147776172NET-PwrCtrl:DT-BT14-IPL-1 :172.25.3.14:255.255.0.0:172.25.1.1:0.4.163.19.3.129:Nr. 1,0:Nr. 2,0:Nr. 3,0:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,0:Nr. 8,0:0:80:NET-PWRCTRL_04.5:xor:"; + private static final String STATUS_IO_EXAMPLE_V6_5 = "NET-PwrCtrl:NET-CONTROL :192.168.0.244:255.255.255.0:192.168.0.1:0.4.163.20.7.65:Nr.1,0:Nr.2,1:Nr.3,0:Nr.4,0:Nr.5,0:Nr.6,0:Nr.7,0:Nr.8,0:0:80:IO-1,0,1:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:23.1°C:NET-PWRCTRL_06.5:i:n:xor:"; + private static final String STATUS_EXAMPLE_V6_0 = " NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_06.0:o:p:225.9:0.0004:50.056:0.04:0.00:0.0:1.0000"; + + @Test + public void authenticationMethod() { + assertThat(AuthMethod.of(""), is(AuthMethod.PLAIN)); + assertThat(AuthMethod.of(" \n"), is(AuthMethod.PLAIN)); + assertThat(AuthMethod.of(STATUS_HUT_V4), is(AuthMethod.PLAIN)); + assertThat(AuthMethod.of(STATUS_HUT_V5), is(AuthMethod.PLAIN)); + assertThat(AuthMethod.of(STATUS_HOME_V4_6), is(AuthMethod.XORBASE64)); + assertThat(AuthMethod.of(STATUS_UDP_SPEC_EXAMPLE_V7), is(AuthMethod.XORBASE64)); + assertThat(AuthMethod.of(STATUS_PRO_EXAMPLE_V4_5), is(AuthMethod.XORBASE64)); + assertThat(AuthMethod.of(STATUS_IO_EXAMPLE_V6_5), is(AuthMethod.XORBASE64)); + assertThat(AuthMethod.of(STATUS_EXAMPLE_V6_0), is(AuthMethod.BASE64)); + } + + @Test + public void encodeUserPasswordPlain() { + encodeUserPassword(AuthMethod.PLAIN, (u, p) -> u + p); + } + + @Test + public void encodeUserPasswordBase64() { + encodeUserPassword(AuthMethod.BASE64, (u, p) -> base64(u + p)); + } + + @Test + public void encodeUserPasswordXorBase64() { + encodeUserPassword(AuthMethod.XORBASE64, (u, p) -> base64(xor(u + p, p))); + } + + private void encodeUserPassword(AuthMethod authMethod, BiFunction expectedEncoding) { + assertThat(AnelAuthentication.getUserPasswordString("admin", "anel", authMethod), + is(equalTo(expectedEncoding.apply("admin", "anel")))); + assertThat(AnelAuthentication.getUserPasswordString("", "", authMethod), + is(equalTo(expectedEncoding.apply("", "")))); + assertThat(AnelAuthentication.getUserPasswordString(null, "", authMethod), + is(equalTo(expectedEncoding.apply("", "")))); + assertThat(AnelAuthentication.getUserPasswordString("", null, authMethod), + is(equalTo(expectedEncoding.apply("", "")))); + assertThat(AnelAuthentication.getUserPasswordString(null, null, authMethod), + is(equalTo(expectedEncoding.apply("", "")))); + } + + private static String base64(String string) { + return Base64.getEncoder().encodeToString(string.getBytes()); + } + + private String xor(String text, String key) { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + sb.append((char) (text.charAt(i) ^ key.charAt(i % key.length()))); + } + return sb.toString(); + } +} diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelCommandHandlerTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelCommandHandlerTest.java new file mode 100644 index 0000000000000..ea7466de4666e --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelCommandHandlerTest.java @@ -0,0 +1,179 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.anel.internal.state.AnelCommandHandler; +import org.openhab.binding.anel.internal.state.AnelState; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.IncreaseDecreaseType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.types.UpDownType; +import org.openhab.core.types.RefreshType; + +/** + * This class tests {@link AnelCommandHandler}. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelCommandHandlerTest { + + private static final String CHANNEL_R1 = IAnelConstants.CHANNEL_RELAY_STATE.get(0); + private static final String CHANNEL_R3 = IAnelConstants.CHANNEL_RELAY_STATE.get(2); + private static final String CHANNEL_R4 = IAnelConstants.CHANNEL_RELAY_STATE.get(3); + private static final String CHANNEL_IO1 = IAnelConstants.CHANNEL_IO_STATE.get(0); + private static final String CHANNEL_IO6 = IAnelConstants.CHANNEL_IO_STATE.get(5); + + private static final AnelState STATE_INVALID = AnelState.of(null); + private static final AnelState STATE_HOME = AnelState.of(IAnelTestStatus.STATUS_HOME_V46); + private static final AnelState STATE_HUT = AnelState.of(IAnelTestStatus.STATUS_HUT_V65); + + private final AnelCommandHandler commandHandler = new AnelCommandHandler(); + + @Test + public void refreshCommand() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_INVALID, CHANNEL_R1, RefreshType.REFRESH, + "a"); + // then + assertNull(cmd); + } + + @Test + public void decimalCommandReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, new DecimalType("1"), "a"); + // then + assertNull(cmd); + } + + @Test + public void stringCommandReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, new StringType("ON"), "a"); + // then + assertNull(cmd); + } + + @Test + public void increaseDecreaseCommandReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, + IncreaseDecreaseType.INCREASE, "a"); + // then + assertNull(cmd); + } + + @Test + public void upDownCommandReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, UpDownType.UP, "a"); + // then + assertNull(cmd); + } + + @Test + public void unlockedSwitchReturnsCommand() { + // given & when + final String cmdOn1 = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, OnOffType.ON, "a"); + final String cmdOff1 = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R1, OnOffType.OFF, "a"); + final String cmdOn3 = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R3, OnOffType.ON, "a"); + final String cmdOff3 = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R3, OnOffType.OFF, "a"); + // then + assertThat(cmdOn1, equalTo("Sw_on1a")); + assertThat(cmdOff1, equalTo("Sw_off1a")); + assertThat(cmdOn3, equalTo("Sw_on3a")); + assertThat(cmdOff3, equalTo("Sw_off3a")); + } + + @Test + public void lockedSwitchReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_R4, OnOffType.ON, "a"); + // then + assertNull(cmd); + } + + @Test + public void nullIOSwitchReturnsCommand() { + // given & when + final String cmdOn = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_IO1, OnOffType.ON, "a"); + final String cmdOff = commandHandler.toAnelCommandAndUnsetState(STATE_HOME, CHANNEL_IO1, OnOffType.OFF, "a"); + // then + assertThat(cmdOn, equalTo("IO_on1a")); + assertThat(cmdOff, equalTo("IO_off1a")); + } + + @Test + public void inputIOSwitchReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HUT, CHANNEL_IO6, OnOffType.ON, "a"); + // then + assertNull(cmd); + } + + @Test + public void outputIOSwitchReturnsCommand() { + // given & when + final String cmdOn = commandHandler.toAnelCommandAndUnsetState(STATE_HUT, CHANNEL_IO1, OnOffType.ON, "a"); + final String cmdOff = commandHandler.toAnelCommandAndUnsetState(STATE_HUT, CHANNEL_IO1, OnOffType.OFF, "a"); + // then + assertThat(cmdOn, equalTo("IO_on1a")); + assertThat(cmdOff, equalTo("IO_off1a")); + } + + @Test + public void ioDirectionSwitchReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HUT, IAnelConstants.CHANNEL_IO_MODE.get(0), + OnOffType.ON, "a"); + // then + assertNull(cmd); + } + + @Test + public void sensorTemperatureCommandReturnsNull() { + // given & when + final String cmd = commandHandler.toAnelCommandAndUnsetState(STATE_HUT, + IAnelConstants.CHANNEL_SENSOR_TEMPERATURE, new DecimalType("1.0"), "a"); + // then + assertNull(cmd); + } + + @Test + public void relayChannelIdIndex() { + for (int i = 0; i < IAnelConstants.CHANNEL_RELAY_STATE.size(); i++) { + final String relayStateChannelId = IAnelConstants.CHANNEL_RELAY_STATE.get(i); + final String relayIndex = relayStateChannelId.substring(1, 2); + final String expectedIndex = String.valueOf(i + 1); + assertThat(relayIndex, equalTo(expectedIndex)); + } + } + + @Test + public void ioChannelIdIndex() { + for (int i = 0; i < IAnelConstants.CHANNEL_IO_STATE.size(); i++) { + final String ioStateChannelId = IAnelConstants.CHANNEL_IO_STATE.get(i); + final String ioIndex = ioStateChannelId.substring(2, 3); + final String expectedIndex = String.valueOf(i + 1); + assertThat(ioIndex, equalTo(expectedIndex)); + } + } +} diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java new file mode 100644 index 0000000000000..a8a1a3fc97592 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateTest.java @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.anel.internal.state.AnelState; + +/** + * This class tests {@link AnelState}. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelStateTest implements IAnelTestStatus { + + @Test + public void parseHomeV46Status() { + final AnelState state = AnelState.of(STATUS_HOME_V46); + assertThat(state.name, equalTo("NET-CONTROL")); + assertThat(state.ip, equalTo("192.168.0.63")); + assertThat(state.mac, equalTo("0.5.163.21.4.71")); + assertNull(state.temperature); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], equalTo("Nr. " + i)); + assertThat(state.relayState[i - 1], is(i % 2 == 1)); + assertThat(state.relayLocked[i - 1], is(i > 3)); // 248 is binary for: 11111000, so first 3 are not locked + } + for (int i = 1; i <= 8; i++) { + assertNull(state.ioName[i - 1]); + assertNull(state.ioState[i - 1]); + assertNull(state.ioIsInput[i - 1]); + } + assertNull(state.sensorTemperature); + assertNull(state.sensorBrightness); + assertNull(state.sensorHumidity); + } + + @Test + public void parseLockedStates() { + final AnelState state = AnelState.of(STATUS_HOME_V46.replaceAll(":\\d+:80:", ":236:80:")); + assertThat(state.relayLocked[0], is(false)); + assertThat(state.relayLocked[1], is(false)); + assertThat(state.relayLocked[2], is(true)); + assertThat(state.relayLocked[3], is(true)); + assertThat(state.relayLocked[4], is(false)); + assertThat(state.relayLocked[5], is(true)); + assertThat(state.relayLocked[6], is(true)); + assertThat(state.relayLocked[7], is(true)); + } + + @Test + public void parseHutV65Status() { + final AnelState state = AnelState.of(STATUS_HUT_V65); + assertThat(state.name, equalTo("NET-CONTROL")); + assertThat(state.ip, equalTo("192.168.0.64")); + assertThat(state.mac, equalTo("0.5.163.17.9.116")); + assertThat(state.temperature, equalTo("27.0")); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], equalTo("Nr." + i)); + assertThat(state.relayState[i - 1], is(i % 2 == 0)); + assertThat(state.relayLocked[i - 1], is(i > 3)); // 248 is binary for: 11111000, so first 3 are not locked + } + for (int i = 1; i <= 8; i++) { + assertThat(state.ioName[i - 1], equalTo("IO-" + i)); + assertThat(state.ioState[i - 1], is(false)); + assertThat(state.ioIsInput[i - 1], is(i >= 5)); + } + assertNull(state.sensorTemperature); + assertNull(state.sensorBrightness); + assertNull(state.sensorHumidity); + } + + @Test + public void parseHutV5Status() { + final AnelState state = AnelState.of(STATUS_HUT_V5); + assertThat(state.name, equalTo("ANEL1")); + assertThat(state.ip, equalTo("192.168.0.244")); + assertThat(state.mac, equalTo("0.5.163.14.7.91")); + assertThat(state.temperature, equalTo("27.3")); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], matchesPattern(".+")); + assertThat(state.relayState[i - 1], is(false)); + assertThat(state.relayLocked[i - 1], is(false)); + } + for (int i = 1; i <= 8; i++) { + assertThat(state.ioName[i - 1], matchesPattern(".+")); + assertThat(state.ioState[i - 1], is(true)); + assertThat(state.ioIsInput[i - 1], is(true)); + } + assertNull(state.sensorTemperature); + assertNull(state.sensorBrightness); + assertNull(state.sensorHumidity); + } + + @Test + public void parseHutV61StatusAndSensor() { + final AnelState state = AnelState.of(STATUS_HUT_V61_POW_SENSOR); + assertThat(state.name, equalTo("NET-CONTROL")); + assertThat(state.ip, equalTo("192.168.178.148")); + assertThat(state.mac, equalTo("0.4.163.10.9.107")); + assertThat(state.temperature, equalTo("27.7")); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], equalTo("Nr. " + i)); + assertThat(state.relayState[i - 1], is(i <= 3 || i >= 7)); + assertThat(state.relayLocked[i - 1], is(false)); + } + for (int i = 1; i <= 8; i++) { + assertThat(state.ioName[i - 1], equalTo("IO-" + i)); + assertThat(state.ioState[i - 1], is(false)); + assertThat(state.ioIsInput[i - 1], is(false)); + } + assertThat(state.sensorTemperature, equalTo("20.61")); + assertThat(state.sensorHumidity, equalTo("40.7")); + assertThat(state.sensorBrightness, equalTo("7.0")); + } + + @Test + public void parseHutV61StatusWithSensor() { + final AnelState state = AnelState.of(STATUS_HUT_V61_SENSOR); + assertThat(state.name, equalTo("NET-CONTROL")); + assertThat(state.ip, equalTo("192.168.178.148")); + assertThat(state.mac, equalTo("0.4.163.10.9.107")); + assertThat(state.temperature, equalTo("27.7")); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], equalTo("Nr. " + i)); + assertThat(state.relayState[i - 1], is(i <= 3 || i >= 7)); + assertThat(state.relayLocked[i - 1], is(false)); + } + for (int i = 1; i <= 8; i++) { + assertThat(state.ioName[i - 1], equalTo("IO-" + i)); + assertThat(state.ioState[i - 1], is(false)); + assertThat(state.ioIsInput[i - 1], is(false)); + } + assertThat(state.sensorTemperature, equalTo("20.61")); + assertThat(state.sensorHumidity, equalTo("40.7")); + assertThat(state.sensorBrightness, equalTo("7.0")); + } + + @Test + public void parseHutV61StatusWithoutSensor() { + final AnelState state = AnelState.of(STATUS_HUT_V61_POW); + assertThat(state.name, equalTo("NET-CONTROL")); + assertThat(state.ip, equalTo("192.168.178.148")); + assertThat(state.mac, equalTo("0.4.163.10.9.107")); + assertThat(state.temperature, equalTo("27.7")); + for (int i = 1; i <= 8; i++) { + assertThat(state.relayName[i - 1], equalTo("Nr. " + i)); + assertThat(state.relayState[i - 1], is(i <= 3 || i >= 7)); + assertThat(state.relayLocked[i - 1], is(false)); + } + for (int i = 1; i <= 8; i++) { + assertThat(state.ioName[i - 1], equalTo("IO-" + i)); + assertThat(state.ioState[i - 1], is(false)); + assertThat(state.ioIsInput[i - 1], is(false)); + } + assertNull(state.sensorTemperature); + assertNull(state.sensorBrightness); + assertNull(state.sensorHumidity); + } + + @Test + public void colonSeparatorInSwitchNameThrowsException() { + try { + AnelState.of(STATUS_INVALID_NAME); + fail("Status format exception expected because of colon separator in name 'Nr: 3'"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage(), containsString("is expected to be a number but it's not")); + } + } +} diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java new file mode 100644 index 0000000000000..3703b4c33d434 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelStateUpdaterTest.java @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.Test; +import org.openhab.binding.anel.internal.state.AnelState; +import org.openhab.binding.anel.internal.state.AnelStateUpdater; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.State; + +/** + * This class tests {@link AnelStateUpdater}. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public class AnelStateUpdaterTest implements IAnelTestStatus, IAnelConstants { + + private final AnelStateUpdater stateUpdater = new AnelStateUpdater(); + + @Test + public void noStateChange() { + // given + final AnelState oldState = AnelState.of(STATUS_HUT_V5); + final AnelState newState = AnelState.of(STATUS_HUT_V5.replace(":80:", ":81:")); // port is irrelevant + // when + Map updates = stateUpdater.getChannelUpdates(oldState, newState); + // then + assertThat(updates.entrySet(), is(empty())); + } + + @Test + public void fromNullStateUpdatesHome() { + // given + final AnelState newState = AnelState.of(STATUS_HOME_V46); + // when + Map updates = stateUpdater.getChannelUpdates(null, newState); + // then + final Map expected = new HashMap<>(); + expected.put(CHANNEL_NAME, new StringType("NET-CONTROL")); + for (int i = 1; i <= 8; i++) { + expected.put(CHANNEL_RELAY_NAME.get(i - 1), new StringType("Nr. " + i)); + expected.put(CHANNEL_RELAY_STATE.get(i - 1), OnOffType.from(i % 2 == 1)); + expected.put(CHANNEL_RELAY_LOCKED.get(i - 1), OnOffType.from(i > 3)); + } + assertThat(updates, equalTo(expected)); + } + + @Test + public void fromNullStateUpdatesHutPowerSensor() { + // given + final AnelState newState = AnelState.of(STATUS_HUT_V61_POW_SENSOR); + // when + Map updates = stateUpdater.getChannelUpdates(null, newState); + // then + assertThat(updates.size(), is(5 + 8 * 6)); + assertThat(updates.get(CHANNEL_NAME), equalTo(new StringType("NET-CONTROL"))); + assertTemperature(updates.get(CHANNEL_TEMPERATURE), 27.7); + + assertThat(updates.get(CHANNEL_SENSOR_BRIGHTNESS), equalTo(new DecimalType("7"))); + assertThat(updates.get(CHANNEL_SENSOR_HUMIDITY), equalTo(new DecimalType("40.7"))); + assertTemperature(updates.get(CHANNEL_SENSOR_TEMPERATURE), 20.61); + + for (int i = 1; i <= 8; i++) { + assertThat(updates.get(CHANNEL_RELAY_NAME.get(i - 1)), equalTo(new StringType("Nr. " + i))); + assertThat(updates.get(CHANNEL_RELAY_STATE.get(i - 1)), equalTo(OnOffType.from(i <= 3 || i >= 7))); + assertThat(updates.get(CHANNEL_RELAY_LOCKED.get(i - 1)), equalTo(OnOffType.OFF)); + } + for (int i = 1; i <= 8; i++) { + assertThat(updates.get(CHANNEL_IO_NAME.get(i - 1)), equalTo(new StringType("IO-" + i))); + assertThat(updates.get(CHANNEL_IO_STATE.get(i - 1)), equalTo(OnOffType.OFF)); + assertThat(updates.get(CHANNEL_IO_MODE.get(i - 1)), equalTo(OnOffType.OFF)); + } + } + + @Test + public void singleRelayStateChange() { + // given + final AnelState oldState = AnelState.of(STATUS_HUT_V61_POW_SENSOR); + final AnelState newState = AnelState.of(STATUS_HUT_V61_POW_SENSOR.replace("Nr. 4,0", "Nr. 4,1")); + // when + Map updates = stateUpdater.getChannelUpdates(oldState, newState); + // then + final Map expected = new HashMap<>(); + expected.put(CHANNEL_RELAY_STATE.get(3), OnOffType.ON); + assertThat(updates, equalTo(expected)); + } + + @Test + public void temperatureChange() { + // given + final AnelState oldState = AnelState.of(STATUS_HUT_V65); + final AnelState newState = AnelState.of(STATUS_HUT_V65.replaceFirst(":27\\.0(.)C:", ":27.1°C:")); + // when + Map updates = stateUpdater.getChannelUpdates(oldState, newState); + // then + assertThat(updates.size(), is(1)); + assertTemperature(updates.get(CHANNEL_TEMPERATURE), 27.1); + } + + @Test + public void singleSensorStatesChange() { + // given + final AnelState oldState = AnelState.of(STATUS_HUT_V61_SENSOR); + final AnelState newState = AnelState.of(STATUS_HUT_V61_SENSOR.replace(":s:20.61:40.7:7.0:", ":s:20.6:40:7.1:")); + // when + Map updates = stateUpdater.getChannelUpdates(oldState, newState); + // then + assertThat(updates.size(), is(3)); + assertThat(updates.get(CHANNEL_SENSOR_BRIGHTNESS), equalTo(new DecimalType("7.1"))); + assertThat(updates.get(CHANNEL_SENSOR_HUMIDITY), equalTo(new DecimalType("40"))); + assertTemperature(updates.get(CHANNEL_SENSOR_TEMPERATURE), 20.6); + } + + private void assertTemperature(@Nullable State state, double value) { + assertThat(state, isA(QuantityType.class)); + if (state instanceof QuantityType) { + assertThat(((QuantityType) state).doubleValue(), closeTo(value, 0.0001d)); + } + } +} diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelUdpConnectorTest.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelUdpConnectorTest.java new file mode 100644 index 0000000000000..60f34e4ee5c1a --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/AnelUdpConnectorTest.java @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +import java.util.LinkedHashSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.openhab.binding.anel.internal.auth.AnelAuthentication; +import org.openhab.binding.anel.internal.auth.AnelAuthentication.AuthMethod; + +/** + * This test requires a physical Anel device! + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +@Disabled // requires a physically available device in the local network +public class AnelUdpConnectorTest { + + /* + * The IP and ports for the Anel device under test. + */ + private static final String HOST = "192.168.6.63"; // 63 / 64 + private static final int PORT_SEND = 7500; // 7500 / 75001 + private static final int PORT_RECEIVE = 7700; // 7700 / 7701 + private static final String USER = "user7"; + private static final String PASSWORD = "anel"; + + /* The device may have an internal delay of 200ms, plus network latency! Should not be <1sec. */ + private static final int WAIT_FOR_DEVICE_RESPONSE_MS = 1000; + + private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(); + + private final Queue receivedMessages = new ConcurrentLinkedQueue<>(); + + @Nullable + private static AnelUdpConnector connector; + + @BeforeAll + public static void prepareConnector() { + connector = new AnelUdpConnector(HOST, PORT_RECEIVE, PORT_SEND, EXECUTOR_SERVICE); + } + + @AfterAll + @SuppressWarnings("null") + public static void closeConnection() { + connector.disconnect(); + } + + @BeforeEach + @SuppressWarnings("null") + public void connectIfNotYetConnected() throws Exception { + Thread.sleep(100); + receivedMessages.clear(); // clear all previously received messages + + if (!connector.isConnected()) { + connector.connect(receivedMessages::offer, false); + } + } + + @Test + public void connectionTest() throws Exception { + final String response = sendAndReceiveSingle(IAnelConstants.BROADCAST_DISCOVERY_MSG); + /* + * Expected example response: + * "NET-PwrCtrl:NET-CONTROL :192.168.0.244:255.255.255.0:192.168.0.1:0.5.163.21.4.71:Nr. 1,0:Nr. 2,1:Nr. 3,0:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,0:Nr. 8,0:248:80:NET-PWRCTRL_04.6:H:xor:" + */ + assertThat(response, startsWith(IAnelConstants.STATUS_RESPONSE_PREFIX + IAnelConstants.STATUS_SEPARATOR)); + } + + @Test + public void toggleSwitch1() throws Exception { + toggleSwitch(1); + } + + @Test + public void toggleSwitch2() throws Exception { + toggleSwitch(2); + } + + @Test + public void toggleSwitch3() throws Exception { + toggleSwitch(3); + } + + @Test + public void toggleSwitch4() throws Exception { + toggleSwitch(4); + } + + @Test + public void toggleSwitch5() throws Exception { + toggleSwitch(5); + } + + @Test + public void toggleSwitch6() throws Exception { + toggleSwitch(6); + } + + @Test + public void toggleSwitch7() throws Exception { + toggleSwitch(7); + } + + @Test + public void toggleSwitch8() throws Exception { + toggleSwitch(8); + } + + private void toggleSwitch(int switchNr) throws Exception { + assertThat(switchNr, allOf(greaterThan(0), lessThan(9))); + final int index = 5 + switchNr; + + // get state of switch 1 + final String status = sendAndReceiveSingle(IAnelConstants.BROADCAST_DISCOVERY_MSG); + final String[] segments = status.split(IAnelConstants.STATUS_SEPARATOR); + assertThat(segments[5 + switchNr], anyOf(endsWith(",1"), endsWith(",0"))); + final boolean switch1state = segments[index].endsWith(",1"); + + // toggle state of switch 1 + final String auth = AnelAuthentication.getUserPasswordString(USER, PASSWORD, AuthMethod.of(status)); + final String command = "Sw_" + (switch1state ? "off" : "on") + String.valueOf(switchNr) + auth; + final String status2 = sendAndReceiveSingle(command); + + // assert new state of switch 1 + assertThat(status2.trim(), not(endsWith(":Err"))); + final String[] segments2 = status2.split(IAnelConstants.STATUS_SEPARATOR); + final String expectedState = segments2[index].substring(0, segments2[index].length() - 1) + + (switch1state ? "0" : "1"); + assertThat(segments2[index], equalTo(expectedState)); + } + + @Test + public void withoutCredentials() throws Exception { + final String status2 = sendAndReceiveSingle("Sw_on1"); + assertThat(status2.trim(), endsWith(":NoPass:Err")); + Thread.sleep(3100); // locked for 3 seconds + } + + private String sendAndReceiveSingle(final String msg) throws Exception { + final Set response = sendAndReceive(msg); + assertThat(response, hasSize(1)); + return response.iterator().next(); + } + + @SuppressWarnings("null") + private Set sendAndReceive(final String msg) throws Exception { + assertThat(receivedMessages, is(empty())); + connector.send(msg); + Thread.sleep(WAIT_FOR_DEVICE_RESPONSE_MS); + final Set response = new LinkedHashSet<>(); + while (!receivedMessages.isEmpty()) { + final String receivedMessage = receivedMessages.poll(); + if (receivedMessage != null) { + response.add(receivedMessage); + } + } + return response; + } +} diff --git a/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/IAnelTestStatus.java b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/IAnelTestStatus.java new file mode 100644 index 0000000000000..61505b03696b0 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/test/java/org/openhab/binding/anel/internal/IAnelTestStatus.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.anel.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Some constants used in the unit tests. + * + * @author Patrick Koenemann - Initial contribution + */ +@NonNullByDefault +public interface IAnelTestStatus { + + String STATUS_INVALID_NAME = "NET-PwrCtrl:NET-CONTROL :192.168.6.63:255.255.255.0:192.168.6.1:0.4.163.21.4.71:" + + "Nr. 1,0:Nr. 2,1:Nr: 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,0:Nr. 8,0:248:80:NET-PWRCTRL_04.6:H:xor:"; + String STATUS_HUT_V61_POW = "NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:" + + "Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:" + + "IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_06.1:h:" + + "p:225.9:0.0004:50.056:0.04:0.00:0.0:1.0000:xor:"; + String STATUS_HUT_V61_SENSOR = "NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:" + + "Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:" + + "IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_06.1:h:" + + "n:s:20.61:40.7:7.0:xor:"; + String STATUS_HUT_V61_POW_SENSOR = "NET-PwrCtrl:NET-CONTROL :192.168.178.148:255.255.255.0:192.168.178.1:0.4.163.10.9.107:" + + "Nr. 1,1:Nr. 2,1:Nr. 3,1:Nr. 4,0:Nr. 5,0:Nr. 6,0:Nr. 7,1:Nr. 8,1:0:80:" + + "IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,0,0:IO-6,0,0:IO-7,0,0:IO-8,0,0:27.7°C:NET-PWRCTRL_06.1:h:" + + "p:225.9:0.0004:50.056:0.04:0.00:0.0:1.0000:s:20.61:40.7:7.0:xor"; + String STATUS_HUT_V5 = "NET-PwrCtrl:ANEL1 :192.168.0.244:255.255.255.0:192.168.0.1:0.5.163.14.7.91:" + + "hoch,0:links hoch,0:runter,0:rechts run,0:runter,0:hoch,0:links runt,0:rechts hoc,0:0:80:" + + "WHN_UP,1,1:LI_DOWN,1,1:RE_DOWN,1,1:LI_UP,1,1:RE_UP,1,1:DOWN,1,1:DOWN,1,1:UP,1,1:27.3°C:NET-PWRCTRL_05.0"; + String STATUS_HUT_V65 = "NET-PwrCtrl:NET-CONTROL :192.168.0.64:255.255.255.0:192.168.6.1:0.5.163.17.9.116:" + + "Nr.1,0:Nr.2,1:Nr.3,0:Nr.4,1:Nr.5,0:Nr.6,1:Nr.7,0:Nr.8,1:248:80:" + + "IO-1,0,0:IO-2,0,0:IO-3,0,0:IO-4,0,0:IO-5,1,0:IO-6,1,0:IO-7,1,0:IO-8,1,0:27.0�C:NET-PWRCTRL_06.5:h:n:xor:"; + String STATUS_HOME_V46 = "NET-PwrCtrl:NET-CONTROL :192.168.0.63:255.255.255.0:192.168.6.1:0.5.163.21.4.71:" + + "Nr. 1,1:Nr. 2,0:Nr. 3,1:Nr. 4,0:Nr. 5,1:Nr. 6,0:Nr. 7,1:Nr. 8,0:248:80:NET-PWRCTRL_04.6:H:xor:"; +} diff --git a/bundles/pom.xml b/bundles/pom.xml index 9635e6296d4cc..2932a8d104698 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -55,6 +55,7 @@ org.openhab.binding.ambientweather org.openhab.binding.amplipi org.openhab.binding.androiddebugbridge + org.openhab.binding.anel org.openhab.binding.astro org.openhab.binding.atlona org.openhab.binding.autelis From 9a334120473c091a603358b55f7bf078a2ec2d80 Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 29 Nov 2021 10:57:58 +0100 Subject: [PATCH 148/361] [miio] fix Error parsing miot data null for new miot devices (#11658) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- .../java/org/openhab/binding/miio/internal/miot/MiotParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java index b5051a819c286..cfae463db9d4b 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java @@ -63,7 +63,7 @@ public class MiotParser { private final Logger logger = LoggerFactory.getLogger(MiotParser.class); - private static final String BASEURL = "http://miot-spec.org/miot-spec-v2/"; + private static final String BASEURL = "https://miot-spec.org/miot-spec-v2/"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final boolean SKIP_SIID_1 = true; From cb7c1ff8068174c9d00b7c66e8dae9d4ee4a883e Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 29 Nov 2021 11:00:19 +0100 Subject: [PATCH 149/361] [miio] Add support Mi Fresh Air Ventilator C1-80 zhimi.airfresh.ua1 (#11579) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 80 +++-- .../binding/miio/internal/MiIoDevices.java | 1 + .../miio/internal/miot/MiotParser.java | 2 +- .../database/careli.fryer.maf01-miot.json | 2 +- .../database/careli.fryer.maf02-miot.json | 2 +- .../database/cgllc.airm.cgdn1-miot.json | 2 +- .../database/dmaker.fan.p15-miot.json | 2 +- .../database/dmaker.fan.p18-miot.json | 2 +- .../database/dmaker.fan.p8-miot.json | 2 +- .../database/dreame.vacuum.mc1808-miot.json | 2 +- .../database/dreame.vacuum.p2008-miot.json | 2 +- .../database/dreame.vacuum.p2156o-miot.json | 2 +- .../database/mmgg.pet_waterer.s1-miot.json | 2 +- .../database/mmgg.pet_waterer.s2-miot.json | 2 +- .../database/viomi.vacuum.v18-miot.json | 2 +- .../database/zhimi.airfresh.ua1-miot.json | 274 ++++++++++++++++++ .../database/zhimi.airpurifier.ma4-miot.json | 2 +- .../database/zhimi.airpurifier.mb3-miot.json | 2 +- .../database/zhimi.heater.ma3-miot.json | 2 +- 19 files changed, 351 insertions(+), 36 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index c8251f60c5829..66f58a5329c13 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -180,10 +180,10 @@ Currently the miio binding supports more than 300 different models. | Device | ThingType | Device Model | Supported | Remark | |------------------------------|------------------|------------------------|-----------|------------| | AUX Smart Air Conditioner | miio:unsupported | aux.aircondition.v1 | No | | -| Mi Air Frying Pan | miio:basic | [careli.fryer.maf01](#careli-fryer-maf01) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Smart Air Fryer (3.5L) | miio:basic | [careli.fryer.maf02](#careli-fryer-maf02) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-custom-cook","siid":3,"aiid":1,"in":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cooking","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Air Frying Pan | miio:basic | [careli.fryer.maf03](#careli-fryer-maf03) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Qingping Air Monitor Lite | miio:basic | [cgllc.airm.cgdn1](#cgllc-airm-cgdn1) | Yes | Identified manual actions for execution
`action{"did":"settings-set-start-time","siid":9,"aiid":2,"in":[2.0]}`
`action{"did":"settings-set-end-time","siid":9,"aiid":3,"in":[3.0]}`
`action{"did":"settings-set-frequency","siid":9,"aiid":4,"in":[4.0]}`
`action{"did":"settings-set-screen-off","siid":9,"aiid":5,"in":[5.0]}`
`action{"did":"settings-set-device-off","siid":9,"aiid":6,"in":[6.0]}`
`action{"did":"settings-set-temp-unit","siid":9,"aiid":7,"in":[7.0]}`
Please test and feedback if they are working to they can be linked to a channel. | +| Mi Air Frying Pan | miio:basic | [careli.fryer.maf01](#careli-fryer-maf01) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Air Fryer (3.5L) | miio:basic | [careli.fryer.maf02](#careli-fryer-maf02) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-custom-cook","siid":3,"aiid":1,"in":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cooking","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Frying Pan | miio:basic | [careli.fryer.maf03](#careli-fryer-maf03) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Qingping Air Monitor Lite | miio:basic | [cgllc.airm.cgdn1](#cgllc-airm-cgdn1) | Yes | Identified manual actions for execution
`action{"did":"settings-set-start-time","siid":9,"aiid":2,"in":[2.0]}`
`action{"did":"settings-set-end-time","siid":9,"aiid":3,"in":[3.0]}`
`action{"did":"settings-set-frequency","siid":9,"aiid":4,"in":[4.0]}`
`action{"did":"settings-set-screen-off","siid":9,"aiid":5,"in":[5.0]}`
`action{"did":"settings-set-device-off","siid":9,"aiid":6,"in":[6.0]}`
`action{"did":"settings-set-temp-unit","siid":9,"aiid":7,"in":[7.0]}`
Please test and feedback if they are working so they can be linked to a channel. | | Mi Multifunction Air Monitor | miio:basic | [cgllc.airmonitor.b1](#cgllc-airmonitor-b1) | Yes | | | Qingping Air Monitor | miio:basic | [cgllc.airmonitor.s1](#cgllc-airmonitor-s1) | Yes | | | Mi Universal Remote | miio:unsupported | chuangmi.ir.v2 | No | | @@ -209,19 +209,19 @@ Currently the miio binding supports more than 300 different models. | Mi Smart Humidifier | miio:basic | [deerma.humidifier.mjjsq](#deerma-humidifier-mjjsq) | Yes | | | Mi Fresh Air Ventilator A1-150 | miio:basic | [dmaker.airfresh.a1](#dmaker-airfresh-a1) | Yes | | | Mi Fresh Air Ventilator | miio:basic | [dmaker.airfresh.t2017](#dmaker-airfresh-t2017) | Yes | | -| Mi Smart Standing Fan 2 Lite | miio:basic | [dmaker.fan.1c](#dmaker-fan-1c) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Standing Fan 2 Lite | miio:basic | [dmaker.fan.1c](#dmaker-fan-1c) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Standing Fan 1X | miio:basic | [dmaker.fan.p5](#dmaker-fan-p5) | Yes | | -| Mi Smart Standing Fan 1C | miio:basic | [dmaker.fan.p8](#dmaker-fan-p8) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Standing Fan 1C | miio:basic | [dmaker.fan.p8](#dmaker-fan-p8) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Tower Fan | miio:basic | [dmaker.fan.p9](#dmaker-fan-p9) | Yes | | | Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p10](#dmaker-fan-p10) | Yes | | -| Mi Smart Standing Fan Pro | miio:basic | [dmaker.fan.p15](#dmaker-fan-p15) | Yes | Identified manual actions for execution
`action{"did":"off-delay-time-toggle","siid":3,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel. | -| Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p18](#dmaker-fan-p18) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Robot Vacuum Mop 1C STYTJ01ZHM | miio:basic | [dreame.vacuum.mc1808](#dreame-vacuum-mc1808) | Yes | Identified manual actions for execution
`action{"did":"battery-start-charge","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-start-sweep","siid":3,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":3,"aiid":2,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":26,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":27,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":28,"aiid":1,"in":[]}`
`action{"did":"clean-start-clean","siid":18,"aiid":1,"in":[]}`
`action{"did":"clean-stop-clean","siid":18,"aiid":2,"in":[]}`
`action{"did":"remote-start-remote","siid":21,"aiid":1,"in":[1.0, 2.0]}`
`action{"did":"remote-stop-remote","siid":21,"aiid":2,"in":[]}`
`action{"did":"remote-exit-remote","siid":21,"aiid":3,"in":[]}`
`action{"did":"map-map-req","siid":23,"aiid":1,"in":[2.0]}`
`action{"did":"audio-position","siid":24,"aiid":1,"in":[]}`
`action{"did":"audio-set-voice","siid":24,"aiid":2,"in":[]}`
`action{"did":"audio-play-sound","siid":24,"aiid":3,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel. | -| Dreame Robot Vacuum-Mop F9 | miio:basic | [dreame.vacuum.p2008](#dreame-vacuum-p2008) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Standing Fan Pro | miio:basic | [dmaker.fan.p15](#dmaker-fan-p15) | Yes | Identified manual actions for execution
`action{"did":"off-delay-time-toggle","siid":3,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel. | +| Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p18](#dmaker-fan-p18) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Robot Vacuum Mop 1C STYTJ01ZHM | miio:basic | [dreame.vacuum.mc1808](#dreame-vacuum-mc1808) | Yes | Identified manual actions for execution
`action{"did":"battery-start-charge","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-start-sweep","siid":3,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":3,"aiid":2,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":26,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":27,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":28,"aiid":1,"in":[]}`
`action{"did":"clean-start-clean","siid":18,"aiid":1,"in":[]}`
`action{"did":"clean-stop-clean","siid":18,"aiid":2,"in":[]}`
`action{"did":"remote-start-remote","siid":21,"aiid":1,"in":[1.0, 2.0]}`
`action{"did":"remote-stop-remote","siid":21,"aiid":2,"in":[]}`
`action{"did":"remote-exit-remote","siid":21,"aiid":3,"in":[]}`
`action{"did":"map-map-req","siid":23,"aiid":1,"in":[2.0]}`
`action{"did":"audio-position","siid":24,"aiid":1,"in":[]}`
`action{"did":"audio-set-voice","siid":24,"aiid":2,"in":[]}`
`action{"did":"audio-play-sound","siid":24,"aiid":3,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel. | +| Dreame Robot Vacuum-Mop F9 | miio:basic | [dreame.vacuum.p2008](#dreame-vacuum-p2008) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Dreame Robot Vacuum D9 | miio:basic | [dreame.vacuum.p2009](#dreame-vacuum-p2009) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| | Trouver Robot LDS Vacuum-Mop Finder | miio:basic | [dreame.vacuum.p2036](#dreame-vacuum-p2036) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| -| Mi Robot Vacuum-Mop 2 Pro+ | miio:basic | [dreame.vacuum.p2041o](#dreame-vacuum-p2041o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| MOVA Z500 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2156o](#dreame-vacuum-p2156o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Robot Vacuum-Mop 2 Pro+ | miio:basic | [dreame.vacuum.p2041o](#dreame-vacuum-p2041o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| MOVA Z500 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2156o](#dreame-vacuum-p2156o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MOVA L600 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2157](#dreame-vacuum-p2157) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| | HUIZUO ARIES For Bedroom | miio:basic | [huayi.light.ari013](#huayi-light-ari013) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO ARIES For Living Room | miio:basic | [huayi.light.aries](#huayi-light-aries) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -257,10 +257,10 @@ Currently the miio binding supports more than 300 different models. | Midea Air Conditioner v2 | miio:unsupported | midea.aircondition.v2 | No | | | Midea AC-Cool Golden | miio:unsupported | midea.aircondition.xa1 | No | | | Mi Robot Vacuum-Mop Essential | miio:basic | [mijia.vacuum.v2](#mijia-vacuum-v2) | Yes | This device may be overwhelmed if refresh is too frequent, slowing down the responses. Suggest to increase refresh time to 120 seconds | -| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s1](#mmgg-pet_waterer-s1) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s2](#mmgg-pet_waterer-s2) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s3](#mmgg-pet_waterer-s3) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| XIAOWAN Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s4](#mmgg-pet_waterer-s4) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s1](#mmgg-pet_waterer-s1) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s2](#mmgg-pet_waterer-s2) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mijia Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s3](#mmgg-pet_waterer-s3) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| XIAOWAN Smart Pet Water Dispenser | miio:basic | [mmgg.pet_waterer.s4](#mmgg-pet_waterer-s4) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":3,"aiid":1,"in":[]}`
`action{"did":"filter-cotton-reset-cotton-life","siid":5,"aiid":1,"in":[]}`
`action{"did":"remain-clean-time-reset-clean-time","siid":6,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MR.BOND | miio:basic | [mrbond.airer.m1pro](#mrbond-airer-m1pro) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MR.BOND | miio:basic | [mrbond.airer.m1s](#mrbond-airer-m1s) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MR.BOND | miio:basic | [mrbond.airer.m1super](#mrbond-airer-m1super) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -346,7 +346,7 @@ Currently the miio binding supports more than 300 different models. | Viomi Cleaning Robot V-RVCLM21B | miio:basic | [viomi.vacuum.v6](#viomi-vacuum-v6) | Yes | | | Mi Robot Vacuum-Mop P | miio:basic | [viomi.vacuum.v7](#viomi-vacuum-v7) | Yes | | | Mi Robot Vacuum-Mop P | miio:basic | [viomi.vacuum.v8](#viomi-vacuum-v8) | Yes | | -| Viomi S9 | miio:basic | [viomi.vacuum.v18](#viomi-vacuum-v18) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"vacuum-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"vacuum-start-charge","siid":2,"aiid":4,"in":[]}`
`action{"did":"vacuum-stop-massage","siid":2,"aiid":5,"in":[]}`
`action{"did":"vacuum-start-mop","siid":2,"aiid":6,"in":[]}`
`action{"did":"vacuum-start-only-sweep","siid":2,"aiid":7,"in":[]}`
`action{"did":"vacuum-start-sweep-mop","siid":2,"aiid":8,"in":[]}`
`action{"did":"viomi-vacuum-reset-map","siid":4,"aiid":7,"in":[]}`
`action{"did":"viomi-vacuum-set-calibration","siid":4,"aiid":10,"in":[]}`
`action{"did":"viomi-vacuum-reset-consumable","siid":4,"aiid":11,"in":[35.0]}`
`action{"did":"viomi-vacuum-set-room-clean","siid":4,"aiid":13,"in":[36.0, 37.0, 38.0]}`
`action{"did":"order-del","siid":5,"aiid":2,"in":[1.0]}`
`action{"did":"order-get","siid":5,"aiid":3,"in":[]}`
`action{"did":"point-zone-start-point-clean","siid":6,"aiid":1,"in":[]}`
`action{"did":"point-zone-pause-point-clean","siid":6,"aiid":2,"in":[]}`
`action{"did":"point-zone-start-zone-clean","siid":6,"aiid":5,"in":[]}`
`action{"did":"point-zone-pause-zone-clean","siid":6,"aiid":6,"in":[]}`
`action{"did":"map-upload-by-maptype","siid":7,"aiid":1,"in":[]}`
`action{"did":"map-upload-by-mapid","siid":7,"aiid":2,"in":[]}`
`action{"did":"map-set-cur-map","siid":7,"aiid":3,"in":[2.0, 15.0]}`
`action{"did":"map-del-map","siid":7,"aiid":5,"in":[2.0]}`
`action{"did":"map-rename-map","siid":7,"aiid":7,"in":[2.0, 4.0]}`
`action{"did":"map-arrange-room","siid":7,"aiid":8,"in":[2.0, 5.0, 6.0, 14.0]}`
`action{"did":"map-split-room","siid":7,"aiid":9,"in":[2.0, 5.0, 7.0, 8.0, 14.0]}`
`action{"did":"map-rename-room","siid":7,"aiid":10,"in":[2.0, 7.0, 9.0, 14.0]}`
`action{"did":"map-get-map-list","siid":7,"aiid":11,"in":[]}`
`action{"did":"map-get-cleaning-path","siid":7,"aiid":12,"in":[12.0]}`
`action{"did":"map-set-new-map","siid":7,"aiid":13,"in":[]}`
`action{"did":"map-deal-new-map","siid":7,"aiid":14,"in":[16.0]}`
`action{"did":"voice-find-device","siid":8,"aiid":2,"in":[]}`
`action{"did":"voice-download-voice","siid":8,"aiid":3,"in":[3.0, 7.0, 8.0]}`
`action{"did":"voice-get-downloadstatus","siid":8,"aiid":4,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Viomi S9 | miio:basic | [viomi.vacuum.v18](#viomi-vacuum-v18) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"vacuum-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"vacuum-start-charge","siid":2,"aiid":4,"in":[]}`
`action{"did":"vacuum-stop-massage","siid":2,"aiid":5,"in":[]}`
`action{"did":"vacuum-start-mop","siid":2,"aiid":6,"in":[]}`
`action{"did":"vacuum-start-only-sweep","siid":2,"aiid":7,"in":[]}`
`action{"did":"vacuum-start-sweep-mop","siid":2,"aiid":8,"in":[]}`
`action{"did":"viomi-vacuum-reset-map","siid":4,"aiid":7,"in":[]}`
`action{"did":"viomi-vacuum-set-calibration","siid":4,"aiid":10,"in":[]}`
`action{"did":"viomi-vacuum-reset-consumable","siid":4,"aiid":11,"in":[35.0]}`
`action{"did":"viomi-vacuum-set-room-clean","siid":4,"aiid":13,"in":[36.0, 37.0, 38.0]}`
`action{"did":"order-del","siid":5,"aiid":2,"in":[1.0]}`
`action{"did":"order-get","siid":5,"aiid":3,"in":[]}`
`action{"did":"point-zone-start-point-clean","siid":6,"aiid":1,"in":[]}`
`action{"did":"point-zone-pause-point-clean","siid":6,"aiid":2,"in":[]}`
`action{"did":"point-zone-start-zone-clean","siid":6,"aiid":5,"in":[]}`
`action{"did":"point-zone-pause-zone-clean","siid":6,"aiid":6,"in":[]}`
`action{"did":"map-upload-by-maptype","siid":7,"aiid":1,"in":[]}`
`action{"did":"map-upload-by-mapid","siid":7,"aiid":2,"in":[]}`
`action{"did":"map-set-cur-map","siid":7,"aiid":3,"in":[2.0, 15.0]}`
`action{"did":"map-del-map","siid":7,"aiid":5,"in":[2.0]}`
`action{"did":"map-rename-map","siid":7,"aiid":7,"in":[2.0, 4.0]}`
`action{"did":"map-arrange-room","siid":7,"aiid":8,"in":[2.0, 5.0, 6.0, 14.0]}`
`action{"did":"map-split-room","siid":7,"aiid":9,"in":[2.0, 5.0, 7.0, 8.0, 14.0]}`
`action{"did":"map-rename-room","siid":7,"aiid":10,"in":[2.0, 7.0, 9.0, 14.0]}`
`action{"did":"map-get-map-list","siid":7,"aiid":11,"in":[]}`
`action{"did":"map-get-cleaning-path","siid":7,"aiid":12,"in":[12.0]}`
`action{"did":"map-set-new-map","siid":7,"aiid":13,"in":[]}`
`action{"did":"map-deal-new-map","siid":7,"aiid":14,"in":[16.0]}`
`action{"did":"voice-find-device","siid":8,"aiid":2,"in":[]}`
`action{"did":"voice-download-voice","siid":8,"aiid":3,"in":[3.0, 7.0, 8.0]}`
`action{"did":"voice-get-downloadstatus","siid":8,"aiid":4,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | VIOMI Internet Electric Water Heater 1A (60L) | miio:basic | [viomi.waterheater.e1](#viomi-waterheater-e1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Inverter Air Conditioner (1.5HP) | miio:basic | [xiaomi.aircondition.ma1](#xiaomi-aircondition-ma1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Inverter Air Conditioner (1.5HP, China Energy Label Level 1) | miio:basic | [xiaomi.aircondition.ma2](#xiaomi-aircondition-ma2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -466,14 +466,15 @@ Currently the miio binding supports more than 300 different models. | Mi Water Purifier v4 | miio:basic | [yunmi.waterpurifier.v4](#yunmi-waterpurifier-v4) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Ventilation System | miio:basic | [zhimi.airfresh.va2](#zhimi-airfresh-va2) | Yes | | | Smartmi Fresh Air System (Heating) | miio:basic | [zhimi.airfresh.va4](#zhimi-airfresh-va4) | Yes | | +| Mi Fresh Air Ventilator C1-80 | miio:basic | [zhimi.airfresh.ua1](#zhimi-airfresh-ua1) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[1.0]}`
Please test and feedback if they are working so they can be linked to a channel. | | Mi PM2.5 Air Quality Monitor | miio:basic | [zhimi.airmonitor.v1](#zhimi-airmonitor-v1) | Yes | | | Mi Air Purifier 2 (mini) | miio:basic | [zhimi.airpurifier.m1](#zhimi-airpurifier-m1) | Yes | | | Mi Air Purifier 2 | miio:basic | [zhimi.airpurifier.m2](#zhimi-airpurifier-m2) | Yes | | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.ma1](#zhimi-airpurifier-ma1) | Yes | | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.ma2](#zhimi-airpurifier-ma2) | Yes | | -| Mi Air Purifier 3 | miio:basic | [zhimi.airpurifier.ma4](#zhimi-airpurifier-ma4) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Purifier 3 | miio:basic | [zhimi.airpurifier.ma4](#zhimi-airpurifier-ma4) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.mb1](#zhimi-airpurifier-mb1) | Yes | | -| Mi Air Purifier 3/3H | miio:basic | [zhimi.airpurifier.mb3](#zhimi-airpurifier-mb3) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Purifier 3/3H | miio:basic | [zhimi.airpurifier.mb3](#zhimi-airpurifier-mb3) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Air Purifier 3C | miio:basic | [zhimi.airpurifier.mb4](#zhimi-airpurifier-mb4) | Yes | Specified action for filter reset
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[3.0]}`
However, this has not been successfully tested yet. | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.mc1](#zhimi-airpurifier-mc1) | Yes | | | Mi Air Purifier 2H | miio:basic | [zhimi.airpurifier.mc2](#zhimi-airpurifier-mc2) | Yes | | @@ -498,7 +499,7 @@ Currently the miio binding supports more than 300 different models. | Smartmi Standing Fan 2S | miio:basic | [zhimi.fan.za4](#zhimi-fan-za4) | Yes | | | Smartmi Standing Fan 3 | miio:basic | [zhimi.fan.za5](#zhimi-fan-za5) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Space Heater S | miio:basic | [zhimi.heater.ma2](#zhimi-heater-ma2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Smart Baseboard Heater E | miio:basic | [zhimi.heater.ma3](#zhimi-heater-ma3) | Yes | Identified manual actions for execution
`action{"did":"private-service-toggle-switch","siid":8,"aiid":1,"in":[]}`
Please test and feedback if they are working to they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Baseboard Heater E | miio:basic | [zhimi.heater.ma3](#zhimi-heater-ma3) | Yes | Identified manual actions for execution
`action{"did":"private-service-toggle-switch","siid":8,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Space Heater S | miio:basic | [zhimi.heater.mc2](#zhimi-heater-mc2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Smart Fan | miio:basic | [zhimi.heater.na1](#zhimi-heater-na1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Smart Fan Heater | miio:basic | [zhimi.heater.nb1](#zhimi-heater-nb1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -4340,6 +4341,24 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | led_level | Number | Led - Brightness | Value mapping `["0"="High","1"="Low","2"="Idle"]` | | temperature | Number:Temperature | Temperature | | +### Mi Fresh Air Ventilator C1-80 (zhimi.airfresh.ua1) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| actions | String | Actions | Value mapping `["filter-reset-filter-life"="Filter Reset Filter Life"]` | +| on | Switch | Air Fresh - Switch Status | | +| fault | Number | Device Fault | Value mapping `["0"="No Faults"]` | +| fan_level | Number | Air Fresh - Fan Level | Value mapping `["1"="Level1","2"="Level2","3"="Level3"]` | +| heater | Switch | Heater | | +| filter_used_time | Number:Time | Filter - Filter Used Time | | +| filter_life_level | Number:Dimensionless | Filter - Filter Life Level | | +| physical_controls_locked | Switch | Physical Control Locked - Physical Control Locked | | +| alarm | Switch | Alarm - Alarm | | +| brightness | Dimmer | Indicator Light - Brightness | | +| motor_a_speed_rpm | Number | Custom Serveice - Motor A Speed Rpm | | +| motor_b_speed_rpm | Number | Custom Serveice - Motor B Speed Rpm | | +| temperature | Number:Temperature | Custom Serveice - Temperature | | + ### Mi PM2.5 Air Quality Monitor (zhimi.airmonitor.v1) Channels | Channel | Type | Description | Comment | @@ -9795,6 +9814,27 @@ Number led_level "Led - Brightness" (G_airfresh) {channel="miio:basic:airfresh:l Number:Temperature temperature "Temperature" (G_airfresh) {channel="miio:basic:airfresh:temperature"} ``` +### Mi Fresh Air Ventilator C1-80 (zhimi.airfresh.ua1) item file lines + +note: Autogenerated example. Replace the id (airfresh) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_airfresh "Mi Fresh Air Ventilator C1-80" +String actions "Actions" (G_airfresh) {channel="miio:basic:airfresh:actions"} +Switch on "Air Fresh - Switch Status" (G_airfresh) {channel="miio:basic:airfresh:on"} +Number fault "Device Fault" (G_airfresh) {channel="miio:basic:airfresh:fault"} +Number fan_level "Air Fresh - Fan Level" (G_airfresh) {channel="miio:basic:airfresh:fan_level"} +Switch heater "Heater" (G_airfresh) {channel="miio:basic:airfresh:heater"} +Number:Time filter_used_time "Filter - Filter Used Time" (G_airfresh) {channel="miio:basic:airfresh:filter_used_time"} +Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_airfresh) {channel="miio:basic:airfresh:filter_life_level"} +Switch physical_controls_locked "Physical Control Locked - Physical Control Locked" (G_airfresh) {channel="miio:basic:airfresh:physical_controls_locked"} +Switch alarm "Alarm - Alarm" (G_airfresh) {channel="miio:basic:airfresh:alarm"} +Dimmer brightness "Indicator Light - Brightness" (G_airfresh) {channel="miio:basic:airfresh:brightness"} +Number motor_a_speed_rpm "Custom Serveice - Motor A Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_a_speed_rpm"} +Number motor_b_speed_rpm "Custom Serveice - Motor B Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_b_speed_rpm"} +Number:Temperature temperature "Custom Serveice - Temperature" (G_airfresh) {channel="miio:basic:airfresh:temperature"} +``` + ### Mi PM2.5 Air Quality Monitor (zhimi.airmonitor.v1) item file lines note: Autogenerated example. Replace the id (airmonitor) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java index e8e89b15ba7f4..931eb258fdeb3 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java @@ -348,6 +348,7 @@ public enum MiIoDevices { YUNMI_WATERPURIFIER_V4("yunmi.waterpurifier.v4", "Mi Water Purifier v4", THING_TYPE_BASIC), ZHIMI_AIRFRESH_VA2("zhimi.airfresh.va2", "Smartmi Ventilation System", THING_TYPE_BASIC), ZHIMI_AIRFRESH_VA4("zhimi.airfresh.va4", "Smartmi Fresh Air System (Heating)", THING_TYPE_BASIC), + ZHIMI_AIRFRESH_UA1("zhimi.airfresh.ua1", "Mi Fresh Air Ventilator C1-80", THING_TYPE_BASIC), ZHIMI_AIRMONITOR_V1("zhimi.airmonitor.v1", "Mi PM2.5 Air Quality Monitor", THING_TYPE_BASIC), ZHIMI_AIRPURIFIER_M1("zhimi.airpurifier.m1", "Mi Air Purifier 2 (mini)", THING_TYPE_BASIC), ZHIMI_AIRPURIFIER_M2("zhimi.airpurifier.m2", "Mi Air Purifier 2", THING_TYPE_BASIC), diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java index cfae463db9d4b..7a23e11add20f 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java @@ -331,7 +331,7 @@ public MiIoBasicDevice getDevice(JsonElement urnData) throws MiotParseException if (actionText.length() > 35) { deviceMapping.setReadmeComment( "Identified " + actionText.toString().replace("Manual", "manual").replace("\r\n", "
") - + "Please test and feedback if they are working to they can be linked to a channel."); + + "Please test and feedback if they are working so they can be linked to a channel."); } logger.info(channelConfigText.toString()); if (actionText.length() > 30) { diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json index 1b900e01af775..7526c0b6fee00 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json @@ -522,7 +522,7 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Switch Off\",\"0\"\u003d\"Not Turn Pot\",\"2\"\u003d\"Turn Pot\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cook\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cook\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json index f32e1718ca5ce..ffa63d674c2c8 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json @@ -494,7 +494,7 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Switch Off\",\"0\"\u003d\"Not Turn Pot\",\"2\"\u003d\"Turn Pot\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-custom-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cooking\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-custom-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cooking\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json index 5c284316c9053..a2dc869d46cc5 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json @@ -446,6 +446,6 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"settings-set-start-time\",\"siid\":9,\"aiid\":2,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-end-time\",\"siid\":9,\"aiid\":3,\"in\":[3.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-frequency\",\"siid\":9,\"aiid\":4,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-screen-off\",\"siid\":9,\"aiid\":5,\"in\":[5.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-device-off\",\"siid\":9,\"aiid\":6,\"in\":[6.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-temp-unit\",\"siid\":9,\"aiid\":7,\"in\":[7.0]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel." + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"settings-set-start-time\",\"siid\":9,\"aiid\":2,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-end-time\",\"siid\":9,\"aiid\":3,\"in\":[3.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-frequency\",\"siid\":9,\"aiid\":4,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-screen-off\",\"siid\":9,\"aiid\":5,\"in\":[5.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-device-off\",\"siid\":9,\"aiid\":6,\"in\":[6.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-temp-unit\",\"siid\":9,\"aiid\":7,\"in\":[7.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel." } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p15-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p15-miot.json index 29316ff4112e2..b128a74a4677b 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p15-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p15-miot.json @@ -313,7 +313,7 @@ "readmeComment": "Value mapping `[\"off-delay-time-toggle\"\u003d\"Off Delay Time Toggle\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"off-delay-time-toggle\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"off-delay-time-toggle\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json index e4bd689bffd01..c46781e1bd1b9 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json @@ -312,7 +312,7 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json index a8b0662dcbf00..6faf335758050 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json @@ -218,7 +218,7 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json index 7a79f7fd8d5b6..7541a72340806 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json @@ -703,7 +703,7 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":26,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":27,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":28,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-start-clean\",\"siid\":18,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-stop-clean\",\"siid\":18,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-start-remote\",\"siid\":21,\"aiid\":1,\"in\":[1.0, 2.0]}`\u003cbr /\u003e`action{\"did\":\"remote-stop-remote\",\"siid\":21,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-exit-remote\",\"siid\":21,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":23,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":24,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-set-voice\",\"siid\":24,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":24,\"aiid\":3,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":26,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":27,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":28,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-start-clean\",\"siid\":18,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-stop-clean\",\"siid\":18,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-start-remote\",\"siid\":21,\"aiid\":1,\"in\":[1.0, 2.0]}`\u003cbr /\u003e`action{\"did\":\"remote-stop-remote\",\"siid\":21,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-exit-remote\",\"siid\":21,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":23,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":24,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-set-voice\",\"siid\":24,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":24,\"aiid\":3,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json index 87f8d571af7fd..3defb4679c49e 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json @@ -628,7 +628,7 @@ "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\",\"-1\"\u003d\"Not Enabled\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json index af8dc0fb88005..0a698c2083f42 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json @@ -1019,7 +1019,7 @@ "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s1-miot.json index 18e81e0b19585..7ffe9c5fe7dd2 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s1-miot.json @@ -239,7 +239,7 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-cotton-reset-cotton-life\",\"siid\":5,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remain-clean-time-reset-clean-time\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-cotton-reset-cotton-life\",\"siid\":5,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remain-clean-time-reset-clean-time\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s2-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s2-miot.json index 203f87af26b16..8e915815721c1 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s2-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/mmgg.pet_waterer.s2-miot.json @@ -254,7 +254,7 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-cotton-reset-cotton-life\",\"siid\":5,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remain-clean-time-reset-clean-time\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-cotton-reset-cotton-life\",\"siid\":5,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remain-clean-time-reset-clean-time\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json index efc34cbc5932e..21d1f1e542a3c 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json @@ -1531,7 +1531,7 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-charge\",\"siid\":2,\"aiid\":4,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-massage\",\"siid\":2,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-mop\",\"siid\":2,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-only-sweep\",\"siid\":2,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep-mop\",\"siid\":2,\"aiid\":8,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-map\",\"siid\":4,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-calibration\",\"siid\":4,\"aiid\":10,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-consumable\",\"siid\":4,\"aiid\":11,\"in\":[35.0]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-room-clean\",\"siid\":4,\"aiid\":13,\"in\":[36.0, 37.0, 38.0]}`\u003cbr /\u003e`action{\"did\":\"order-del\",\"siid\":5,\"aiid\":2,\"in\":[1.0]}`\u003cbr /\u003e`action{\"did\":\"order-get\",\"siid\":5,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-point-clean\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-point-clean\",\"siid\":6,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-zone-clean\",\"siid\":6,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-zone-clean\",\"siid\":6,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-maptype\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-mapid\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-set-cur-map\",\"siid\":7,\"aiid\":3,\"in\":[2.0, 15.0]}`\u003cbr /\u003e`action{\"did\":\"map-del-map\",\"siid\":7,\"aiid\":5,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-map\",\"siid\":7,\"aiid\":7,\"in\":[2.0, 4.0]}`\u003cbr /\u003e`action{\"did\":\"map-arrange-room\",\"siid\":7,\"aiid\":8,\"in\":[2.0, 5.0, 6.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-split-room\",\"siid\":7,\"aiid\":9,\"in\":[2.0, 5.0, 7.0, 8.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-room\",\"siid\":7,\"aiid\":10,\"in\":[2.0, 7.0, 9.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-get-map-list\",\"siid\":7,\"aiid\":11,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-get-cleaning-path\",\"siid\":7,\"aiid\":12,\"in\":[12.0]}`\u003cbr /\u003e`action{\"did\":\"map-set-new-map\",\"siid\":7,\"aiid\":13,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-deal-new-map\",\"siid\":7,\"aiid\":14,\"in\":[16.0]}`\u003cbr /\u003e`action{\"did\":\"voice-find-device\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"voice-download-voice\",\"siid\":8,\"aiid\":3,\"in\":[3.0, 7.0, 8.0]}`\u003cbr /\u003e`action{\"did\":\"voice-get-downloadstatus\",\"siid\":8,\"aiid\":4,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-charge\",\"siid\":2,\"aiid\":4,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-massage\",\"siid\":2,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-mop\",\"siid\":2,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-only-sweep\",\"siid\":2,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep-mop\",\"siid\":2,\"aiid\":8,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-map\",\"siid\":4,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-calibration\",\"siid\":4,\"aiid\":10,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-consumable\",\"siid\":4,\"aiid\":11,\"in\":[35.0]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-room-clean\",\"siid\":4,\"aiid\":13,\"in\":[36.0, 37.0, 38.0]}`\u003cbr /\u003e`action{\"did\":\"order-del\",\"siid\":5,\"aiid\":2,\"in\":[1.0]}`\u003cbr /\u003e`action{\"did\":\"order-get\",\"siid\":5,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-point-clean\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-point-clean\",\"siid\":6,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-zone-clean\",\"siid\":6,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-zone-clean\",\"siid\":6,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-maptype\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-mapid\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-set-cur-map\",\"siid\":7,\"aiid\":3,\"in\":[2.0, 15.0]}`\u003cbr /\u003e`action{\"did\":\"map-del-map\",\"siid\":7,\"aiid\":5,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-map\",\"siid\":7,\"aiid\":7,\"in\":[2.0, 4.0]}`\u003cbr /\u003e`action{\"did\":\"map-arrange-room\",\"siid\":7,\"aiid\":8,\"in\":[2.0, 5.0, 6.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-split-room\",\"siid\":7,\"aiid\":9,\"in\":[2.0, 5.0, 7.0, 8.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-room\",\"siid\":7,\"aiid\":10,\"in\":[2.0, 7.0, 9.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-get-map-list\",\"siid\":7,\"aiid\":11,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-get-cleaning-path\",\"siid\":7,\"aiid\":12,\"in\":[12.0]}`\u003cbr /\u003e`action{\"did\":\"map-set-new-map\",\"siid\":7,\"aiid\":13,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-deal-new-map\",\"siid\":7,\"aiid\":14,\"in\":[16.0]}`\u003cbr /\u003e`action{\"did\":\"voice-find-device\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"voice-download-voice\",\"siid\":8,\"aiid\":3,\"in\":[3.0, 7.0, 8.0]}`\u003cbr /\u003e`action{\"did\":\"voice-get-downloadstatus\",\"siid\":8,\"aiid\":4,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json new file mode 100644 index 0000000000000..00cfc6071ed3a --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json @@ -0,0 +1,274 @@ +{ + "deviceMapping": { + "id": [ + "zhimi.airfresh.ua1" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "filter-reset-filter-life", + "label": "Filter Reset Filter Life" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "UNKNOWN", + "parameters": [ + 1.0 + ], + "siid": 4, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "filter-reset-filter-life" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"filter-reset-filter-life\"\u003d\"Filter Reset Filter Life\"]`" + }, + { + "property": "on", + "siid": 2, + "piid": 1, + "friendlyName": "Air Fresh - Switch Status", + "channel": "on", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ], + "category": "switch", + "tags": [ + "Switch" + ] + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Faults" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Faults\"]`" + }, + { + "property": "fan-level", + "siid": 2, + "piid": 5, + "friendlyName": "Air Fresh - Fan Level", + "channel": "fan_level", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "Level1" + }, + { + "value": "2", + "label": "Level2" + }, + { + "value": "3", + "label": "Level3" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "tags": [ + "Control" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Level1\",\"2\"\u003d\"Level2\",\"3\"\u003d\"Level3\"]`" + }, + { + "property": "heater", + "siid": 2, + "piid": 6, + "friendlyName": "Heater", + "channel": "heater", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "filter-used-time", + "siid": 4, + "piid": 1, + "friendlyName": "Filter - Filter Used Time", + "channel": "filter_used_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 9999999, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-life-level", + "siid": 4, + "piid": 2, + "friendlyName": "Filter - Filter Life Level", + "channel": "filter_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "physical-controls-locked", + "siid": 5, + "piid": 1, + "friendlyName": "Physical Control Locked - Physical Control Locked", + "channel": "physical_controls_locked", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "alarm", + "siid": 6, + "piid": 1, + "friendlyName": "Alarm - Alarm", + "channel": "alarm", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "brightness", + "siid": 7, + "piid": 3, + "friendlyName": "Indicator Light - Brightness", + "channel": "brightness", + "type": "Dimmer", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "motor-a-speed-rpm", + "siid": 8, + "piid": 1, + "friendlyName": "Custom Serveice - Motor A Speed Rpm", + "channel": "motor_a_speed_rpm", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 65535, + "step": 1, + "pattern": "%.0f rpm", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "motor-b-speed-rpm", + "siid": 8, + "piid": 2, + "friendlyName": "Custom Serveice - Motor B Speed Rpm", + "channel": "motor_b_speed_rpm", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 65535, + "step": 1, + "pattern": "%.0f rpm", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "temperature", + "siid": 8, + "piid": 5, + "friendlyName": "Custom Serveice - Temperature", + "channel": "temperature", + "type": "Number:Temperature", + "unit": "CELSIUS", + "stateDescription": { + "minimum": -40, + "maximum": 125, + "pattern": "%.1f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "temperature", + "tags": [ + "Measurement", + "Temperature" + ] + } + ], + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[1.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", + "experimental": false + } +} diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json index 2c5706efcf564..e4bc266de821c 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json @@ -1020,7 +1020,7 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Level1\",\"2\"\u003d\"Level2\",\"3\"\u003d\"Level3\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json index df0121297c64f..63813d0b95632 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json @@ -1063,7 +1063,7 @@ "readmeComment": "Value mapping `[\"91\"\u003d\"印度\",\"44\"\u003d\"分销英文\",\"852\"\u003d\"中国香港\",\"886\"\u003d\"中国台湾\",\"82\"\u003d\"韩国\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json index 403086849eee5..6799cf4dd80e9 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json @@ -283,7 +283,7 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"private-service-toggle-switch\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working to they can be linked to a channel.", + "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"private-service-toggle-switch\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } From b02d23064925905e41bd55008a68997c89e8aa2a Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 29 Nov 2021 12:34:09 +0100 Subject: [PATCH 150/361] [miio] add support for BT Gateway switch on chuangmi.plug.212a01 (#11657) * [miio] add support for BT Gateway switch on chuangmi.plug.212a01 Signed-off-by: Marcel Verpaalen * [miio] improve conversion & add test for it Signed-off-by: Marcel Verpaalen * [miio] add one empty string test Signed-off-by: Marcel Verpaalen * [miio] remove unnessesary exceptions Signed-off-by: Marcel Verpaalen * [miio] add one more test for different inputs Signed-off-by: Marcel Verpaalen * [miio] typo Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 4 +- .../miio/internal/basic/Conversions.java | 29 +++++ .../database/chuangmi.plug.212a01-miot.json | 51 +++++++- .../miio/internal/ConversionsTest.java | 123 ++++++++++++++++++ 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 66f58a5329c13..59695ffb27196 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -187,7 +187,7 @@ Currently the miio binding supports more than 300 different models. | Mi Multifunction Air Monitor | miio:basic | [cgllc.airmonitor.b1](#cgllc-airmonitor-b1) | Yes | | | Qingping Air Monitor | miio:basic | [cgllc.airmonitor.s1](#cgllc-airmonitor-s1) | Yes | | | Mi Universal Remote | miio:unsupported | chuangmi.ir.v2 | No | | -| Mi Smart Power Plug 2 (Wi-Fi and Bluetooth Gateway) | miio:basic | [chuangmi.plug.212a01](#chuangmi-plug-212a01) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Power Plug 2 (Wi-Fi and Bluetooth Gateway) | miio:basic | [chuangmi.plug.212a01](#chuangmi-plug-212a01) | Yes | | | Mi Smart Plug WiFi | miio:basic | [chuangmi.plug.hmi205](#chuangmi-plug-hmi205) | Yes | | | Mi Smart Plug (WiFi) | miio:basic | [chuangmi.plug.hmi206](#chuangmi-plug-hmi206) | Yes | | | Mi Smart Wi-Fi Plug (Bluetooth Gateway) | miio:basic | [chuangmi.plug.hmi208](#chuangmi-plug-hmi208) | Yes | | @@ -694,6 +694,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | countdown | Number:Time | Imilab Timer - Countdown | | | task-switch | Switch | Imilab Timer - Task Switch | | | countdown-info | Switch | Imilab Timer - Countdown Info | | +| bt-gw | String | BT Gateway | Value mapping `["disable"="Disable","enable"="Enable"]` | ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) Channels @@ -5488,6 +5489,7 @@ Number:Time off_duration "Imilab Timer - Off Duration" (G_plug) {channel="miio:b Number:Time countdown "Imilab Timer - Countdown" (G_plug) {channel="miio:basic:plug:countdown"} Switch task_switch "Imilab Timer - Task Switch" (G_plug) {channel="miio:basic:plug:task-switch"} Switch countdown_info "Imilab Timer - Countdown Info" (G_plug) {channel="miio:basic:plug:countdown-info"} +String bt_gw "BT Gateway" (G_plug) {channel="miio:basic:plug:bt-gw"} ``` ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) item file lines diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java index ba79c31cac9fc..e20487d09a0b8 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java @@ -23,6 +23,9 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; /** @@ -121,9 +124,35 @@ public static JsonElement tankLevel(JsonElement value12) throws ClassCastExcepti } } + public static JsonElement getJsonElement(String element, JsonElement responseValue) { + try { + if (responseValue.isJsonPrimitive() || responseValue.isJsonObject()) { + JsonElement jsonElement = responseValue.isJsonObject() ? responseValue + : JsonParser.parseString(responseValue.getAsString()); + if (jsonElement.isJsonObject()) { + JsonObject value = jsonElement.getAsJsonObject(); + if (value.has(element)) { + return value.get(element); + } + } + } + } catch (JsonParseException e) { + // ignore + } + LOGGER.debug("JsonElement '{}' not found in '{}'", element, responseValue); + return responseValue; + } + public static JsonElement execute(String transformation, JsonElement value, @Nullable Map deviceVariables) { try { + if (transformation.toUpperCase().startsWith("GETJSONELEMENT")) { + if (transformation.length() > 15) { + return getJsonElement(transformation.substring(15), value); + } else { + LOGGER.info("Transformation {} missing element. Returning '{}'", transformation, value.toString()); + } + } switch (transformation.toUpperCase()) { case "YEELIGHTSCENEID": return yeelightSceneConversion(value); diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json index 4827ef6cd6df4..9ee47e5e69f3e 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json @@ -274,8 +274,57 @@ }, "refresh": true, "actions": [] + }, + { + "property": "", + "friendlyName": "BT Gateway", + "channel": "bt-gw", + "type": "String", + "stateDescription": { + "readOnly": false, + "options": [ + { + "value": "disable", + "label": "Disable" + }, + { + "value": "enable", + "label": "Enable" + } + ] + }, + "refresh": true, + "customRefreshCommand": "bt_gateway_status", + "transformation": "getJsonElement-gateway_status", + "actions": [ + { + "command": "bt_gateway_enable", + "parameterType": "EMPTY", + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "enable" + } + ] + } + }, + { + "command": "bt_gateway_disable", + "parameterType": "EMPTY", + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "disable" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"disable\"\u003d\"Disable\",\"enable\"\u003d\"Enable\"]`" } ], - "experimental": true + "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java new file mode 100644 index 0000000000000..2ee46a065f5d4 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.miio.internal; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Collections; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.miio.internal.basic.Conversions; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; + +/** + * Test case for {@link ConversionsTest} + * + * @author Marcel Verpaalen - Initial contribution + * + */ +@NonNullByDefault +public class ConversionsTest { + + @Test + public void getJsonElementTest() { + + Map deviceVariables = Collections.emptyMap(); + + // test invalid missing element + String transformation = "getJsonElement"; + JsonElement value = new JsonPrimitive(""); + JsonElement resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test invalid missing element + value = new JsonPrimitive("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + transformation = "getJsonElement-test"; + + // test without deviceVariables + resp = Conversions.execute(transformation, value, null); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test non json + value = new JsonPrimitive("some non json value"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test non json empty string + value = new JsonPrimitive(""); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test input as jsonString + value = new JsonPrimitive("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test input as jsonObject + value = JsonParser.parseString("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test input as jsonString for a number + value = new JsonPrimitive("{\"test\": 3}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(3), resp); + + // test input as jsonString for a array + value = new JsonPrimitive("{\"test\": []}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonArray(), resp); + + // test input as jsonString for a boolean + value = new JsonPrimitive("{\"test\": false}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(false), resp); + + // test input as jsonObject for a number + value = JsonParser.parseString("{\"test\": 3}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(3), resp); + + // test input as jsonString for non-existing element + value = new JsonPrimitive("{\"nottest\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test input as jsonString for non-existing element + value = JsonParser.parseString("{\"nottest\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + } +} From 16945719f860f1d8b4932618552d80872c488bc2 Mon Sep 17 00:00:00 2001 From: eugen Date: Wed, 1 Dec 2021 09:43:41 +0100 Subject: [PATCH 151/361] [homekit] switch to official Java HAP lib release (#11671) Signed-off-by: Eugen Freiter Signed-off-by: Michael Schmidt --- bundles/org.openhab.io.homekit/pom.xml | 6 +++--- .../internal/accessories/HomekitGarageDoorOpenerImpl.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.io.homekit/pom.xml b/bundles/org.openhab.io.homekit/pom.xml index 2e85a6538f761..c153955a82f7b 100644 --- a/bundles/org.openhab.io.homekit/pom.xml +++ b/bundles/org.openhab.io.homekit/pom.xml @@ -20,9 +20,9 @@ - com.github.j-n-k - hap-java - 2.1.0.OH + io.github.hap-java + hap + 2.0.0 compile diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitGarageDoorOpenerImpl.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitGarageDoorOpenerImpl.java index 6c7995836635c..4e2ad6a202b43 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitGarageDoorOpenerImpl.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitGarageDoorOpenerImpl.java @@ -74,7 +74,7 @@ public CompletableFuture getCurrentDoorState() { } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateOpening)) { mode = CurrentDoorStateEnum.OPENING; } else if (stringValue.equalsIgnoreCase(settings.doorCurrentStateStopped)) { - mode = CurrentDoorStateEnum.SOPPED; + mode = CurrentDoorStateEnum.STOPPED; } else if (stringValue.equals("UNDEF") || stringValue.equals("NULL")) { logger.warn("Current door state not available. Relaying value of CLOSED to HomeKit"); mode = CurrentDoorStateEnum.CLOSED; From 0bea02f8dd76252b4aa3ce7abae08ef8e2805ab4 Mon Sep 17 00:00:00 2001 From: mlobstein Date: Wed, 1 Dec 2021 02:48:30 -0600 Subject: [PATCH 152/361] [kaleidescape] Fix incorrect word in player ui documentation (#11676) Signed-off-by: Michael Lobstein Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.kaleidescape/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.kaleidescape/README.md b/bundles/org.openhab.binding.kaleidescape/README.md index 29b00a059b7f6..5fa9c52e0fc2a 100644 --- a/bundles/org.openhab.binding.kaleidescape/README.md +++ b/bundles/org.openhab.binding.kaleidescape/README.md @@ -78,7 +78,7 @@ The following channels are available: | ui#power | Switch | Turn the zone On or Off (system standby) | | ui#volume | Dimmer | A virtual volume that tracks the volume in K control apps, use as a proxy to adjust a real volume item via rules | | ui#mute | Switch | A virtual mute switch that tracks the mute status in K control apps, use as a proxy to control a real mute item | -| ui#control | Player | Control Movie Playback e.g. start/pause/next/previous/ffward/rewind | +| ui#control | Player | Control Movie Playback e.g. play/pause/next/previous/ffward/rewind | | ui#title_name | String | The title of the movie currently playing | | ui#play_mode | String | The current playback mode of the movie | | ui#play_speed | String | The speed of playback scanning | @@ -112,7 +112,7 @@ The following channels are available: | ui#user_input | String | Indicates if the user is being prompted for input, what type of input, and any currently entered characters | | ui#user_input_prompt | String | Indicates user input prompt info and properties currently shown on screen | | -- music channels (not available on Alto and Strato) -- | -| music#control | Player | Control Music Playback e.g. start/pause/next/previous/ffward/rewind | +| music#control | Player | Control Music Playback e.g. play/pause/next/previous/ffward/rewind | | music#repeat | Switch | Controls repeat playback for music | | music#random | Switch | Controls random playback for music | | music#track | String | The name of the currently playing track | From 9c65e24a0df9dbc883b4c5de99b589a8effd09c6 Mon Sep 17 00:00:00 2001 From: Hilbrand Bouwkamp Date: Wed, 1 Dec 2021 11:57:09 +0100 Subject: [PATCH 153/361] [tplinksmarthome] Fixed invalid channels in KL125/KL135. (#11680) These are color bulbs and should have the color channel instead of the brightness channel. Closes #11660 Signed-off-by: Hilbrand Bouwkamp Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/KL125.xml | 2 +- .../src/main/resources/OH-INF/thing/KL135.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL125.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL125.xml index 3583b6057f72f..fff94fa871eff 100644 --- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL125.xml +++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL125.xml @@ -10,7 +10,7 @@ Lightbulb - + diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL135.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL135.xml index 297014467b64f..ec025384916bb 100644 --- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL135.xml +++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/thing/KL135.xml @@ -10,7 +10,7 @@ Lightbulb - + From 9eebccab3378910bebaf0019fbda275dfd4ff885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans-J=C3=B6rg=20Merk?= Date: Wed, 1 Dec 2021 11:58:59 +0100 Subject: [PATCH 154/361] [wemo] Fix receiving empty binary state during poll (#11679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hans-Jörg Merk Signed-off-by: Michael Schmidt --- .../openhab/binding/wemo/internal/handler/WemoHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java index 50191917aab67..0eb877d39f0c6 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java @@ -421,8 +421,10 @@ protected void updateWemoState() { } else { value = substringBetween(wemoCallResponse, "", ""); } - logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); + if (value.length() != 0) { + logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + } } } } catch (Exception e) { From e9956cd3c16c30de963ed980659e46ad5408825d Mon Sep 17 00:00:00 2001 From: mlobstein Date: Wed, 1 Dec 2021 05:22:29 -0600 Subject: [PATCH 155/361] [tivo] Minor update and cleanup README.md (#11673) Signed-off-by: Michael Lobstein Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.tivo/README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.tivo/README.md b/bundles/org.openhab.binding.tivo/README.md index f3c37d6fc835b..f1076823585af 100644 --- a/bundles/org.openhab.binding.tivo/README.md +++ b/bundles/org.openhab.binding.tivo/README.md @@ -7,6 +7,11 @@ This binding controls a [TiVo](https://www.tivo.com/) Digital Video Recorder (DV ## Supported Things Most TiVo DVRs that support network remote control can be managed/supported by this binding. +Please note that beyond sending a full set of control commands, the network control protocol is very limited. +The only feedback provided is the currently tuned channel number and whether or not the channel is recording. + +It is possible to control a TiVo at a deeper level through an authenticated API. See the kmttg project for more details. +There are no current plans to add any of the authenticated API features to this binding. All TiVo devices must: @@ -121,8 +126,9 @@ VIDEO_MODE_NATIVE **tivo.things** -```java +``` tivo:sckt:Living_Room "Living Room TiVo" [ host="192.168.0.19" ] + ``` **tivo.items:** @@ -155,8 +161,8 @@ sitemap tivo label="Tivo Central" { Switch item=TiVo_IRCmd label="Channel" icon="screen" mappings=["CHANNELDOWN"="CH -","CHANNELUP"="CH +"] Switch item=TiVo_IRCmd label="Media" icon="screen" mappings=["REVERSE"="⏪", "PAUSE"="⏸", "PLAY"="▶", /*(DVD TiVo only!) "STOP"="⏹",*/ "FORWARD"="⏩", "RECORD"="⏺" ] Switch item=TiVo_MenuScreen label="Menus" icon="screen" mappings=["TIVO"="Home", "LIVETV"="Live Tv", "GUIDE"="Guide", "NOWPLAYING"="My Shows", "NETFLIX"="Netflix", SEARCH="Search" ] - Switch item=TiVo_SetChannel label="Fav TV" icon="screen" mappings=[2.1="CBS", 4.1="NBC", 7.1="ABC", 11.1="FOX", 5.2="AntennaTV"] - Switch item=TiVo_IRCmd label="Navigation" icon="screen" mappings=["UP"="˄", "DOWN"="˅", "LEFT"="<", "RIGHT"=">", "SELECT"="Select", "EXIT"="Exit" ] + Switch item=TiVo_SetChannel label="Fav TV" icon="screen" mappings=[2.1="CBS", 4.1="NBC", 7.1="ABC", 11.1="FOX", 5.2="AntennaTV"] + Switch item=TiVo_IRCmd label="Navigation" icon="screen" mappings=["UP"="˄", "DOWN"="˅", "LEFT"="<", "RIGHT"=">", "SELECT"="Select", "EXIT"="Exit" ] Switch item=TiVo_IRCmd label="Actions" icon="screen" mappings=["ACTION_A"="Red","ACTION_B"="Green","ACTION_C"="Yellow","ACTION_D"="Blue"] Switch item=TiVo_IRCmd label="Likes" icon="screen" mappings=["THUMBSUP"="Thumbs Up", "THUMBSDOWN"="Thumbs Down"] Switch item=TiVo_IRCmd label="Remote" icon="screen" mappings=["FIND_REMOTE"="Find Remote"] @@ -213,11 +219,11 @@ when Item TiVo_KeyboardStr received update then if (TiVo_KeyboardStr.state != NULL && TiVo_KeyboardStr.state.toString.length > 0) { - + // Command to get us to the TiVo search menu sendCommand(TiVo_MenuScreen, "SEARCH") Thread::sleep(1000) - + var i = 0 var char txt = "" var srch = TiVo_KeyboardStr.state.toString.toUpperCase From 04c35ea4f1bb4b6906db3af3320445f79d5c3cc2 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Wed, 1 Dec 2021 18:53:01 +0100 Subject: [PATCH 156/361] Add i18n-maven-plugin dependency (#11648) When the plugin dependency is managed you can also use the plugin without adding GAV parameters to commands. E.g. it allows for using it with: ``` mvn i18n:generate-default-translations ``` Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index d1053e574ad86..019425708f24b 100644 --- a/pom.xml +++ b/pom.xml @@ -520,6 +520,12 @@ Import-Package: \\ + + org.openhab.core.tools + i18n-maven-plugin + ${ohc.version} + + org.openhab.tools.sat sat-plugin @@ -541,6 +547,7 @@ Import-Package: \\ + com.diffplug.spotless spotless-maven-plugin From 062d13e1eec4327974c32d26ebb14c1d6ffc9b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Os?= Date: Wed, 1 Dec 2021 21:53:11 +0100 Subject: [PATCH 157/361] [homewizard] Fix issue with missing gas values (#11666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes a crash that happens when the smart meter does not provide gas values. The crash was caused by the empty timestamp. Signed-off-by: Daniël van Os Signed-off-by: Michael Schmidt --- .../internal/HomeWizardHandler.java | 52 ++++++++++++------- .../homewizard/internal/P1Payload.java | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardHandler.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardHandler.java index 3e47191f37421..9eeb5dc38f720 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardHandler.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/HomeWizardHandler.java @@ -13,6 +13,9 @@ package org.openhab.binding.homewizard.internal; import java.io.IOException; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -29,6 +32,8 @@ import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; @@ -43,6 +48,7 @@ @NonNullByDefault public class HomeWizardHandler extends BaseThingHandler { + private final Logger logger = LoggerFactory.getLogger(HomeWizardHandler.class); private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); @@ -171,30 +177,40 @@ private void pollingCode() { updateState(HomeWizardBindingConstants.CHANNEL_ACTIVE_POWER_L3, new QuantityType<>(payload.getActivePowerL3W(), Units.WATT)); - updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS, - new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE)); - - // 210119164000 + // If no data from the gas meter is present, the json value will be null, which means gson ignores it, + // leaving the value in the payload object at 0. long dtv = payload.getGasTimestamp(); - long seconds = dtv % 100; + if (dtv > 0) { + updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS, + new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE)); + + // 210119164000 + int seconds = (int) (dtv % 100); - dtv /= 100; - long minutes = dtv % 100; + dtv /= 100; + int minutes = (int) (dtv % 100); - dtv /= 100; - long hours = dtv % 100; + dtv /= 100; + int hours = (int) (dtv % 100); - dtv /= 100; - long day = dtv % 100; + dtv /= 100; + int day = (int) (dtv % 100); - dtv /= 100; - long month = dtv % 100; + dtv /= 100; + int month = (int) (dtv % 100); - dtv /= 100; - long year = dtv + 2000; // Where (When?) have I seen this before? + dtv /= 100; + int year = (int) (dtv + 2000); - DateTimeType dtt = DateTimeType - .valueOf(String.format("%04d-%02d-%02dT%02d:%02d:%02d", year, month, day, hours, minutes, seconds)); - updateState(HomeWizardBindingConstants.CHANNEL_GAS_TIMESTAMP, dtt); + try { + DateTimeType dtt = new DateTimeType( + ZonedDateTime.of(year, month, day, hours, minutes, seconds, 0, ZoneId.systemDefault())); + updateState(HomeWizardBindingConstants.CHANNEL_GAS_TIMESTAMP, dtt); + updateState(HomeWizardBindingConstants.CHANNEL_TOTAL_GAS, + new QuantityType<>(payload.getTotalGasM3(), SIUnits.CUBIC_METRE)); + } catch (DateTimeException e) { + logger.warn("Unable to parse Gas timestamp: {}", payload.getGasTimestamp()); + } + } } } diff --git a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/P1Payload.java b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/P1Payload.java index 6fd42b7e92ec9..33c49b3a81615 100644 --- a/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/P1Payload.java +++ b/bundles/org.openhab.binding.homewizard/src/main/java/org/openhab/binding/homewizard/internal/P1Payload.java @@ -43,7 +43,7 @@ public class P1Payload { private double activePowerL2W; private double activePowerL3W; private double totalGasM3; - private long gasTimestamp; + private long gasTimestamp = 0; /** * Getter for the smart meter version From a5360e3093d6d8dec252153afca9bd0efaa2bd4e Mon Sep 17 00:00:00 2001 From: mlobstein Date: Wed, 1 Dec 2021 14:57:46 -0600 Subject: [PATCH 158/361] [nuvo] Update thing description for better matching in add-on search (#11674) Signed-off-by: Michael Lobstein Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/channels.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml index d73cac332f480..462c61cb87a60 100644 --- a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/thing/channels.xml @@ -8,7 +8,7 @@ - A Multi-zone Whole House Amplifier System + Grand Concerto or Essentia G Amplifier System From 2466d15576caf33af1dfb46c32854b3abbfffa4c Mon Sep 17 00:00:00 2001 From: mlobstein Date: Wed, 1 Dec 2021 14:58:36 -0600 Subject: [PATCH 159/361] [radiothermostat] Update thing description for better matching in add-on search (#11675) Signed-off-by: Michael Lobstein Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/thing/thing-types.xml index 247f643c04e26..9060b85cec6cf 100644 --- a/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/thing/thing-types.xml @@ -8,7 +8,7 @@ - A Thermostat to Control the House's HVAC System + CT30, CT50/3M50 or CT80 Wi-Fi Thermostat From 1a19f695c370a29ca6b12a227e74eca970f6ab7e Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Thu, 2 Dec 2021 09:07:17 +0100 Subject: [PATCH 160/361] [avmfritz] Exclude other Powerline products from discovery (#11682) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../internal/AVMFritzBindingConstants.java | 16 ++++++++-------- .../internal/AVMFritzHandlerFactory.java | 2 +- .../AVMFritzUpnpDiscoveryParticipant.java | 4 ++-- .../internal/handler/Powerline546EHandler.java | 2 +- .../AVMFritzDiscoveryServiceOSGiTest.java | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java index 7abd3d26a9648..c9c7354e65230 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java @@ -37,7 +37,7 @@ public class AVMFritzBindingConstants { public static final String BINDING_ID = "avmfritz"; public static final String BRIDGE_FRITZBOX = "fritzbox"; public static final String BOX_MODEL_NAME = "FRITZ!Box"; - public static final String POWERLINE_MODEL_NAME = "FRITZ!Powerline"; + public static final String POWERLINE546E_MODEL_NAME = "FRITZ!Powerline 546E"; // List of main device types public static final String DEVICE_DECT500 = "FRITZ_DECT_500"; @@ -48,8 +48,8 @@ public class AVMFritzBindingConstants { public static final String DEVICE_DECT210 = "FRITZ_DECT_210"; public static final String DEVICE_DECT200 = "FRITZ_DECT_200"; public static final String DEVICE_DECT100 = "FRITZ_DECT_Repeater_100"; - public static final String DEVICE_PL546E = "FRITZ_Powerline_546E"; - public static final String DEVICE_PL546E_STANDALONE = "FRITZ_Powerline_546E_Solo"; + public static final String DEVICE_POWERLINE546E = "FRITZ_Powerline_546E"; + public static final String DEVICE_POWERLINE546E_STANDALONE = "FRITZ_Powerline_546E_Solo"; public static final String DEVICE_COMETDECT = "Comet_DECT"; public static final String DEVICE_HAN_FUN_CONTACT = "HAN_FUN_CONTACT"; public static final String DEVICE_HAN_FUN_SWITCH = "HAN_FUN_SWITCH"; @@ -70,9 +70,9 @@ public class AVMFritzBindingConstants { public static final ThingTypeUID DECT210_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT210); public static final ThingTypeUID DECT200_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT200); public static final ThingTypeUID DECT100_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT100); - public static final ThingTypeUID PL546E_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_PL546E); - public static final ThingTypeUID PL546E_STANDALONE_THING_TYPE = new ThingTypeUID(BINDING_ID, - DEVICE_PL546E_STANDALONE); + public static final ThingTypeUID POWERLINE546E_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_POWERLINE546E); + public static final ThingTypeUID POWERLINE546E_STANDALONE_THING_TYPE = new ThingTypeUID(BINDING_ID, + DEVICE_POWERLINE546E_STANDALONE); public static final ThingTypeUID COMETDECT_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_COMETDECT); public static final ThingTypeUID HAN_FUN_CONTACT_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_CONTACT); public static final ThingTypeUID HAN_FUN_SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_SWITCH); @@ -176,14 +176,14 @@ public class AVMFritzBindingConstants { COMETDECT_THING_TYPE); public static final Set SUPPORTED_DEVICE_THING_TYPES_UIDS = Set.of(DECT100_THING_TYPE, - DECT200_THING_TYPE, DECT210_THING_TYPE, PL546E_THING_TYPE, HAN_FUN_CONTACT_THING_TYPE, + DECT200_THING_TYPE, DECT210_THING_TYPE, POWERLINE546E_THING_TYPE, HAN_FUN_CONTACT_THING_TYPE, HAN_FUN_ON_OFF_THING_TYPE, HAN_FUN_BLINDS_THING_TYPE); public static final Set SUPPORTED_GROUP_THING_TYPES_UIDS = Set.of(GROUP_HEATING_THING_TYPE, GROUP_SWITCH_THING_TYPE); public static final Set SUPPORTED_BRIDGE_THING_TYPES_UIDS = Set.of(BRIDGE_THING_TYPE, - PL546E_STANDALONE_THING_TYPE); + POWERLINE546E_STANDALONE_THING_TYPE); public static final Set SUPPORTED_THING_TYPES_UIDS = Stream.of(SUPPORTED_LIGHTING_THING_TYPES, SUPPORTED_BUTTON_THING_TYPES_UIDS, SUPPORTED_HEATING_THING_TYPES, SUPPORTED_DEVICE_THING_TYPES_UIDS, diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzHandlerFactory.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzHandlerFactory.java index 5d396a2c66aa7..386c33b530b86 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzHandlerFactory.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzHandlerFactory.java @@ -75,7 +75,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (BRIDGE_THING_TYPE.equals(thingTypeUID)) { return new BoxHandler((Bridge) thing, httpClient, commandDescriptionProvider); - } else if (PL546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) { + } else if (POWERLINE546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) { return new Powerline546EHandler((Bridge) thing, httpClient, commandDescriptionProvider); } else if (SUPPORTED_LIGHTING_THING_TYPES.contains(thingTypeUID)) { return new AVMFritzColorLightDeviceHandler(thing); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java index fa42200ce5a0a..d5c160b89a7d8 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzUpnpDiscoveryParticipant.java @@ -109,9 +109,9 @@ public Set getSupportedThingTypeUIDs() { if (modelName.startsWith(BOX_MODEL_NAME)) { logger.debug("discovered on {}", device.getIdentity().getDiscoveredOnLocalAddress()); return new ThingUID(BRIDGE_THING_TYPE, id); - } else if (modelName.startsWith(POWERLINE_MODEL_NAME)) { + } else if (POWERLINE546E_MODEL_NAME.equals(modelName)) { logger.debug("discovered on {}", device.getIdentity().getDiscoveredOnLocalAddress()); - return new ThingUID(PL546E_STANDALONE_THING_TYPE, id); + return new ThingUID(POWERLINE546E_STANDALONE_THING_TYPE, id); } } } diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/Powerline546EHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/Powerline546EHandler.java index dc5176a0c4788..f84c2b75e8948 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/Powerline546EHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/Powerline546EHandler.java @@ -225,7 +225,7 @@ public void onDeviceGone(ThingUID thingUID) { ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, getThingTypeId(device).concat("_Solo")); String ipAddress = getConfigAs(AVMFritzBoxConfiguration.class).ipAddress; - if (PL546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) { + if (POWERLINE546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) { String thingName = "fritz.powerline".equals(ipAddress) ? ipAddress : ipAddress.replaceAll(INVALID_PATTERN, "_"); return new ThingUID(thingTypeUID, thingName); diff --git a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java index 26d7dd3eb6c35..ce927e9a6f5db 100644 --- a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java +++ b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java @@ -98,7 +98,7 @@ public void correctSupportedTypes() { assertTrue(discovery.getSupportedThingTypes().contains(DECT400_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT440_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT500_THING_TYPE)); - assertTrue(discovery.getSupportedThingTypes().contains(PL546E_THING_TYPE)); + assertTrue(discovery.getSupportedThingTypes().contains(POWERLINE546E_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(COMETDECT_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_CONTACT_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_SWITCH_THING_TYPE)); @@ -508,7 +508,7 @@ public void validPowerline546EDiscoveryResult() throws JAXBException, XMLStreamE assertEquals(DiscoveryResultFlag.NEW, discoveryResult.getFlag()); assertEquals(new ThingUID("avmfritz:FRITZ_Powerline_546E:1:5C_49_79_F0_A3_84"), discoveryResult.getThingUID()); - assertEquals(PL546E_THING_TYPE, discoveryResult.getThingTypeUID()); + assertEquals(POWERLINE546E_THING_TYPE, discoveryResult.getThingTypeUID()); assertEquals(BRIGE_THING_ID, discoveryResult.getBridgeUID()); assertEquals("5C:49:79:F0:A3:84", discoveryResult.getProperties().get(CONFIG_AIN)); assertEquals("AVM", discoveryResult.getProperties().get(PROPERTY_VENDOR)); From 13b1ce7174e8fef10b307f6219c4681ea15c6a40 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 2 Dec 2021 09:08:17 +0100 Subject: [PATCH 161/361] [miio] i18n translation handling for basic channels (#11576) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- .../miio/internal/MiIoBindingConstants.java | 4 + .../miio/internal/MiIoHandlerFactory.java | 19 +- .../internal/handler/MiIoAbstractHandler.java | 24 +- .../internal/handler/MiIoBasicHandler.java | 16 +- .../internal/handler/MiIoGenericHandler.java | 6 +- .../handler/MiIoUnsupportedHandler.java | 7 +- .../internal/handler/MiIoVacuumHandler.java | 7 +- .../resources/OH-INF/i18n/basic.properties | 2460 +++++++++++++++++ .../binding/miio/internal/ReadmeHelper.java | 148 +- 9 files changed, 2640 insertions(+), 51 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoBindingConstants.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoBindingConstants.java index 4a887e7f76b39..ce318ee083ea6 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoBindingConstants.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoBindingConstants.java @@ -123,4 +123,8 @@ public final class MiIoBindingConstants { + File.separator + BINDING_ID; public static final String BINDING_USERDATA_PATH = OpenHAB.getUserDataFolder() + File.separator + MiIoBindingConstants.BINDING_ID; + + public static final String I18N_THING_PREFIX = "thing."; + public static final String I18N_CHANNEL_PREFIX = "ch."; + public static final String I18N_OPTION_PREFIX = "option."; } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoHandlerFactory.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoHandlerFactory.java index afb8073b11228..8a68a89a9ea59 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoHandlerFactory.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoHandlerFactory.java @@ -29,6 +29,8 @@ import org.openhab.binding.miio.internal.handler.MiIoUnsupportedHandler; import org.openhab.binding.miio.internal.handler.MiIoVacuumHandler; import org.openhab.core.common.ThreadPoolManager; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -60,6 +62,8 @@ public class MiIoHandlerFactory extends BaseThingHandlerFactory { private CloudConnector cloudConnector; private ChannelTypeRegistry channelTypeRegistry; private BasicChannelTypeProvider basicChannelTypeProvider; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; private @Nullable Future scheduledTask; private final Logger logger = LoggerFactory.getLogger(MiIoHandlerFactory.class); @@ -67,11 +71,14 @@ public class MiIoHandlerFactory extends BaseThingHandlerFactory { public MiIoHandlerFactory(@Reference HttpClientFactory httpClientFactory, @Reference ChannelTypeRegistry channelTypeRegistry, @Reference MiIoDatabaseWatchService miIoDatabaseWatchService, @Reference CloudConnector cloudConnector, - @Reference BasicChannelTypeProvider basicChannelTypeProvider, Map properties) { + @Reference BasicChannelTypeProvider basicChannelTypeProvider, @Reference TranslationProvider i18nProvider, + @Reference LocaleProvider localeProvider, Map properties) { this.httpClientFactory = httpClientFactory; this.miIoDatabaseWatchService = miIoDatabaseWatchService; this.channelTypeRegistry = channelTypeRegistry; this.basicChannelTypeProvider = basicChannelTypeProvider; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; this.cloudConnector = cloudConnector; @Nullable String username = (String) properties.get("username"); @@ -108,16 +115,18 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(THING_TYPE_MIIO)) { - return new MiIoGenericHandler(thing, miIoDatabaseWatchService, cloudConnector); + return new MiIoGenericHandler(thing, miIoDatabaseWatchService, cloudConnector, i18nProvider, + localeProvider); } if (thingTypeUID.equals(THING_TYPE_BASIC)) { return new MiIoBasicHandler(thing, miIoDatabaseWatchService, cloudConnector, channelTypeRegistry, - basicChannelTypeProvider); + basicChannelTypeProvider, i18nProvider, localeProvider); } if (thingTypeUID.equals(THING_TYPE_VACUUM)) { - return new MiIoVacuumHandler(thing, miIoDatabaseWatchService, cloudConnector, channelTypeRegistry); + return new MiIoVacuumHandler(thing, miIoDatabaseWatchService, cloudConnector, channelTypeRegistry, + i18nProvider, localeProvider); } return new MiIoUnsupportedHandler(thing, miIoDatabaseWatchService, cloudConnector, - httpClientFactory.getCommonHttpClient()); + httpClientFactory.getCommonHttpClient(), i18nProvider, localeProvider); } } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java index dd8aaa923fbae..244435a4d4779 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java @@ -50,6 +50,8 @@ import org.openhab.core.cache.ExpiringCache; import org.openhab.core.common.NamedThreadFactory; import org.openhab.core.config.core.Configuration; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.ChannelUID; @@ -60,6 +62,8 @@ import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.builder.ThingBuilder; import org.openhab.core.types.Command; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,6 +85,9 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi protected static final int MAX_QUEUE = 5; protected static final Gson GSON = new GsonBuilder().create(); protected static final String TIMESTAMP = "timestamp"; + protected final Bundle bundle; + protected final TranslationProvider i18nProvider; + protected final LocaleProvider localeProvider; protected ScheduledExecutorService miIoScheduler = new ScheduledThreadPoolExecutor(3, new NamedThreadFactory("binding-" + getThing().getUID().getAsString(), true)); @@ -114,10 +121,13 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi protected MiIoDatabaseWatchService miIoDatabaseWatchService; public MiIoAbstractHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, - CloudConnector cloudConnector) { + CloudConnector cloudConnector, TranslationProvider i18nProvider, LocaleProvider localeProvider) { super(thing); this.miIoDatabaseWatchService = miIoDatabaseWatchService; this.cloudConnector = cloudConnector; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; + this.bundle = FrameworkUtil.getBundle(this.getClass()); } @Override @@ -590,7 +600,8 @@ private void changeType(final String modelId) { String label = getThing().getLabel(); if (label == null || label.startsWith("Xiaomi Mi Device")) { ThingBuilder thingBuilder = editThing(); - thingBuilder.withLabel(miDevice.getDescription()); + label = getLocalText(I18N_THING_PREFIX + modelId, miDevice.getDescription()); + thingBuilder.withLabel(label); updateThing(thingBuilder.build()); } logger.info("Mi Device model {} identified as: {}. Does not match thingtype {}. Changing thingtype to {}", @@ -644,4 +655,13 @@ public void onMessageReceived(MiIoSendCommand response) { logger.debug("Error while handing message {}", response.getResponse(), e); } } + + protected String getLocalText(String key, String defaultText) { + try { + String text = i18nProvider.getText(bundle, key, defaultText, localeProvider.getLocale()); + return text != null ? text : defaultText; + } catch (IllegalArgumentException e) { + return defaultText; + } + } } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java index 19f7e3382aabc..d192889aad8a8 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java @@ -49,6 +49,8 @@ import org.openhab.binding.miio.internal.cloud.CloudConnector; import org.openhab.binding.miio.internal.transport.MiIoAsyncCommunication; import org.openhab.core.cache.ExpiringCache; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.HSBType; import org.openhab.core.library.types.OnOffType; @@ -106,8 +108,9 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { public MiIoBasicHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, CloudConnector cloudConnector, ChannelTypeRegistry channelTypeRegistry, - BasicChannelTypeProvider basicChannelTypeProvider) { - super(thing, miIoDatabaseWatchService, cloudConnector); + BasicChannelTypeProvider basicChannelTypeProvider, TranslationProvider i18nProvider, + LocaleProvider localeProvider) { + super(thing, miIoDatabaseWatchService, cloudConnector, i18nProvider, localeProvider); this.channelTypeRegistry = channelTypeRegistry; this.basicChannelTypeProvider = basicChannelTypeProvider; } @@ -452,6 +455,7 @@ private boolean buildChannelStructure(String deviceName) { try { JsonObject deviceMapping = Utils.convertFileToJSON(fn); logger.debug("Using device database: {} for device {}", fn.getFile(), deviceName); + String key = fn.getFile().replaceFirst("/database/", "").split("json")[0]; Gson gson = new GsonBuilder().serializeNulls().create(); miioDevice = gson.fromJson(deviceMapping, MiIoBasicDevice.class); for (Channel ch : getThing().getChannels()) { @@ -475,7 +479,7 @@ private boolean buildChannelStructure(String deviceName) { logger.debug("properties {}", miChannel); if (!miChannel.getType().isEmpty()) { basicChannelTypeProvider.addChannelType(miChannel, deviceName); - ChannelUID channelUID = addChannel(thingBuilder, miChannel, deviceName); + ChannelUID channelUID = addChannel(thingBuilder, miChannel, deviceName, key); if (channelUID != null) { actions.put(channelUID, miChannel); channelsAdded++; @@ -505,7 +509,8 @@ private boolean buildChannelStructure(String deviceName) { return false; } - private @Nullable ChannelUID addChannel(ThingBuilder thingBuilder, MiIoBasicChannel miChannel, String model) { + private @Nullable ChannelUID addChannel(ThingBuilder thingBuilder, MiIoBasicChannel miChannel, String model, + String key) { String channel = miChannel.getChannel(); String dataType = miChannel.getType(); if (channel.isEmpty() || dataType.isEmpty()) { @@ -514,7 +519,8 @@ private boolean buildChannelStructure(String deviceName) { return null; } ChannelUID channelUID = new ChannelUID(getThing().getUID(), channel); - ChannelBuilder newChannel = ChannelBuilder.create(channelUID, dataType).withLabel(miChannel.getFriendlyName()); + String label = getLocalText(I18N_CHANNEL_PREFIX + key + channel, miChannel.getFriendlyName()); + ChannelBuilder newChannel = ChannelBuilder.create(channelUID, dataType).withLabel(label); boolean useGeneratedChannelType = false; if (!miChannel.getChannelType().isBlank()) { ChannelTypeUID channelTypeUID = new ChannelTypeUID(miChannel.getChannelType()); diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoGenericHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoGenericHandler.java index 233adbd1df18c..6377698c98d99 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoGenericHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoGenericHandler.java @@ -15,6 +15,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.miio.internal.basic.MiIoDatabaseWatchService; import org.openhab.binding.miio.internal.cloud.CloudConnector; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.types.Command; @@ -33,8 +35,8 @@ public class MiIoGenericHandler extends MiIoAbstractHandler { private final Logger logger = LoggerFactory.getLogger(MiIoGenericHandler.class); public MiIoGenericHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, - CloudConnector cloudConnector) { - super(thing, miIoDatabaseWatchService, cloudConnector); + CloudConnector cloudConnector, TranslationProvider i18nProvider, LocaleProvider localeProvider) { + super(thing, miIoDatabaseWatchService, cloudConnector, i18nProvider, localeProvider); } @Override diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoUnsupportedHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoUnsupportedHandler.java index 21e0dbdb967ff..84cb9c18c5d51 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoUnsupportedHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoUnsupportedHandler.java @@ -44,6 +44,8 @@ import org.openhab.binding.miio.internal.cloud.CloudConnector; import org.openhab.binding.miio.internal.miot.MiotParser; import org.openhab.core.cache.ExpiringCache; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -87,8 +89,9 @@ public class MiIoUnsupportedHandler extends MiIoAbstractHandler { }); public MiIoUnsupportedHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, - CloudConnector cloudConnector, HttpClient httpClientFactory) { - super(thing, miIoDatabaseWatchService, cloudConnector); + CloudConnector cloudConnector, HttpClient httpClientFactory, TranslationProvider i18nProvider, + LocaleProvider localeProvider) { + super(thing, miIoDatabaseWatchService, cloudConnector, i18nProvider, localeProvider); this.httpClient = httpClientFactory; } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoVacuumHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoVacuumHandler.java index 74f7b3e45eda4..98caed804be04 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoVacuumHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoVacuumHandler.java @@ -52,6 +52,8 @@ import org.openhab.binding.miio.internal.robot.VacuumErrorType; import org.openhab.binding.miio.internal.transport.MiIoAsyncCommunication; import org.openhab.core.cache.ExpiringCache; +import org.openhab.core.i18n.LocaleProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; @@ -113,8 +115,9 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler { private RRMapDrawOptions mapDrawOptions = new RRMapDrawOptions(); public MiIoVacuumHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, - CloudConnector cloudConnector, ChannelTypeRegistry channelTypeRegistry) { - super(thing, miIoDatabaseWatchService, cloudConnector); + CloudConnector cloudConnector, ChannelTypeRegistry channelTypeRegistry, TranslationProvider i18nProvider, + LocaleProvider localeProvider) { + super(thing, miIoDatabaseWatchService, cloudConnector, i18nProvider, localeProvider); this.channelTypeRegistry = channelTypeRegistry; mapChannelUid = new ChannelUID(thing.getUID(), CHANNEL_VACUUM_MAP); status = new ExpiringCache<>(CACHE_EXPIRY, () -> { diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties new file mode 100644 index 0000000000000..124919afdbec3 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties @@ -0,0 +1,2460 @@ +# Automatic created list by miio readme maker for miio devices & database channels + +# Devices + +thing.aux.aircondition.v1 = AUX Smart Air Conditioner +thing.careli.fryer.maf01 = Mi Air Frying Pan +thing.careli.fryer.maf02 = Mi Smart Air Fryer (3.5L) +thing.careli.fryer.maf03 = Mi Air Frying Pan +thing.cgllc.airm.cgdn1 = Qingping Air Monitor Lite +thing.cgllc.airmonitor.b1 = Mi Multifunction Air Monitor +thing.cgllc.airmonitor.s1 = Qingping Air Monitor +thing.chuangmi.ir.v2 = Mi Universal Remote +thing.chuangmi.plug.212a01 = Mi Smart Power Plug 2 (Wi-Fi and Bluetooth Gateway) +thing.chuangmi.plug.hmi205 = Mi Smart Plug WiFi +thing.chuangmi.plug.hmi206 = Mi Smart Plug (WiFi) +thing.chuangmi.plug.hmi208 = Mi Smart Wi-Fi Plug (Bluetooth Gateway) +thing.chuangmi.plug.m1 = Mi Plug Mini +thing.chuangmi.plug.m3 = Mi Smart Plug (Wi-Fi) Basic +thing.chuangmi.plug.v1 = Mi Smart Power Plug +thing.chuangmi.plug.v2 = Mi Smart Power Plug v2 +thing.chuangmi.plug.v3 = MIJIA Smart Plug Enhanced +thing.chuangmi.remote.v2 = Mi Remote +thing.chunmi.cooker.normal1 = Mi IH Rice Cooker +thing.chunmi.cooker.normal2 = Mi IH Rice Cooker +thing.chunmi.cooker.normal4 = Mi IH Rice Cooker 4L +thing.chunmi.cooker.press1 = Mi IH Pressure Rice Cooker +thing.chunmi.cooker.press2 = Mi IH Pressure Rice Cooker +thing.cuco.plug.cp1 = Gosund Smart Plug +thing.deerma.humidifier.jsq = Mi Smart Antibacterial Humidifier +thing.deerma.humidifier.jsq1 = Mi S Smart Humidifer +thing.deerma.humidifier.mjjsq = Mi Smart Humidifier +thing.dmaker.airfresh.a1 = Mi Fresh Air Ventilator A1-150 +thing.dmaker.airfresh.t2017 = Mi Fresh Air Ventilator +thing.dmaker.fan.1c = Mi Smart Standing Fan 2 Lite +thing.dmaker.fan.p5 = Mi Smart Standing Fan 1X +thing.dmaker.fan.p8 = Mi Smart Standing Fan 1C +thing.dmaker.fan.p9 = Mi Smart Tower Fan +thing.dmaker.fan.p10 = Mi Smart Standing Fan 2 +thing.dmaker.fan.p15 = Mi Smart Standing Fan Pro +thing.dmaker.fan.p18 = Mi Smart Standing Fan 2 +thing.dreame.vacuum.mc1808 = Mi Robot Vacuum Mop 1C STYTJ01ZHM +thing.dreame.vacuum.p2008 = Dreame Robot Vacuum-Mop F9 +thing.dreame.vacuum.p2009 = Dreame Robot Vacuum D9 +thing.dreame.vacuum.p2036 = Trouver Robot LDS Vacuum-Mop Finder +thing.dreame.vacuum.p2041o = Mi Robot Vacuum-Mop 2 Pro+ +thing.dreame.vacuum.p2156o = MOVA Z500 Robot Vacuum and Mop Cleaner +thing.dreame.vacuum.p2157 = MOVA L600 Robot Vacuum and Mop Cleaner +thing.huayi.light.ari013 = HUIZUO ARIES For Bedroom +thing.huayi.light.aries = HUIZUO ARIES For Living Room +thing.huayi.light.fanwy = HUIZUO Fan Light +thing.huayi.light.fanwy2 = HUIZUO Fan Light(2020) +thing.huayi.light.peg091 = HUIZUO PEGASUS For Living Room +thing.huayi.light.peg093 = HUIZUO PEGASUS For Bedroom +thing.huayi.light.pis123 = HUIZUO PISCES For Bedroom +thing.huayi.light.pisces = HUIZUO PISCES For Living Room +thing.huayi.light.tau023 = HUIZUO TAURUS For Bedroom +thing.huayi.light.taurus = HUIZUO TAURUS For Living Room +thing.huayi.light.vir063 = HUIZUO VIRGO For Bedroom +thing.huayi.light.virgo = HUIZUO VIRGO For Living Room +thing.huayi.light.wy = HUIZUO Ceiling Light +thing.huayi.light.wy200 = HUIZUO LIANGCHEN(BLE Mesh) +thing.huayi.light.wy201 = HUIZUO SAG Downlight (BLE Mesh) +thing.huayi.light.wy202 = HUIZUO Bulb (BLE Mesh) +thing.huayi.light.wy203 = HUIZUO YONG Downlight (BLE Mesh) +thing.huayi.light.wy204 = huayi.light.wy204 +thing.huayi.light.wyheat = HUIZUO Heating Lamp +thing.huayi.light.zw131 = HUIZUO ZIWEI Ceiling Lamp +thing.hunmi.cooker.normal3 = MiJia Rice Cooker +thing.idelan.aircondition.v1 = Jinxing Smart Air Conditioner +thing.lumi.ctrl_neutral1.v1 = Aqara Wall Switch(No Neutral, Single Rocker) +thing.lumi.ctrl_neutral2.v1 = Aqara Wall Switch (No Neutral, Double Rocker) +thing.lumi.curtain.hagl05 = Xiaomiyoupin Curtain Controller (Wi-Fi) +thing.lumi.gateway.mgl03 = Mi Air Purifier virtual +thing.lumi.gateway.v1 = Mi smart Home Gateway Hub v1 +thing.lumi.gateway.v2 = Mi smart Home GatewayHub v2 +thing.lumi.gateway.v3 = Mi smart Home Gateway Hub v3 +thing.lumi.gateway.mieu01 = Mi smart Home Gateway Hub +thing.midea.aircondition.v1 = Midea AC-i Youth +thing.midea.aircondition.v2 = Midea Air Conditioner v2 +thing.midea.aircondition.xa1 = Midea AC-Cool Golden +thing.mijia.vacuum.v2 = Mi Robot Vacuum-Mop Essential +thing.mmgg.pet_waterer.s1 = Mijia Smart Pet Water Dispenser +thing.mmgg.pet_waterer.s2 = Mijia Smart Pet Water Dispenser +thing.mmgg.pet_waterer.s3 = Mijia Smart Pet Water Dispenser +thing.mmgg.pet_waterer.s4 = XIAOWAN Smart Pet Water Dispenser +thing.mrbond.airer.m1pro = MR.BOND +thing.mrbond.airer.m1s = MR.BOND +thing.mrbond.airer.m1super = MR.BOND +thing.nwt.derh.wdh318efw1 = WIDETECH WDH318EFW1 Internet Dehumidifier +thing.philips.light.bceiling1 = Philips Zhirui Ceiling Lamp Bedroom 40W +thing.philips.light.bceiling2 = Philips Zhirui Ceiling Lamp Bedroom 28W +thing.philips.light.bulb = Philips ZhiRui E27 bulb +thing.philips.light.candle = Philips ZhiRui E14 Candle Lamp Frosted version +thing.philips.light.candle2 = Philips ZhiRui E14 Candle Lamp Crystal version +thing.philips.light.cbulb = Mijia Philips Color Bulb +thing.philips.light.cbulbs = Philips Light +thing.philips.light.ceiling = Philips Connected Ceiling +thing.philips.light.dcolor = Philips Light +thing.philips.light.dlight = ZhiRui Dimmable Downlight +thing.philips.light.downlight = Philips ZhiRui Downlight +thing.philips.light.hbulb = Philips Wi-Fi bulb E27 White +thing.philips.light.lnblight1 = Philips ZhiYi Ceiling Lamp FL 40W +thing.philips.light.lnblight2 = Philips ZhiYi Ceiling Lamp FL 28W +thing.philips.light.lnlrlight = Philips ZhiYi Ceiling Lamp FL 80W +thing.philips.light.lrceiling = Philips Zhirui Ceiling Lamp Living room 80W +thing.philips.light.mceil = Zhirui Ceiling Lamp Nordic 80W +thing.philips.light.mceilm = Zhirui Ceiling Lamp Nordic 40W +thing.philips.light.mceils = Zhirui Ceiling Lamp Nordic 28W +thing.philips.light.mono1 = Philips Smart Lamp +thing.philips.light.moonlight = Philips ZhiRui Bedside Lamp +thing.philips.light.obceil = Zhirui Ceiling Lamp Black 80W +thing.philips.light.obceim = Zhirui Ceiling Lamp Black 40W +thing.philips.light.obceis = Zhirui Ceiling Lamp Black 28W +thing.philips.light.rwread = Mijia Philips Study Desk Lamp +thing.philips.light.sceil = Zhirui Ceiling Lamp Starry 80W +thing.philips.light.sceilm = Zhirui Ceiling Lamp Starry 40W +thing.philips.light.sceils = Zhirui Ceiling Lamp Starry 28W +thing.philips.light.sread1 = Philips EyeCare Connected Desk Lamp gen2. +thing.philips.light.sread2 = Mijia Philips Desk Lamp 2S +thing.philips.light.virtual = Philips Connected Lights +thing.philips.light.xzceil = Zhirui Ceiling Lamp Gorgeous 80W +thing.philips.light.xzceim = Zhirui Ceiling Lamp Gorgeous 40W +thing.philips.light.xzceis = Zhirui Ceiling Lamp Gorgeous 28W +thing.philips.light.zyceiling = Philips ZhiYi Ceiling lamp +thing.philips.light.zysread = Philips ZhiYi Desk Lamp +thing.philips.light.zystrip = Philips ZhiYi Strip +thing.qmi.powerstrip.v1 = CHINGMI Smart Power Strip v1 +thing.roborock.sweeper.e2v2 = Rockrobo Xiaowa Sweeper v2 +thing.roborock.sweeper.e2v3 = Rockrobo Xiaowa Sweeper v3 +thing.roborock.vacuum.a08 = Roborock S6 Pure +thing.roborock.vacuum.a09 = Roborock T7 Pro +thing.roborock.vacuum.a10 = Roborock S6 MaxV +thing.roborock.vacuum.a11 = Roborock T7 +thing.roborock.vacuum.a14 = Roborock T7S +thing.roborock.vacuum.a15 = Roborock S7 +thing.roborock.vacuum.a19 = Roborock S4 Max +thing.roborock.vacuum.a23 = Roborock T7S Plus +thing.roborock.vacuum.c1 = Xiaowa C1 +thing.roborock.vacuum.e2 = Roborock Xiaowa E Series Vacuum v2 +thing.roborock.vacuum.m1s = Mi Robot Vacuum 1S +thing.roborock.vacuum.p5 = Roborock P5 +thing.roborock.vacuum.s4 = Roborock S4 +thing.roborock.vacuum.s4v2 = Roborock Vacuum S4v2 +thing.roborock.vacuum.s5 = Roborock S5 +thing.roborock.vacuum.s5e = Roborock S5 Max +thing.roborock.vacuum.s6 = Roborock S6 +thing.roborock.vacuum.t4 = Roborock T4 +thing.roborock.vacuum.t4v2 = Roborock Vacuum T4 v2 +thing.roborock.vacuum.t4v3 = Roborock Vacuum T4 v3 +thing.roborock.vacuum.t6 = Roborock T6 +thing.roborock.vacuum.t6v2 = Roborock Vacuum T6 v2 +thing.roborock.vacuum.t6v3 = Roborock Vacuum T6 v3 +thing.roborock.vacuum.t7 = Roborock Vacuum T7 +thing.roborock.vacuum.t7p = Roborock Vacuum T7p +thing.roborock.vacuum.t7pv2 = Roborock Vacuum T7 v2 +thing.roborock.vacuum.t7pv3 = Roborock Vacuum T7 v3 +thing.roborock.vacuum.t7v2 = Roborock Vacuum T7 v2 +thing.roborock.vacuum.t7v3 = Roborock Vacuum T7 v3 +thing.rockrobo.vacuum.s6 = Roborock Vacuum S6 +thing.rockrobo.vacuum.v1 = Mi Robot Vacuum +thing.090615.switch.xswitch01 = PTX OneKey Switch (WIFI) +thing.090615.switch.xswitch02 = PTX Twokey switch(wifi) +thing.090615.switch.xswitch03 = PTX ThreeKey Switch (WIFI) +thing.scishare.coffee.s1102 = SCISHARE Smart Capsule Coffee Machine +thing.scishare.coffee.s1301 = Xiaomi Scishare Smart Capsule Coffee Machine +thing.soocare.toothbrush.x3 = Soocare Electric Toothbrush +thing.viomi.fridge.v3 = Viomi Internet Refrigerator iLive(French style 462L) +thing.viomi.vacuum.v6 = Viomi Cleaning Robot V-RVCLM21B +thing.viomi.vacuum.v7 = Mi Robot Vacuum-Mop P +thing.viomi.vacuum.v8 = Mi Robot Vacuum-Mop P +thing.viomi.vacuum.v18 = Viomi S9 +thing.viomi.waterheater.e1 = VIOMI Internet Electric Water Heater 1A (60L) +thing.xiaomi.aircondition.ma1 = Mi Inverter Air Conditioner (1.5HP) +thing.xiaomi.aircondition.ma2 = Mi Inverter Air Conditioner (1.5HP, China Energy Label Level 1) +thing.xiaomi.aircondition.ma4 = Mi Vertical Air Conditioner (2HP) +thing.xiaomi.aircondition.ma5 = Mi Smart Vertical Air Conditioner C1 (2HP / Inverter / China Energy Label Level 1) +thing.xiaomi.aircondition.ma6 = Mi Smart Air Conditioner C1 (1.5HP / Conventional / China Energy Label Level 3) +thing.xiaomi.aircondition.ma9 = Mi Smart Air Conditioner C1 (1HP / Inverter / China Energy Label Level 1) +thing.xiaomi.aircondition.mc1 = Mi Smart Air Conditioner A (1HP / Inverter / China Energy Label Level 1) +thing.xiaomi.aircondition.mc2 = Mi Smart Air Conditioner A (1.5HP / Inverter / China Energy Label Level 1) +thing.xiaomi.aircondition.mc4 = Mi Smart Air Conditioner A (1HP / Inverter / China Energy Label Level <1) +thing.xiaomi.aircondition.mc5 = Mi Smart Air Conditioner A (1.5HP / Inverter / China Energy Label Level <1) +thing.xiaomi.aircondition.mc6 = Mi Smart Vertical Air Conditioner A (2HP / Inverter / China Energy Label Level <1) +thing.xiaomi.aircondition.mc7 = Mi Smart Vertical Air Conditioner A (3HP / Inverter / China Energy Label Level <1) +thing.xiaomi.aircondition.mc8 = Mi Smart Ultra Electricity Saving Air Conditioner(1.5HP/Inverter/New China Energy Label Level 3) +thing.xiaomi.aircondition.mc9 = Mi Smart Ultra Electricity Saving Vertical Air Conditioner(2HP/Inverter/New China Energy Label Level 3) +thing.xiaomi.aircondition.c10 = Mi Smart Ultra Electricity Saving Vertical Air Conditioner (2HP/Inverter/New China Energy Label Level 1) +thing.xiaomi.aircondition.c11 = Mi Smart Ultra Electricity Saving Vertical Air Conditioner (3HP/Inverter/New China Energy Label Level 1) +thing.xiaomi.aircondition.mh1 = Mi Smart Air Conditioner C (1HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mh2 = Mi Smart Air Conditioner C (1.5HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mh3 = Mi Smart Ultra Electricity Saving Air Conditioner(1HP/Inverter/New China Energy Label Level 3) +thing.xiaomi.aircondition.mt1 = Mi Smart Air Conditioner X (1HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mt2 = Mi Smart Air Conditioner X (1.5HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mt3 = Mi Smart Gentle Breeze Air Conditioner (1HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mt4 = Mi Smart Gentle Breeze Air Conditioner (1.5HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mt5 = Mi Smart Gentle Breeze Vertical Air Conditioner (3HP / Inverter / New China Energy Label Level 1) +thing.xiaomi.aircondition.mt7 = Mi Smart Ultra Electricity Saving Air Conditioner (1HP/Inverter/New China Energy Label Level 1) +thing.xiaomi.aircondition.mt8 = Mi Smart Ultra Electricity Saving Air Conditioner (1.5HP/Inverter/New China Energy Label Level 1) +thing.xiaomi.repeater.v2 = Mi Wi-Fi Repeater 2 +thing.xiaomi.wifispeaker.v1 = Mi Network Speaker +thing.xjx.toilet.pro = Uclean Smart Toilet Seat +thing.xjx.toilet.pure = Uclean Smart Toilet pure +thing.xjx.toilet.relax = Uclean Smart Toilet relax +thing.xjx.toilet.zero = Whale Spout Smart Toilet Zero +thing.yeelight.bhf_light.v2 = Yeelight Smart Bath Heater +thing.yeelink.bhf_light.v1 = Yeelight Smart Bath Heater Pro +thing.yeelink.bhf_light.v2 = Yeelight Smart Bath Heater +thing.yeelink.light.bslamp1 = Mi Bedside Lamp +thing.yeelink.light.bslamp2 = Mi Bedside Lamp 2 +thing.yeelink.light.bslamp3 = Yeelight Bedside Lamp II +thing.yeelink.light.ceiling1 = Yeelight Ceiling Light +thing.yeelink.light.ceiling2 = Yeelight Ceiling Light SE +thing.yeelink.light.ceiling3 = Yeelight LED Ceiling Light +thing.yeelink.light.ceiling4 = Yeelight LED Ceiling Light +thing.yeelink.light.ceiling4.ambi = Yeelight LED Ceiling Ambi Lamp +thing.yeelink.light.ceiling5 = Mi LED Ceiling Light +thing.yeelink.light.ceiling6 = Yeelight HaoShi LED Ceiling Lamp Pro +thing.yeelink.light.ceiling7 = Yeelight Haoshi Ceiling Lamp +thing.yeelink.light.ceiling8 = LED Ceiling Light Crystal Plus +thing.yeelink.light.ceiling9 = Yeelight HaoShi LED Ceiling Lamp Pro +thing.yeelink.light.ceiling10 = Yeelight Crystal Pendant Lamp +thing.yeelink.light.ceiling10.ambi = Yeelight LED Ceiling Ambi Lamp +thing.yeelink.light.ceiling11 = Yeelight Ceiling Light 320 1S +thing.yeelink.light.ceiling12 = Yeelight Stylized Ceiling Light Pro +thing.yeelink.light.ceiling13 = Yeelight Ceiling Light +thing.yeelink.light.ceiling14 = Yeelight Ceiling Light Mini +thing.yeelink.light.ceiling15 = Yeelight Ceiling Light 480 1S +thing.yeelink.light.ceiling16 = Yeelight Xingyu Ceiling Light +thing.yeelink.light.ceiling17 = Yeelight ShaoHua Celing Light +thing.yeelink.light.ceiling18 = Yeelight Ceiling Light Pro +thing.yeelink.light.ceiling19 = Yeelight Ceiling Light Pro +thing.yeelink.light.ceiling19.ambi = Yeelight LED Ceiling Ambi Lamp +thing.yeelink.light.ceiling20 = Yeelight Ceiling Light +thing.yeelink.light.ceiling20.ambi = Yeelight LED Ceiling Ambi Lamp +thing.yeelink.light.ceiling21 = Mi Smart LED Living Room Ceiling Light +thing.yeelink.light.ceiling22 = Mi Smart LED Ceiling Light +thing.yeelink.light.ceiling23 = Mi Smart LED Ceiling Light (350mm) +thing.yeelink.light.ceil26 = Yeelight Jade Smart LED Ceiling Light C2001 +thing.yeelink.light.color1 = Yeelight Color Bulb +thing.yeelink.light.color2 = Yeelight LED Bulb (Color) +thing.yeelink.light.color3 = Mi LED Smart Bulb (White and Color) +thing.yeelink.light.color4 = Yeelight LED Bulb 1S(Color) +thing.yeelink.light.color5 = Mi Smart LED Bulb Essential (White and Color) +thing.yeelink.light.colora = Yeelight Smart LED Bulb 1SE (color) +thing.yeelink.light.ct2 = Yeelight LED Bulb (Tunable) +thing.yeelink.light.lamp1 = Mi LED Desk Lamp +thing.yeelink.light.lamp2 = Mi Smart LED Desk Lamp Pro +thing.yeelink.light.lamp3 = Yeelight LED Lamp +thing.yeelink.light.lamp4 = Mi LED Desk Lamp 1S +thing.yeelink.light.lamp5 = Yeelight Smart Desk Lamp Prime +thing.yeelink.light.lamp6 = Yeelight +thing.yeelink.light.lamp7 = Yeelight LED Light Sensor Desk Lamp V1 +thing.yeelink.light.lamp8 = Yeelight +thing.yeelink.light.lamp9 = Yeelight Star LED Table Lamp +thing.yeelink.light.lamp10 = Yeelight Star Floor Lamp +thing.yeelink.light.lamp15 = Yeelight Screen Light Bar +thing.yeelink.light.mono1 = Yeelight Bulb +thing.yeelink.light.mono2 = Yeelight White Bulb v2 +thing.yeelink.light.mono4 = Yeelight LED Bulb 1S(Dimmable) +thing.yeelink.light.mono5 = Yeelight LED Filament Bulb +thing.yeelink.light.mono6 = Mi Smart LED Bulb +thing.yeelink.light.monoa = Yeelight LED smart bulb W3(dimmable) +thing.yeelink.light.monob = Yeelight GU10 Smart Bulb W1(dimmable) +thing.yeelink.light.panel1 = Yeelight Whiteglow Panel Light +thing.yeelink.light.strip1 = Yeelight Lightstrip +thing.yeelink.light.strip2 = Yeelight Lightstrip Plus +thing.yeelink.light.strip4 = Yeelight Willow LED Lightstrip +thing.yeelink.light.virtual = Light Group (Mi & Yeelight) +thing.yeelink.switch.sw1 = Yeelight Smart Dual Control Module +thing.yeelink.wifispeaker.v1 = Yeelight Smart Speaker +thing.yilai.light.ceiling1 = Yilai Ceiling Light Aiyue 480 +thing.yilai.light.ceiling2 = Yilai Ceiling Lamp Hefeng 430 +thing.yilai.light.ceiling3 = Yilai Ceiling Lamp Hefeng Pro +thing.yunmi.waterpuri.lx2 = Mi Water Purifier lx2 +thing.yunmi.waterpuri.lx3 = Mi Water Purifier (Under Counter) +thing.yunmi.waterpuri.lx4 = Mi Water Purifier lx4 +thing.yunmi.waterpuri.lx5 = Mi Water Purifier 1A/400G Pro +thing.yunmi.waterpuri.lx6 = Mi Water Purifier (Under Counter) +thing.yunmi.waterpuri.lx7 = Mi Water Purifier 500G/500G Pro +thing.yunmi.waterpuri.lx8 = Mi Water Purifier 600G +thing.yunmi.waterpuri.lx9 = Mi Water Purifier D1 +thing.yunmi.waterpuri.lx10 = Mi Water Purifier lx10 +thing.yunmi.waterpuri.lx11 = Mi Water Purifier C1 (Triple Setting) +thing.yunmi.waterpuri.lx12 = Mi Water Purifier S1 +thing.yunmi.waterpurifier.v1 = Mi Water Purifier v1 +thing.yunmi.waterpurifier.v2 = Mi Water Purifier v2 +thing.yunmi.waterpurifier.v3 = Mi Water Purifier (Under sink) v3 +thing.yunmi.waterpurifier.v4 = Mi Water Purifier v4 +thing.zhimi.airfresh.va2 = Smartmi Ventilation System +thing.zhimi.airfresh.va4 = Smartmi Fresh Air System (Heating) +thing.zhimi.airmonitor.v1 = Mi PM2.5 Air Quality Monitor +thing.zhimi.airpurifier.m1 = Mi Air Purifier 2 (mini) +thing.zhimi.airpurifier.m2 = Mi Air Purifier 2 +thing.zhimi.airpurifier.ma1 = Mi Air Purifier 2S +thing.zhimi.airpurifier.ma2 = Mi Air Purifier 2S +thing.zhimi.airpurifier.ma4 = Mi Air Purifier 3 +thing.zhimi.airpurifier.mb1 = Mi Air Purifier 2S +thing.zhimi.airpurifier.mb3 = Mi Air Purifier 3/3H +thing.zhimi.airpurifier.mb4 = Mi Air Purifier 3C +thing.zhimi.airpurifier.mc1 = Mi Air Purifier 2S +thing.zhimi.airpurifier.mc2 = Mi Air Purifier 2H +thing.zhimi.airpurifier.sa1 = Mi Air Purifier Super +thing.zhimi.airpurifier.sa2 = Mi Air Purifier MAX / MAX Pro +thing.zhimi.airpurifier.v1 = Mi Air Purifier v1 +thing.zhimi.airpurifier.v2 = Mi Air Purifier v2 +thing.zhimi.airpurifier.v3 = Mi Air Purifier v3 +thing.zhimi.airpurifier.v5 = Mi Air Purifier v5 +thing.zhimi.airpurifier.v6 = Mi Air Purifier Pro v6 +thing.zhimi.airpurifier.v7 = Mi Air Purifier Pro v7 +thing.zhimi.airpurifier.vb2 = Mi Air Purifier Pro H +thing.zhimi.airpurifier.virtual = Mi Air Purifier virtual +thing.zhimi.airpurifier.vtl_m1 = Mi Air Purifier 2(Virtual) +thing.zhimi.airpurifier.za1 = Smartmi Air Purifier +thing.zhimi.fan.sa1 = Mi Standing Fan +thing.zhimi.fan.v1 = Mi Smart Fan +thing.zhimi.fan.v2 = Smartmi DC Pedestal Fan +thing.zhimi.fan.v3 = Smartmi DC Pedestal Fan +thing.zhimi.fan.za1 = Smartmi Inverter Pedestal Fan +thing.zhimi.fan.za3 = Smartmi Standing Fan 2 +thing.zhimi.fan.za4 = Smartmi Standing Fan 2S +thing.zhimi.fan.za5 = Smartmi Standing Fan 3 +thing.zhimi.heater.ma2 = Mi Smart Space Heater S +thing.zhimi.heater.ma3 = Mi Smart Baseboard Heater E +thing.zhimi.heater.mc2 = Mi Smart Space Heater S +thing.zhimi.heater.na1 = Smartmi Smart Fan +thing.zhimi.heater.nb1 = Smartmi Smart Fan Heater +thing.zhimi.heater.za1 = Smartmi Radiant Heater Smart Version +thing.zhimi.heater.za2 = Smartmi Smart Convector Heater 1S +thing.zhimi.heater.zb1 = Smartmi Smart Convector Heater 1S +thing.zhimi.humidifier.ca1 = Smartmi Evaporative Humidifier +thing.zhimi.humidifier.ca4 = Smartmi Evaporative Humidifer 2 +thing.zhimi.humidifier.cb1 = Smartmi Evaporative Humidifier +thing.zhimi.humidifier.cb2 = Smartmi Evaporative Humidifier +thing.zhimi.humidifier.v1 = Smartmi Humidifier +thing.zimi.clock.myk01 = Mi AI Alarm +thing.zimi.powerstrip.v2 = Mi Smart Power Strip +thing.unknown = Unknown Mi IO Device + +# Channels + +ch.090615.switch.xswitch01.switch1name = Switch Name 1 +ch.090615.switch.xswitch01.switch1state = Switch 1 +ch.090615.switch.xswitch02.switch1name = Switch Name 1 +ch.090615.switch.xswitch02.switch1state = Switch 1 +ch.090615.switch.xswitch02.switch2name = Switch Name 2 +ch.090615.switch.xswitch02.switch2state = Switch 2 +ch.090615.switch.xswitch03.switch1name = Switch Name 1 +ch.090615.switch.xswitch03.switch1state = Switch 1 +ch.090615.switch.xswitch03.switch2name = Switch Name 2 +ch.090615.switch.xswitch03.switch2state = Switch 2 +ch.090615.switch.xswitch03.switch3name = Switch Name 3 +ch.090615.switch.xswitch03.switch3state = Switch 3 +ch.careli.fryer.maf01-miot.actions = Actions +ch.careli.fryer.maf01-miot.appoint_time = Custom - Appoint Time +ch.careli.fryer.maf01-miot.appoint_time_left = Custom - Appoint Time Left +ch.careli.fryer.maf01-miot.fault = Air Fryer - Device Fault +ch.careli.fryer.maf01-miot.food_quantity = Custom - Food Quantity +ch.careli.fryer.maf01-miot.left_time = Air Fryer - Left Time +ch.careli.fryer.maf01-miot.preheat_switch = Custom - Preheat Switch +ch.careli.fryer.maf01-miot.recipe_id = Custom - Recipe Id +ch.careli.fryer.maf01-miot.recipe_name = Custom - Recipe Name +ch.careli.fryer.maf01-miot.recipe_sync = Custom - Recipe Sync +ch.careli.fryer.maf01-miot.status = Air Fryer - Status +ch.careli.fryer.maf01-miot.target_temperature = Air Fryer - Target Temperature +ch.careli.fryer.maf01-miot.target_time = Air Fryer - Target Time +ch.careli.fryer.maf01-miot.turn_pot = Custom - Turn Pot +ch.careli.fryer.maf01-miot.work_temp = Custom - Work Temp +ch.careli.fryer.maf01-miot.work_time = Custom - Work Time +ch.careli.fryer.maf02-miot.actions = Actions +ch.careli.fryer.maf02-miot.appoint_time = Custom - Appoint Time +ch.careli.fryer.maf02-miot.appoint_time_left = Custom - Appoint Time Left +ch.careli.fryer.maf02-miot.fault = Air Fryer - Device Fault +ch.careli.fryer.maf02-miot.food_quantity = Custom - Food Quantity +ch.careli.fryer.maf02-miot.left_time = Air Fryer - Left Time +ch.careli.fryer.maf02-miot.preheat_switch = Custom - Preheat Switch +ch.careli.fryer.maf02-miot.recipe_id = Custom - Recipe Id +ch.careli.fryer.maf02-miot.status = Air Fryer - Status +ch.careli.fryer.maf02-miot.target_temperature = Air Fryer - Target Temperature +ch.careli.fryer.maf02-miot.target_time = Air Fryer - Target Time +ch.careli.fryer.maf02-miot.turn_pot = Custom - Turn Pot +ch.careli.fryer.maf02-miot.work_temp = Custom - Work Temp +ch.careli.fryer.maf02-miot.work_time = Custom - Work Time +ch.cgllc.airm.cgdn1-miot.actions = Actions +ch.cgllc.airm.cgdn1-miot.battery_level = Battery - Battery Level +ch.cgllc.airm.cgdn1-miot.charging_state = Battery - Charging State +ch.cgllc.airm.cgdn1-miot.co2_density = Environment - CO2 Density +ch.cgllc.airm.cgdn1-miot.device_off = Settings - Device Off +ch.cgllc.airm.cgdn1-miot.mac = Mac - Mac +ch.cgllc.airm.cgdn1-miot.monitoring_frequency = Settings - Monitoring Frequency +ch.cgllc.airm.cgdn1-miot.pm10_density = Environment - PM10 Density +ch.cgllc.airm.cgdn1-miot.pm2_5_density = Environment - PM2 5 Density +ch.cgllc.airm.cgdn1-miot.relative_humidity = Environment - Relative Humidity +ch.cgllc.airm.cgdn1-miot.screen_off = Settings - Screen Off +ch.cgllc.airm.cgdn1-miot.tempature_unit = Settings - Tempature Unit +ch.cgllc.airm.cgdn1-miot.temperature = Environment - Temperature +ch.cgllc.airm.cgdn1-miot.voltage = Battery - Voltage +ch.cgllc.airmonitor.b1.battery = Battery +ch.cgllc.airmonitor.b1.co2 = CO2e +ch.cgllc.airmonitor.b1.humidity = Humidity +ch.cgllc.airmonitor.b1.pm25 = PM2.5 +ch.cgllc.airmonitor.b1.temperature = Temperature +ch.cgllc.airmonitor.b1.tvoc = tVOC +ch.cgllc.airmonitor.s1.battery = Battery +ch.cgllc.airmonitor.s1.co2 = CO2 +ch.cgllc.airmonitor.s1.humidity = Humidity +ch.cgllc.airmonitor.s1.pm25 = PM2.5 +ch.cgllc.airmonitor.s1.temperature = Temperature +ch.cgllc.airmonitor.s1.tvoc = tVOC +ch.chuangmi.plug.212a01-miot.countdown = Imilab Timer - Countdown +ch.chuangmi.plug.212a01-miot.countdown-info = Imilab Timer - Countdown Info +ch.chuangmi.plug.212a01-miot.electric-current = Power Consumption - Electric Current +ch.chuangmi.plug.212a01-miot.electric-power = Current Power Consumption - Electric Power +ch.chuangmi.plug.212a01-miot.off-duration = Imilab Timer - Off Duration +ch.chuangmi.plug.212a01-miot.on = Power +ch.chuangmi.plug.212a01-miot.on-duration = Imilab Timer - On Duration +ch.chuangmi.plug.212a01-miot.on1 = Indicator Light - Switch Status +ch.chuangmi.plug.212a01-miot.power-consumption = Daily Power Consumption +ch.chuangmi.plug.212a01-miot.task-switch = Imilab Timer - Task Switch +ch.chuangmi.plug.212a01-miot.temperature = Temperature +ch.chuangmi.plug.212a01-miot.voltage = Power Consumption - Voltage +ch.chuangmi.plug.212a01-miot.working-time = Working Time +ch.chuangmi.plug.m1.led = Indicator light +ch.chuangmi.plug.m1.power = Power +ch.chuangmi.plug.m1.temperature = Temperature +ch.chuangmi.plug.v1.power = Power +ch.chuangmi.plug.v1.temperature = Temperature +ch.chuangmi.plug.v1.usb = USB +ch.chuangmi.plug.v2.power = Power +ch.chuangmi.plug.v2.usb = USB +ch.chuangmi.plug.v3.led = Wifi LED +ch.chuangmi.plug.v3.power = Power +ch.chuangmi.plug.v3.temperature = Temperature +ch.chuangmi.plug.v3.usb = USB +ch.cuco.plug.cp1-miot.FirmwareRevision = Device Information-CurrentFirmware Version +ch.cuco.plug.cp1-miot.Manufacturer = Device Information-Device Manufacturer +ch.cuco.plug.cp1-miot.Model = Device Information-Device Model +ch.cuco.plug.cp1-miot.On = Switch-Switch Status +ch.cuco.plug.cp1-miot.SerialNumber = Device Information-Device Serial Number +ch.deerma.humidifier.jsq1.humidity = Humidity +ch.deerma.humidifier.jsq1.humidity_set = Humidity Setting +ch.deerma.humidifier.jsq1.led = LED indicator Light +ch.deerma.humidifier.jsq1.mode = Mode +ch.deerma.humidifier.jsq1.power = Power +ch.deerma.humidifier.jsq1.sound = Notification Sounds +ch.deerma.humidifier.jsq1.watertankstatus = Watertank Status +ch.deerma.humidifier.jsq1.wet_and_protect = Wet and Protect +ch.deerma.humidifier.mjjsq.humidity = Humidity +ch.deerma.humidifier.mjjsq.humidity_set = Humidity Setting +ch.deerma.humidifier.mjjsq.led = LED indicator Light +ch.deerma.humidifier.mjjsq.mode = Mode +ch.deerma.humidifier.mjjsq.power = Power +ch.deerma.humidifier.mjjsq.sound = Notification Sounds +ch.deerma.humidifier.mjjsq.watertankstatus = Watertank Status +ch.dmaker.airfresh.a1.airFreshCO2 = CO2 +ch.dmaker.airfresh.a1.airFreshChildLock = Child Lock +ch.dmaker.airfresh.a1.airFreshCurrentSpeed = Current Speed +ch.dmaker.airfresh.a1.airFreshDisplay = Display +ch.dmaker.airfresh.a1.airFreshFavoriteSpeed = Favorite Speed +ch.dmaker.airfresh.a1.airFreshFilterDays = Filter Days Remaining +ch.dmaker.airfresh.a1.airFreshFilterPercents = Filter Percents Remaining +ch.dmaker.airfresh.a1.airFreshMode = Mode +ch.dmaker.airfresh.a1.airFreshPM25 = PM2.5 +ch.dmaker.airfresh.a1.airFreshPTCPower = PTC +ch.dmaker.airfresh.a1.airFreshPTCStatus = PTC Status +ch.dmaker.airfresh.a1.airFreshResetFilterA1 = Reset Filter +ch.dmaker.airfresh.a1.airFreshSound = Sound +ch.dmaker.airfresh.a1.airFreshTemperature = Temperature Outside +ch.dmaker.airfresh.a1.power = Power +ch.dmaker.airfresh.t2017.airFreshCO2 = CO2 +ch.dmaker.airfresh.t2017.airFreshChildLock = Child Lock +ch.dmaker.airfresh.t2017.airFreshCurrentSpeed = Current Speed +ch.dmaker.airfresh.t2017.airFreshDisplay = Display +ch.dmaker.airfresh.t2017.airFreshDisplayDirection = Screen direction +ch.dmaker.airfresh.t2017.airFreshFavoriteSpeed = Favorite Speed +ch.dmaker.airfresh.t2017.airFreshFilterDays = Filter Days Remaining +ch.dmaker.airfresh.t2017.airFreshFilterPercents = Filter Percents Remaining +ch.dmaker.airfresh.t2017.airFreshFilterProDays = Filter Pro Days Remaining +ch.dmaker.airfresh.t2017.airFreshFilterProPercents = Filter Pro Percents Remaining +ch.dmaker.airfresh.t2017.airFreshMode = Mode +ch.dmaker.airfresh.t2017.airFreshPM25 = PM2.5 +ch.dmaker.airfresh.t2017.airFreshPTCPower = PTC +ch.dmaker.airfresh.t2017.airFreshPTCStatus = PTC Status +ch.dmaker.airfresh.t2017.airFreshPtcLevel = PTC Level +ch.dmaker.airfresh.t2017.airFreshResetFilter = Reset Filter +ch.dmaker.airfresh.t2017.airFreshSound = Sound +ch.dmaker.airfresh.t2017.airFreshTemperature = Temperature Outside +ch.dmaker.airfresh.t2017.power = Power +ch.dmaker.fan.p15-miot.actions = Actions +ch.dmaker.fan.p15-miot.alarm = Alarm - Alarm +ch.dmaker.fan.p15-miot.fan_level = Fan - Gear Fan Level +ch.dmaker.fan.p15-miot.fault = Motor Controller - Device Fault +ch.dmaker.fan.p15-miot.horizontal_angle = Fan - Horizontal Angle +ch.dmaker.fan.p15-miot.horizontal_swing = Fan - Horizontal Swing +ch.dmaker.fan.p15-miot.mode = Fan - Mode +ch.dmaker.fan.p15-miot.off_delay_time = Off Delay Time - Off Delay Time +ch.dmaker.fan.p15-miot.on = Fan - Switch Status +ch.dmaker.fan.p15-miot.on1 = Indicator Light - Switch Status +ch.dmaker.fan.p15-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.dmaker.fan.p15-miot.status = Fan - Status +ch.dmaker.fan.p18-miot.actions = Actions +ch.dmaker.fan.p18-miot.alarm = Fan - Alarm +ch.dmaker.fan.p18-miot.brightness = Fan - Brightness +ch.dmaker.fan.p18-miot.fan_level = Fan - Fan Level +ch.dmaker.fan.p18-miot.horizontal_angle = Fan - Horizontal Angle +ch.dmaker.fan.p18-miot.horizontal_swing = Fan - Horizontal Swing +ch.dmaker.fan.p18-miot.mode = Fan - Mode +ch.dmaker.fan.p18-miot.motor_control = Fan - Motor Control +ch.dmaker.fan.p18-miot.off_delay_time = Fan - Power Off Delay Time +ch.dmaker.fan.p18-miot.on = Fan - Switch Status +ch.dmaker.fan.p18-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.dmaker.fan.p18-miot.speed_level = Fan - Speed Level +ch.dmaker.fan.p5.angle = Angle +ch.dmaker.fan.p5.beep = Beep Sound +ch.dmaker.fan.p5.child_lock = Child Lock +ch.dmaker.fan.p5.light = Light +ch.dmaker.fan.p5.mode = Mode +ch.dmaker.fan.p5.power = Power +ch.dmaker.fan.p5.roll = Rotation +ch.dmaker.fan.p5.speed = Speed +ch.dmaker.fan.p5.timer = Timer +ch.dmaker.fan.p8-miot.Alarm = Fan-Alarm +ch.dmaker.fan.p8-miot.Brightness = Fan-Brightness +ch.dmaker.fan.p8-miot.FanLevel = Fan-Fan Level +ch.dmaker.fan.p8-miot.HorizontalSwing = Fan-Horizontal Swing +ch.dmaker.fan.p8-miot.Mode = Fan-Mode +ch.dmaker.fan.p8-miot.OffDelayTime = Fan-Power Off Delay Time +ch.dmaker.fan.p8-miot.On = Fan - Switch Status +ch.dmaker.fan.p8-miot.PhysicalControlsLocked = Physical Control Locked-Physical Control Locked +ch.dmaker.fan.p8-miot.actions = Actions +ch.dmaker.fan.p9-miot.Alarm = Fan-Alarm +ch.dmaker.fan.p9-miot.Brightness = Fan-Brightness +ch.dmaker.fan.p9-miot.FanLevel = Fan-Fan Level +ch.dmaker.fan.p9-miot.HorizontalAngle = Fan-Horizontal Angle +ch.dmaker.fan.p9-miot.HorizontalSwing = Fan-Horizontal Swing +ch.dmaker.fan.p9-miot.Mode = Fan-Mode +ch.dmaker.fan.p9-miot.MotorControl = Fan-Motor Control +ch.dmaker.fan.p9-miot.OffDelayTime = Fan - Power Off Delay Time +ch.dmaker.fan.p9-miot.On = Fan-Switch Status +ch.dmaker.fan.p9-miot.PhysicalControlsLocked = Physical Control Locked-Physical Control Locked +ch.dmaker.fan.p9-miot.SpeedLevel = Fan-Speed Level +ch.dmaker.fan.p9-miot.actions = Actions +ch.dreame.vacuum.mc1808-miot.Area = clean-area +ch.dreame.vacuum.mc1808-miot.BatteryLevel = Battery-Battery Level +ch.dreame.vacuum.mc1808-miot.BrushLeftTime = Main Cleaning Brush-Brush Left Time +ch.dreame.vacuum.mc1808-miot.BrushLeftTime1 = Side Cleaning Brush-Brush Left Time +ch.dreame.vacuum.mc1808-miot.BrushLifeLevel = Main Cleaning Brush-Brush Life Level +ch.dreame.vacuum.mc1808-miot.BrushLifeLevel1 = Side Cleaning Brush-Brush Life Level +ch.dreame.vacuum.mc1808-miot.ButtonLed = Clean - Button Led +ch.dreame.vacuum.mc1808-miot.ChargingState = Battery-Charging State +ch.dreame.vacuum.mc1808-miot.CleanLogStartTime = Clean - Clean Log Start Time +ch.dreame.vacuum.mc1808-miot.Enable = Annoy - Enable +ch.dreame.vacuum.mc1808-miot.Fault = Robot Cleaner-Device Fault +ch.dreame.vacuum.mc1808-miot.FilterLeftTime = Filter-Filter Left Time +ch.dreame.vacuum.mc1808-miot.FilterLifeLevel = Filter - Filter Life Level +ch.dreame.vacuum.mc1808-miot.LifeBrushMain = Consumable - Life Brush Main +ch.dreame.vacuum.mc1808-miot.LifeBrushSide = Consumable - Life Brush Side +ch.dreame.vacuum.mc1808-miot.LifeSieve = Consumable - Life Sieve +ch.dreame.vacuum.mc1808-miot.MapView = Map - Map View +ch.dreame.vacuum.mc1808-miot.Mode = clean-mode +ch.dreame.vacuum.mc1808-miot.StartTime = Annoy - Start Time +ch.dreame.vacuum.mc1808-miot.Status = Robot Cleaner-Status +ch.dreame.vacuum.mc1808-miot.StopTime = Annoy - Stop Time +ch.dreame.vacuum.mc1808-miot.TaskDone = Clean - Task Done +ch.dreame.vacuum.mc1808-miot.TimeZone = Time - Time Zone +ch.dreame.vacuum.mc1808-miot.Timer = clean-timer +ch.dreame.vacuum.mc1808-miot.TotalCleanArea = Clean - Total Clean Area +ch.dreame.vacuum.mc1808-miot.TotalCleanTime = Clean - Total Clean Time +ch.dreame.vacuum.mc1808-miot.TotalCleanTimes = Clean - Total Clean Times +ch.dreame.vacuum.mc1808-miot.VoicePackets = Audio - Voice Packets +ch.dreame.vacuum.mc1808-miot.Volume = Audio - Volume +ch.dreame.vacuum.mc1808-miot.WorkMode = clean-workmode +ch.dreame.vacuum.mc1808-miot.vacuumaction = Vacuum Action +ch.dreame.vacuum.mc1808-miot.water-mode = Water Mode +ch.dreame.vacuum.p2008-miot.battery-level = Battery - Battery Level +ch.dreame.vacuum.p2008-miot.break-point-restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2008-miot.brush-left-time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2008-miot.brush-left-time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2008-miot.brush-life-level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2008-miot.brush-life-level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2008-miot.carpet-press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2008-miot.charging-state = Battery - Charging State +ch.dreame.vacuum.p2008-miot.cleaning-area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2008-miot.cleaning-mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2008-miot.cleaning-time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2008-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2008-miot.end-time = Do Not Disturb - End Time +ch.dreame.vacuum.p2008-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2008-miot.filter-left-time = Filter - Filter Left Time +ch.dreame.vacuum.p2008-miot.filter-life-level = Filter - Filter Life Level +ch.dreame.vacuum.p2008-miot.first-clean-time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2008-miot.mop-mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2008-miot.save-map-status = Vslam Extend - Save Map Status +ch.dreame.vacuum.p2008-miot.start-time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2008-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2008-miot.task-status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2008-miot.time-zone = Time - Time Zone +ch.dreame.vacuum.p2008-miot.timer-clean = Time - Timer Clean +ch.dreame.vacuum.p2008-miot.total-clean-area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2008-miot.total-clean-time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2008-miot.total-clean-times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2008-miot.voice-change-state = Audio - Voice Change State +ch.dreame.vacuum.p2008-miot.voice-packet-id = Audio - Voice Packet Id +ch.dreame.vacuum.p2008-miot.volume = Audio - Volume +ch.dreame.vacuum.p2008-miot.waterbox-status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2008-miot.work-mode = Vacuum Extend - Work Mode +ch.dreame.vacuum.p2009-miot.battery-level = Battery - Battery Level +ch.dreame.vacuum.p2009-miot.break-point-restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2009-miot.brush-left-time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2009-miot.brush-left-time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2009-miot.brush-life-level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2009-miot.brush-life-level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2009-miot.carpet-press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2009-miot.charging-state = Battery - Charging State +ch.dreame.vacuum.p2009-miot.clean-rags-tip = Vacuum Extend - Clean Rags Tip +ch.dreame.vacuum.p2009-miot.cleaning-area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2009-miot.cleaning-mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2009-miot.cleaning-time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2009-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2009-miot.end-time = Do Not Disturb - End Time +ch.dreame.vacuum.p2009-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2009-miot.faults = Vacuum Extend - Faults +ch.dreame.vacuum.p2009-miot.filter-left-time = Filter - Filter Left Time +ch.dreame.vacuum.p2009-miot.filter-life-level = Filter - Filter Life Level +ch.dreame.vacuum.p2009-miot.first-clean-time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2009-miot.keep-sweeper-time = Vacuum Extend - Keep Sweeper Time +ch.dreame.vacuum.p2009-miot.mop-mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2009-miot.resetConsumable = Consumables Reset +ch.dreame.vacuum.p2009-miot.serial-number1 = Vacuum Extend - Serial Number +ch.dreame.vacuum.p2009-miot.start-time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2009-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2009-miot.task-status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2009-miot.time-zone = Time - Time Zone +ch.dreame.vacuum.p2009-miot.timer-clean = Time - Timer Clean +ch.dreame.vacuum.p2009-miot.total-clean-area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2009-miot.total-clean-time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2009-miot.total-clean-times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2009-miot.vacuumaction = Vacuum Action +ch.dreame.vacuum.p2009-miot.voice-change-state = Audio - Voice Change State +ch.dreame.vacuum.p2009-miot.voice-packet-id = Audio - Voice Packet Id +ch.dreame.vacuum.p2009-miot.volume = Audio - Volume +ch.dreame.vacuum.p2009-miot.waterbox-status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2009-miot.work-mode = Vacuum Extend - Work Mode +ch.dreame.vacuum.p2156o-miot.actions = Actions +ch.dreame.vacuum.p2156o-miot.battery_level = Battery - Battery Level +ch.dreame.vacuum.p2156o-miot.break_point_restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2156o-miot.brush_left_time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2156o-miot.brush_left_time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2156o-miot.brush_life_level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2156o-miot.brush_life_level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2156o-miot.carpet_press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2156o-miot.charging_state = Battery - Charging State +ch.dreame.vacuum.p2156o-miot.cleaning-area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2156o-miot.cleaning_mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2156o-miot.cleaning_time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2156o-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2156o-miot.end_time = Do Not Disturb - End Time +ch.dreame.vacuum.p2156o-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2156o-miot.faults = Vacuum Extend - Faults +ch.dreame.vacuum.p2156o-miot.filter_left_time = Filter - Filter Left Time +ch.dreame.vacuum.p2156o-miot.filter_life_level = Filter - Filter Life Level +ch.dreame.vacuum.p2156o-miot.first_clean_time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2156o-miot.keep_sweeper_time = Vacuum Extend - Keep Sweeper Time +ch.dreame.vacuum.p2156o-miot.mode = Robot Cleaner - Mode +ch.dreame.vacuum.p2156o-miot.mop_mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2156o-miot.save_map_status = Vslam Extend - Save Map Status +ch.dreame.vacuum.p2156o-miot.serial_number = Vacuum Extend - Serial Number +ch.dreame.vacuum.p2156o-miot.start_time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2156o-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2156o-miot.task_status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2156o-miot.time_zone = Time - Time Zone +ch.dreame.vacuum.p2156o-miot.timer_clean = Time - Timer Clean +ch.dreame.vacuum.p2156o-miot.total_clean_area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2156o-miot.total_clean_time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2156o-miot.total_clean_times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2156o-miot.voice_change_state = Audio - Voice Change State +ch.dreame.vacuum.p2156o-miot.voice_packet_id = Audio - Voice Packet Id +ch.dreame.vacuum.p2156o-miot.volume = Audio - Volume +ch.dreame.vacuum.p2156o-miot.waterbox_status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2156o-miot.work_mode = Vacuum Extend - Work Mode +ch.huayi.light.fanwy-miot.brightness = Light - Brightness +ch.huayi.light.fanwy-miot.color-temperature = Light - Color Temperature +ch.huayi.light.fanwy-miot.fan-level = Fan - Fan Level +ch.huayi.light.fanwy-miot.mode = Fan - Mode +ch.huayi.light.fanwy-miot.motor-reverse = Fan - Motor Reverse +ch.huayi.light.fanwy-miot.on = Light - Power +ch.huayi.light.fanwy-miot.on1 = Fan - Power +ch.huayi.light.fanwy2-miot.brightness = Light - Brightness +ch.huayi.light.fanwy2-miot.color-temperature = Light - Color Temperature +ch.huayi.light.fanwy2-miot.fan-level = Fan - Fan Level +ch.huayi.light.fanwy2-miot.flabellum = Presets - Flabellum +ch.huayi.light.fanwy2-miot.mode = Fan - Mode +ch.huayi.light.fanwy2-miot.on = Light - Power +ch.huayi.light.fanwy2-miot.on1 = Fan - Power +ch.huayi.light.fanwy2-miot.pre-brightness = Presets - Pre Brightness +ch.huayi.light.fanwy2-miot.pre-colortemp = Presets - Pre Colortemp +ch.huayi.light.fanwy2-miot.pre-custom = Presets - Pre Custom +ch.huayi.light.fanwy2-miot.pre-speed = Presets - Pre Speed +ch.huayi.light.fanwy2-miot.reversal = Presets - Reversal +ch.huayi.light.fanwy2-miot.time-off = Presets - Time Off +ch.huayi.light.pis123-miot.brightness = Light - Brightness +ch.huayi.light.pis123-miot.color-temperature = Light - Color Temperature +ch.huayi.light.pis123-miot.on = Light - Power +ch.huayi.light.wy200-miot.brightness = Light - Brightness +ch.huayi.light.wy200-miot.color-temperature = Light - Color Temperature +ch.huayi.light.wy200-miot.on = Light - Power +ch.huayi.light.wyheat-miot.brightness = Light - Brightness +ch.huayi.light.wyheat-miot.color-temperature = Light - Color Temperature +ch.huayi.light.wyheat-miot.fault = Heater - Device Fault +ch.huayi.light.wyheat-miot.heat-level = Heater - Heat Level +ch.huayi.light.wyheat-miot.on = Light - Power +ch.huayi.light.wyheat-miot.on1 = Heater - Power +ch.huayi.light.wyheat-miot.screenshow = Other - Screenshow +ch.lumi.curtain.hagl05-miot.current-position = Curtain - Current Position +ch.lumi.curtain.hagl05-miot.en-night-tip-light = Set Night Tip Light +ch.lumi.curtain.hagl05-miot.fault = Curtain - Device Fault +ch.lumi.curtain.hagl05-miot.manual-enabled = curtain_cfg - Manual Enabled +ch.lumi.curtain.hagl05-miot.polarity = curtain_cfg - Polarity +ch.lumi.curtain.hagl05-miot.pos-limit = curtain_cfg - Position Limit +ch.lumi.curtain.hagl05-miot.run-time = curtain_cfg - Run-time +ch.lumi.curtain.hagl05-miot.status = Curtain - Status +ch.lumi.curtain.hagl05-miot.target-position = Curtain - Target Position +ch.lumi.gateway.alarmingVol = Alarming Volume +ch.lumi.gateway.doorbellPush = Doorbell Push +ch.lumi.gateway.doorbellVol = Doorbell Volume +ch.lumi.gateway.gatewayVol = Gateway Volume +ch.lumi.gateway.mieu01.alarming_volume = Alarming Volume +ch.lumi.gateway.mieu01.arming_time = Arming Time +ch.lumi.gateway.mieu01.corridor = Automatic Night Light +ch.lumi.gateway.mieu01.corridor_on_time = Corridor on time +ch.lumi.gateway.mieu01.doorbell_push = Doorbell Push +ch.lumi.gateway.mieu01.doorbell_volume = Doorbell Volume +ch.lumi.gateway.mieu01.gateway_volume = Gateway Volume +ch.lumi.gateway.mieu01.guard = Guard +ch.lumi.gateway.mieu01.language = Voice prompt Language +ch.lumi.gateway.mieu01.lumi_bind = Lumi_bind info +ch.lumi.gateway.mieu01.nightlight = Night Light +ch.lumi.gateway.mieu01.rgb = Colored Light +ch.lumi.gateway.mieu01.zigbee_channel = Zigbee Channel +ch.lumi.gateway.telnetEnable = Enable Telnet +ch.mijia.vacuum.v2-miot.alarm = Alarm - Alarm +ch.mijia.vacuum.v2-miot.battery-level = Battery - Battery Level +ch.mijia.vacuum.v2-miot.brush-left-time = Brush Cleaner - Brush Left Time +ch.mijia.vacuum.v2-miot.brush-left-time1 = Brush Cleaner - Brush Left Time +ch.mijia.vacuum.v2-miot.brush-life-level = Brush Cleaner - Brush Life Level +ch.mijia.vacuum.v2-miot.brush-life-level1 = Brush Cleaner - Brush Life Level +ch.mijia.vacuum.v2-miot.charging-state = Battery - Charging State +ch.mijia.vacuum.v2-miot.clean-area = Clean Record - Clean Area +ch.mijia.vacuum.v2-miot.clean_time = Clean Record - Clean Time +ch.mijia.vacuum.v2-miot.direction_key = Remote Control - Direction Key +ch.mijia.vacuum.v2-miot.fan-level = Robot Cleaner - Fan Level +ch.mijia.vacuum.v2-miot.fault = Robot Cleaner - Device Fault +ch.mijia.vacuum.v2-miot.filter-left-time = Filter - Filter Left Time +ch.mijia.vacuum.v2-miot.filter_life_level = Filter - Filter Life Level +ch.mijia.vacuum.v2-miot.language = Language - Language +ch.mijia.vacuum.v2-miot.mode = Robot Cleaner - Mode +ch.mijia.vacuum.v2-miot.mop-status = Other Status - Mop Status +ch.mijia.vacuum.v2-miot.not-disturb-switch = Language - Not Disturb Switch +ch.mijia.vacuum.v2-miot.status = Robot Cleaner - Status +ch.mijia.vacuum.v2-miot.target-water-level = Robot Cleaner - Target Water Level +ch.mijia.vacuum.v2-miot.total-clean-area = Clean Record - Total Clean Area +ch.mijia.vacuum.v2-miot.total-clean-count = Clean Record - Total Clean Count +ch.mijia.vacuum.v2-miot.total-clean-time = Clean Record - Total Clean Time +ch.mijia.vacuum.v2-miot.vacuumaction = Vacuum Action +ch.mijia.vacuum.v2-miot.volume = Alarm - Volume +ch.mmgg.pet_waterer.s1-miot.cotton-left-time = Filter Cotton - Cotton Left Time +ch.mmgg.pet_waterer.s1-miot.fault = Pet Drinking Fountain - Device Fault +ch.mmgg.pet_waterer.s1-miot.filter-left-time = Filter - Filter Left Time +ch.mmgg.pet_waterer.s1-miot.mode = Mode +ch.mmgg.pet_waterer.s1-miot.no-water-flag = No Water Flag - No Water Flag +ch.mmgg.pet_waterer.s1-miot.no-water-time = No Water Flag - No Water Time +ch.mmgg.pet_waterer.s1-miot.on = Power +ch.mmgg.pet_waterer.s1-miot.on1 = Indicator Light - Switch +ch.mmgg.pet_waterer.s1-miot.remain-clean-time = Remain Clean Time - Remain Clean Time +ch.mmgg.pet_waterer.s1-miot.resetConsumable = Consumables Reset +ch.mmgg.pet_waterer.s2-miot.cotton-left-time = Filter Cotton - Cotton Left Time +ch.mmgg.pet_waterer.s2-miot.fault = Pet Drinking Fountain - Device Fault +ch.mmgg.pet_waterer.s2-miot.filter-left-time = Filter - Filter Left Time +ch.mmgg.pet_waterer.s2-miot.mode = Mode +ch.mmgg.pet_waterer.s2-miot.no-water-flag = No Water Flag - No Water Flag +ch.mmgg.pet_waterer.s2-miot.no-water-time = No Water Flag - No Water Time +ch.mmgg.pet_waterer.s2-miot.on = Power +ch.mmgg.pet_waterer.s2-miot.on1 = Indicator Light - Switch +ch.mmgg.pet_waterer.s2-miot.pump-block-flag = No Water Flag - Pump Block Flag +ch.mmgg.pet_waterer.s2-miot.remain-clean-time = Remain Clean Time - Remain Clean Time +ch.mmgg.pet_waterer.s2-miot.resetConsumable = Consumables Reset +ch.mrbond.airer.m1pro.airer_location = Airer Location +ch.mrbond.airer.m1pro.disinfect = disinfect +ch.mrbond.airer.m1pro.distime = Disinfect Time +ch.mrbond.airer.m1pro.dry = Dry +ch.mrbond.airer.m1pro.drytime = Dry Time +ch.mrbond.airer.m1pro.led = LED Status +ch.mrbond.airer.m1pro.motor = Motor +ch.nwt.derh.wdh318efw1.alarm = Alarm +ch.nwt.derh.wdh318efw1.autohumidity = Auto humidity +ch.nwt.derh.wdh318efw1.buzzer = Buzzer +ch.nwt.derh.wdh318efw1.childlock = Child Lock +ch.nwt.derh.wdh318efw1.compressorstatus = Compressor Status +ch.nwt.derh.wdh318efw1.defroststatus = Defrost Status +ch.nwt.derh.wdh318efw1.fanspeed = Fan Speed +ch.nwt.derh.wdh318efw1.fanst = Fan St +ch.nwt.derh.wdh318efw1.humidity = Humidity +ch.nwt.derh.wdh318efw1.led = LED +ch.nwt.derh.wdh318efw1.mode = Mode +ch.nwt.derh.wdh318efw1.power = Power +ch.nwt.derh.wdh318efw1.tankfull = Tank Full +ch.nwt.derh.wdh318efw1.temperature = Temperature +ch.philips.light.bceiling1.ac = Auto Ambiance +ch.philips.light.bceiling1.bl = Night Light +ch.philips.light.bceiling1.brightness = Brightness +ch.philips.light.bceiling1.cct = Correlated Color Temperature +ch.philips.light.bceiling1.delayoff = Delay Off +ch.philips.light.bceiling1.dv = DV +ch.philips.light.bceiling1.mb = MiBand +ch.philips.light.bceiling1.ms = MiBand Notifications +ch.philips.light.bceiling1.power = Power +ch.philips.light.bceiling1.scene = Scene +ch.philips.light.bceiling1.sw = Switch +ch.philips.light.bulb.brightness = Brightness +ch.philips.light.bulb.cct = Correlated Color Temperature +ch.philips.light.bulb.delayoff = Delay Off +ch.philips.light.bulb.dv = DV +ch.philips.light.bulb.power = Power +ch.philips.light.bulb.scene = Scene +ch.philips.light.bulb.switchscene = Switch Scene +ch.philips.light.candle.brightness = Brightness +ch.philips.light.candle.cct = Correlated Color Temperature +ch.philips.light.candle.delayoff = Delay Off +ch.philips.light.candle.power = Power +ch.philips.light.candle.scene = Scene +ch.philips.light.candle.toggle = Toggle +ch.philips.light.cbulb.brightness = Brightness +ch.philips.light.cbulb.cct = Correlated Color Temperature +ch.philips.light.cbulb.cid = Color +ch.philips.light.cbulb.delayoff = Delay Off +ch.philips.light.cbulb.power = Power +ch.philips.light.cbulb.scene = Scene +ch.philips.light.cbulb.switch_en = Switch Enabled +ch.philips.light.cbulb.switchscene = Switch Scene +ch.philips.light.ceil-miot.MibandStatus = Mi Band Status +ch.philips.light.ceil-miot.WallScene = Wall Scene +ch.philips.light.ceil-miot.WallSceneEn = Wall Scene Enable +ch.philips.light.ceil-miot.autoCct = Auto CCT +ch.philips.light.ceil-miot.brightness = Brightness +ch.philips.light.ceil-miot.cct = Color Temperature +ch.philips.light.ceil-miot.dimmingPeriod = Dimming Period +ch.philips.light.ceil-miot.dv = Delayed Turn-off +ch.philips.light.ceil-miot.mode = Mode +ch.philips.light.ceil-miot.on = Power +ch.philips.light.ceiling.brightness = Brightness +ch.philips.light.ceiling.cct = Correlated Color Temperature +ch.philips.light.ceiling.power = Power +ch.philips.light.ceiling.scene = Scene +ch.philips.light.ceiling.switchscene = Switch Scene +ch.philips.light.ceiling.toggle = Toggle +ch.philips.light.mono.brightness = Brightness +ch.philips.light.mono.power = Power +ch.philips.light.mono.scene = Scene +ch.philips.light.moonlight.brightness = Brightness +ch.philips.light.moonlight.cct = Correlated Color Temperature +ch.philips.light.moonlight.delayoff = Delay Off +ch.philips.light.moonlight.dv = DV +ch.philips.light.moonlight.gonight = Go Night +ch.philips.light.moonlight.power = Power +ch.philips.light.moonlight.scene = Scene +ch.philips.light.moonlight.toggle = Toggle +ch.philips.light.rwread.brightness = Brightness +ch.philips.light.rwread.dv = DV +ch.philips.light.rwread.flm = Follow Me +ch.philips.light.rwread.power = Power +ch.philips.light.rwread.scene = Scene +ch.philips.light.sread1.ambientBrightness = Ambient Brightness +ch.philips.light.sread1.ambientPower = Ambient Power +ch.philips.light.sread1.bl = Night Light +ch.philips.light.sread1.brightness = Brightness +ch.philips.light.sread1.eyecare = Eyecare +ch.philips.light.sread1.illumination = Ambient Illumination +ch.philips.light.sread1.power = Power +ch.qmi.powerstrip.v1.current = Current +ch.qmi.powerstrip.v1.elec_leakage = Electic Leakage +ch.qmi.powerstrip.v1.led = wifi LED +ch.qmi.powerstrip.v1.mode = Mode +ch.qmi.powerstrip.v1.power = Power +ch.qmi.powerstrip.v1.powerUsage = Power Consumption +ch.qmi.powerstrip.v1.power_factor = Power Factor +ch.qmi.powerstrip.v1.power_price = Power Price +ch.qmi.powerstrip.v1.temperature = Temperature +ch.qmi.powerstrip.v1.voltage = Voltage +ch.scishare.coffee.s1102.Status = status +ch.scishare.coffee.s1102.boil = Boil water +ch.scishare.coffee.s1102.expresso = Brew Americano +ch.scishare.coffee.s1102.power = Power +ch.viomi.vacuum.v18-miot.auto-area-id = Map - Auto Area Id +ch.viomi.vacuum.v18-miot.battery-level = Battery - Battery Level +ch.viomi.vacuum.v18-miot.clean-area = Viomi Vacuum - Clean Area +ch.viomi.vacuum.v18-miot.clean-map-url = Viomi Vacuum - Clean Map Url +ch.viomi.vacuum.v18-miot.clean-mode = Viomi Vacuum - Clean Mode +ch.viomi.vacuum.v18-miot.clean-start-time = Viomi Vacuum - Clean Start Time +ch.viomi.vacuum.v18-miot.clean-use-time = Viomi Vacuum - Clean Use Time +ch.viomi.vacuum.v18-miot.clean-way = Viomi Vacuum - Clean Way +ch.viomi.vacuum.v18-miot.contact-state = Robot Cleaner - Contact State +ch.viomi.vacuum.v18-miot.contact-state1 = Robot Cleaner - Contact State +ch.viomi.vacuum.v18-miot.contact-state2 = Robot Cleaner - Contact State +ch.viomi.vacuum.v18-miot.cur-cleaning-path = Map - Cur Cleaning Path +ch.viomi.vacuum.v18-miot.cur-lang = Viomi Vacuum - Cur Lang +ch.viomi.vacuum.v18-miot.cur-map-id = Viomi Vacuum - Cur Map Id +ch.viomi.vacuum.v18-miot.cur-map-url = Viomi Vacuum - Cur Map Url +ch.viomi.vacuum.v18-miot.cur-voice = Voice - Cur Voice +ch.viomi.vacuum.v18-miot.dnd-enable = Order - Dnd Enable +ch.viomi.vacuum.v18-miot.dnd-end-hour = Order - Dnd End Hour +ch.viomi.vacuum.v18-miot.dnd-end-minute = Order - Dnd End Minute +ch.viomi.vacuum.v18-miot.dnd-start-hour = Order - Dnd Start Hour +ch.viomi.vacuum.v18-miot.dnd-start-minute = Order - Dnd Start Minute +ch.viomi.vacuum.v18-miot.dnd-timezone = Order - Dnd Timezone +ch.viomi.vacuum.v18-miot.door-state = Robot Cleaner - Door State +ch.viomi.vacuum.v18-miot.download-progress = Voice - Download Progress +ch.viomi.vacuum.v18-miot.download-status = Voice - Download Status +ch.viomi.vacuum.v18-miot.dust-collection = Viomi Vacuum - Dust Collection +ch.viomi.vacuum.v18-miot.fault = Robot Cleaner - Device Fault +ch.viomi.vacuum.v18-miot.has-map = Viomi Vacuum - Has Map +ch.viomi.vacuum.v18-miot.has-newmap = Viomi Vacuum - Has Newmap +ch.viomi.vacuum.v18-miot.hypa-hours = Viomi Vacuum - Hypa Hours +ch.viomi.vacuum.v18-miot.hypa-life = Viomi Vacuum - Hypa Life +ch.viomi.vacuum.v18-miot.last-update-time = Viomi Vacuum - Last Update Time +ch.viomi.vacuum.v18-miot.main-brush-hours = Viomi Vacuum - Main Brush Hours +ch.viomi.vacuum.v18-miot.main-brush-life = Viomi Vacuum - Main Brush Life +ch.viomi.vacuum.v18-miot.map-id = Map - Map Id +ch.viomi.vacuum.v18-miot.map-list = Map - Map List +ch.viomi.vacuum.v18-miot.map-name = Map - Map Name +ch.viomi.vacuum.v18-miot.map-num = Viomi Vacuum - Map Num +ch.viomi.vacuum.v18-miot.map-type = Map - Map Type +ch.viomi.vacuum.v18-miot.mode = Robot Cleaner - Mode +ch.viomi.vacuum.v18-miot.mop-hours = Viomi Vacuum - Mop Hours +ch.viomi.vacuum.v18-miot.mop-life = Viomi Vacuum - Mop Life +ch.viomi.vacuum.v18-miot.mop-route = Viomi Vacuum - Mop Route +ch.viomi.vacuum.v18-miot.mute = Robot Cleaner - Mute +ch.viomi.vacuum.v18-miot.oper-result = Map - Oper Result +ch.viomi.vacuum.v18-miot.orderdata = Order - Orderdata +ch.viomi.vacuum.v18-miot.remember-state = Viomi Vacuum - Remember State +ch.viomi.vacuum.v18-miot.repeat-state = Viomi Vacuum - Repeat State +ch.viomi.vacuum.v18-miot.side-brush-hours = Viomi Vacuum - Side Brush Hours +ch.viomi.vacuum.v18-miot.side-brush-life = Viomi Vacuum - Side Brush Life +ch.viomi.vacuum.v18-miot.status = Robot Cleaner - Status +ch.viomi.vacuum.v18-miot.suction-grade = Viomi Vacuum - Suction Grade +ch.viomi.vacuum.v18-miot.sweep-type = Robot Cleaner - Sweep Type +ch.viomi.vacuum.v18-miot.target-point = Point Zone - Target Point +ch.viomi.vacuum.v18-miot.target-voice = Voice - Target Voice +ch.viomi.vacuum.v18-miot.time-zone = Viomi Vacuum - Time Zone +ch.viomi.vacuum.v18-miot.timestamp = Order - Timestamp +ch.viomi.vacuum.v18-miot.vacuumaction = Vacuum Action +ch.viomi.vacuum.v18-miot.water-grade = Viomi Vacuum - Water Grade +ch.viomi.vacuum.v18-miot.wdr-mode = Robot Cleaner - Wide Dynamic Range Mode +ch.viomi.vacuum.v8.battery_life = Battery +ch.viomi.vacuum.v8.box_type = Box type +ch.viomi.vacuum.v8.err_state = Error +ch.viomi.vacuum.v8.has_map = has_map +ch.viomi.vacuum.v8.has_newmap = has_newmap +ch.viomi.vacuum.v8.is_mop = is_mop +ch.viomi.vacuum.v8.mode = Mode +ch.viomi.vacuum.v8.mop_type = mop_type +ch.viomi.vacuum.v8.remember_map = remember_map +ch.viomi.vacuum.v8.s_area = Clean Area +ch.viomi.vacuum.v8.s_time = Clean time +ch.viomi.vacuum.v8.state = State +ch.viomi.vacuum.v8.suction_grade = suction_grade +ch.viomi.vacuum.v8.vacuumaction = Vacuum Action +ch.viomi.vacuum.v8.water_grade = water_grade +ch.viomi.waterheater.e1.appointEnd = Appoint End +ch.viomi.waterheater.e1.appointStart = Appoint Start +ch.viomi.waterheater.e1.errStatus = Error Status +ch.viomi.waterheater.e1.hotWater = Hot Water +ch.viomi.waterheater.e1.modeType = Mode +ch.viomi.waterheater.e1.needClean = Need Clean +ch.viomi.waterheater.e1.targetTemp = Target Temperature +ch.viomi.waterheater.e1.velocity = Velocity +ch.viomi.waterheater.e1.washStatus = Wash Status +ch.viomi.waterheater.e1.waterTemp = Water Temperature +ch.xiaomi.aircondition.ma1-miot.alarm = Alarm - Alarm +ch.xiaomi.aircondition.ma1-miot.dryer = Air Conditioner - Dryer +ch.xiaomi.aircondition.ma1-miot.eco = Air Conditioner - Eco +ch.xiaomi.aircondition.ma1-miot.fan-level = Fan Control - Fan Level +ch.xiaomi.aircondition.ma1-miot.heater = Air Conditioner - Heater +ch.xiaomi.aircondition.ma1-miot.mode = Air Conditioner - Mode +ch.xiaomi.aircondition.ma1-miot.on = Power +ch.xiaomi.aircondition.ma1-miot.on1 = Indicator Light - Switch Status +ch.xiaomi.aircondition.ma1-miot.sleep-mode = Air Conditioner - Sleep Mode +ch.xiaomi.aircondition.ma1-miot.target-temperature = Air Conditioner - Target Temperature +ch.xiaomi.aircondition.ma1-miot.temperature = Environment - Temperature +ch.xiaomi.aircondition.ma1-miot.vertical-swing = Fan Control - Vertical Swing +ch.xiaomi.aircondition.mc1-miot.alarm = Alarm - Alarm +ch.xiaomi.aircondition.mc1-miot.clean = Maintenance - Clean +ch.xiaomi.aircondition.mc1-miot.dryer = Air Conditioner - Dryer +ch.xiaomi.aircondition.mc1-miot.eco = Air Conditioner - Eco +ch.xiaomi.aircondition.mc1-miot.elec-count = Electricity - Count +ch.xiaomi.aircondition.mc1-miot.electricity = Power consumption accumulation in kWh +ch.xiaomi.aircondition.mc1-miot.examine = Maintenance - Examine +ch.xiaomi.aircondition.mc1-miot.fan-level = Fan Control - Fan Level +ch.xiaomi.aircondition.mc1-miot.fan-percent = Fan Speed % +ch.xiaomi.aircondition.mc1-miot.heater = Air Conditioner - Heater +ch.xiaomi.aircondition.mc1-miot.mode = Air Conditioner - Mode +ch.xiaomi.aircondition.mc1-miot.on = Power +ch.xiaomi.aircondition.mc1-miot.on1 = Indicator Light - Switch Status +ch.xiaomi.aircondition.mc1-miot.running-duration = Maintenance - Running Duration +ch.xiaomi.aircondition.mc1-miot.sleep-mode = Air Conditioner - Sleep Mode +ch.xiaomi.aircondition.mc1-miot.target-temperature = Air Conditioner - Target Temperature +ch.xiaomi.aircondition.mc1-miot.temperature = Environment - Temperature +ch.xiaomi.aircondition.mc1-miot.timer = Enhance - Timer +ch.xiaomi.aircondition.mc1-miot.vertical-swing = Fan Control - Vertical Swing +ch.xjx.toilet.fan_temp = Fan Temperature +ch.xjx.toilet.seat_temp = Seat Temperature +ch.xjx.toilet.status_led = Night Light +ch.xjx.toilet.status_seatheat = Seat Status +ch.xjx.toilet.water_temp_t = Water Temperature +ch.yeelink.bhf1.bh_mode = Bath Heater mode +ch.yeelink.bhf1.brightness = Brightness +ch.yeelink.bhf1.delayoff = Shutdown Timer +ch.yeelink.bhf1.nightlightBrightness = Nightlight Brightness +ch.yeelink.bhf1.power = Power +ch.yeelink.bhf1.temperature = Temperature +ch.yeelink.light.ceiling.brightness = Brightness +ch.yeelink.light.ceiling.colorMode = Color Mode +ch.yeelink.light.ceiling.colorTemperature = Color Temperature +ch.yeelink.light.ceiling.customScene = Set Scene +ch.yeelink.light.ceiling.delayoff = Shutdown Timer +ch.yeelink.light.ceiling.name = Name +ch.yeelink.light.ceiling.nightlightBrightness = Nightlight Brightness +ch.yeelink.light.ceiling.power = Power +ch.yeelink.light.ceiling2.brightness = Brightness +ch.yeelink.light.ceiling2.colorMode = Color Mode +ch.yeelink.light.ceiling2.colorTemperature = Color Temperature +ch.yeelink.light.ceiling2.customScene = Set Scene +ch.yeelink.light.ceiling2.delayoff = Shutdown Timer +ch.yeelink.light.ceiling2.name = Name +ch.yeelink.light.ceiling2.nightlightBrightness = Nightlight Brightness +ch.yeelink.light.ceiling2.power = Power +ch.yeelink.light.ceiling4.ambientBrightness = Ambient Brightness +ch.yeelink.light.ceiling4.ambientColor = Ambient Color +ch.yeelink.light.ceiling4.ambientColorMode = Ambient Color Mode +ch.yeelink.light.ceiling4.ambientColorTemperature = Ambient Color Temperature +ch.yeelink.light.ceiling4.ambientPower = Ambient Power +ch.yeelink.light.ceiling4.brightness = Brightness +ch.yeelink.light.ceiling4.colorMode = Color Mode +ch.yeelink.light.ceiling4.colorTemperature = Color Temperature +ch.yeelink.light.ceiling4.customScene = Set Scene +ch.yeelink.light.ceiling4.delayoff = Shutdown Timer +ch.yeelink.light.ceiling4.name = Name +ch.yeelink.light.ceiling4.nightlightBrightness = Nightlight Brightness +ch.yeelink.light.ceiling4.power = Power +ch.yeelink.light.color1.brightness = Brightness +ch.yeelink.light.color1.colorMode = Color Mode +ch.yeelink.light.color1.colorTemperature = Color Temperature +ch.yeelink.light.color1.colorflow = Color Flow +ch.yeelink.light.color1.delayoff = Shutdown Timer +ch.yeelink.light.color1.name = Name +ch.yeelink.light.color1.power = Power +ch.yeelink.light.color1.rgbColor = RGB Color +ch.yeelink.light.lamp1.brightness = Brightness +ch.yeelink.light.lamp1.colorMode = Color Mode +ch.yeelink.light.lamp1.colorTemperature = Color Temperature +ch.yeelink.light.lamp1.delayoff = Shutdown Timer +ch.yeelink.light.lamp1.name = Name +ch.yeelink.light.lamp1.power = Power +ch.yeelink.light.light15.ambientBrightness = Ambient Brightness +ch.yeelink.light.light15.ambientColor = Ambient Color +ch.yeelink.light.light15.ambientColorMode = Ambient Color Mode +ch.yeelink.light.light15.ambientColorTemperature = Ambient Color Temperature +ch.yeelink.light.light15.ambientPower = Ambient Power +ch.yeelink.light.light15.brightness = Brightness +ch.yeelink.light.light15.colorMode = Color Mode +ch.yeelink.light.light15.colorTemperature = Color Temperature +ch.yeelink.light.light15.delayoff = Shutdown Timer +ch.yeelink.light.light15.power = Power +ch.yeelink.light.light15.rgbColor = RGB Color +ch.yeelink.switch.sw1-miot.flash = Extension - Flash +ch.yeelink.switch.sw1-miot.interlock = Extension - Interlock +ch.yeelink.switch.sw1-miot.mode = First Switch Default - Mode +ch.yeelink.switch.sw1-miot.mode1 = First Switch - Delay +ch.yeelink.switch.sw1-miot.mode2 = Second Switch Default - Mode +ch.yeelink.switch.sw1-miot.mode3 = Second Switch Service - Delay +ch.yeelink.switch.sw1-miot.on = First Switch - Switch Status +ch.yeelink.switch.sw1-miot.on1 = Second Switch - Switch Status +ch.yeelink.switch.sw1-miot.rc-list = Extension - Rc List +ch.yunmi.waterpurifier.f1_totalflow = Filter 1 Total Flow +ch.yunmi.waterpurifier.f1_totaltime = Filter 1 Total Time +ch.yunmi.waterpurifier.f1_usedflow = Filter 1 Used Flow +ch.yunmi.waterpurifier.f1_usedtime = Filter 1 Used Time +ch.yunmi.waterpurifier.f2_totalflow = Filter 2 Total Flow +ch.yunmi.waterpurifier.f2_totaltime = Filter 2 Total Time +ch.yunmi.waterpurifier.f2_usedflow = Filter 2 Used Flow +ch.yunmi.waterpurifier.f2_usedtime = Filter 2 Used Time +ch.yunmi.waterpurifier.f3_totalflow = Filter 3 Total Flow +ch.yunmi.waterpurifier.f3_totaltime = Filter 3 Total Time +ch.yunmi.waterpurifier.f3_usedflow = Filter 3 Used Flow +ch.yunmi.waterpurifier.f3_usedtime = Filter 3 Used Time +ch.yunmi.waterpurifier.f4_totalflow = Filter 4 Total Flow +ch.yunmi.waterpurifier.f4_totaltime = Filter 4 Total Time +ch.yunmi.waterpurifier.f4_usedflow = Filter 4 Used Flow +ch.yunmi.waterpurifier.f4_usedtime = Filter 4 Used Time +ch.yunmi.waterpurifier.lightMode = Light Mode +ch.yunmi.waterpurifier.lx8.f1_totalflow = Filter 1 Total Flow +ch.yunmi.waterpurifier.lx8.f1_totaltime = Filter 1 Total Time +ch.yunmi.waterpurifier.lx8.f1_usedflow = Filter 1 Used Flow +ch.yunmi.waterpurifier.lx8.f1_usedtime = Filter 1 Used Time +ch.yunmi.waterpurifier.lx8.f2_totalflow = Filter 2 Total Flow +ch.yunmi.waterpurifier.lx8.f2_totaltime = Filter 2 Total Time +ch.yunmi.waterpurifier.lx8.f2_usedflow = Filter 2 Used Flow +ch.yunmi.waterpurifier.lx8.f2_usedtime = Filter 2 Used Time +ch.yunmi.waterpurifier.lx8.f3_totalflow = Filter 3 Total Flow +ch.yunmi.waterpurifier.lx8.f3_totaltime = Filter 3 Total Time +ch.yunmi.waterpurifier.lx8.f3_usedflow = Filter 3 Used Flow +ch.yunmi.waterpurifier.lx8.f3_usedtime = Filter 3 Used Time +ch.yunmi.waterpurifier.lx8.f4_totalflow = Filter 4 Total Flow +ch.yunmi.waterpurifier.lx8.f4_totaltime = Filter 4 Total Time +ch.yunmi.waterpurifier.lx8.f4_usedflow = Filter 4 Used Flow +ch.yunmi.waterpurifier.lx8.f4_usedtime = Filter 4 Used Time +ch.yunmi.waterpurifier.lx8.lightMode = Light Mode +ch.yunmi.waterpurifier.lx8.maintenance_interval = Maintenance Interval +ch.yunmi.waterpurifier.lx8.maintenance_state = Maintenance State +ch.yunmi.waterpurifier.lx8.rinse = Rinse +ch.yunmi.waterpurifier.lx8.run_status = Run Status +ch.yunmi.waterpurifier.lx8.tds_in = TDS in +ch.yunmi.waterpurifier.lx8.tds_out = TDS out +ch.yunmi.waterpurifier.lx8.tds_warn_thd = TDS Warn Threshold +ch.yunmi.waterpurifier.maintenance_interval = Maintenance Interval +ch.yunmi.waterpurifier.maintenance_state = Maintenance State +ch.yunmi.waterpurifier.rinse = Rinse +ch.yunmi.waterpurifier.run_status = Run Status +ch.yunmi.waterpurifier.tds_in = TDS in +ch.yunmi.waterpurifier.tds_out = TDS out +ch.yunmi.waterpurifier.tds_out_avg = Average TDS out +ch.yunmi.waterpurifier.tds_warn_thd = TDS Warn Threshold +ch.yunmi.waterpurifier.temperature = Temperature +ch.zhimi.airfresh.va4.aqi = Air Quality Index +ch.zhimi.airfresh.va4.averageaqi = Average Air Quality Index +ch.zhimi.airfresh.va4.buzzer = Buzzer +ch.zhimi.airfresh.va4.childLock = Child Lock +ch.zhimi.airfresh.va4.co2 = CO2 +ch.zhimi.airfresh.va4.filterhours = Filter Hours used +ch.zhimi.airfresh.va4.heater = Heater +ch.zhimi.airfresh.va4.humidity = Humidity +ch.zhimi.airfresh.va4.led_level = Led - Brightness +ch.zhimi.airfresh.va4.mode = Mode +ch.zhimi.airfresh.va4.motorspeed = Motor Speed +ch.zhimi.airfresh.va4.power = Power +ch.zhimi.airfresh.va4.temperature = Temperature +ch.zhimi.airfresh.va4.usedhours = Run Time +ch.zhimi.airmonitor.v1.aqi = Air Quality Index +ch.zhimi.airmonitor.v1.battery = Battery +ch.zhimi.airmonitor.v1.night_begin = Night Begin Time +ch.zhimi.airmonitor.v1.night_end = Night End Time +ch.zhimi.airmonitor.v1.night_state = Night State +ch.zhimi.airmonitor.v1.power = Power +ch.zhimi.airmonitor.v1.time_state = Time State +ch.zhimi.airmonitor.v1.usb_state = USB State +ch.zhimi.airpurifier.m1.aqi = Air Quality Index +ch.zhimi.airpurifier.m1.averageaqi = Average Air Quality Index +ch.zhimi.airpurifier.m1.buzzer = Buzzer Status +ch.zhimi.airpurifier.m1.childlock = Child Lock +ch.zhimi.airpurifier.m1.favoritelevel = Favorite Level +ch.zhimi.airpurifier.m1.filterhours = Filter Hours used +ch.zhimi.airpurifier.m1.filterlife = Filter Life +ch.zhimi.airpurifier.m1.filtermaxlife = Filter Max Life +ch.zhimi.airpurifier.m1.humidity = Humidity +ch.zhimi.airpurifier.m1.led = LED Status +ch.zhimi.airpurifier.m1.mode = Mode +ch.zhimi.airpurifier.m1.motorspeed = Motor Speed +ch.zhimi.airpurifier.m1.power = Power +ch.zhimi.airpurifier.m1.purifyvolume = Purified Volume +ch.zhimi.airpurifier.m1.temperature = Temperature +ch.zhimi.airpurifier.m1.usedhours = Run Time +ch.zhimi.airpurifier.ma4-miot.alarm = Alarm - Alarm +ch.zhimi.airpurifier.ma4-miot.app-extra = Others - App Extra +ch.zhimi.airpurifier.ma4-miot.aqi-goodh = Aqi - Aqi Goodh +ch.zhimi.airpurifier.ma4-miot.aqi-runstate = Aqi - Aqi Runstate +ch.zhimi.airpurifier.ma4-miot.aqi-state = Aqi - Aqi State +ch.zhimi.airpurifier.ma4-miot.aqi-updata-heartbeat = Aqi - Aqi Updata Heartbeat +ch.zhimi.airpurifier.ma4-miot.aqi-zone = Aqi - Aqi Zone +ch.zhimi.airpurifier.ma4-miot.average-aqi = Aqi - Average Aqi +ch.zhimi.airpurifier.ma4-miot.average-aqi-cnt = Aqi - Average Aqi Cnt +ch.zhimi.airpurifier.ma4-miot.brightness = Indicator Light - Brightness +ch.zhimi.airpurifier.ma4-miot.buttom-door = Others - Buttom Door +ch.zhimi.airpurifier.ma4-miot.button-pressed = Button - Button_pressed +ch.zhimi.airpurifier.ma4-miot.cola = Others - Cola +ch.zhimi.airpurifier.ma4-miot.fan-level = Air Purifier - Fan Level +ch.zhimi.airpurifier.ma4-miot.fault = Air Purifier - Device Fault +ch.zhimi.airpurifier.ma4-miot.favorite-fan-level = Motor Speed - Favorite Fan Level +ch.zhimi.airpurifier.ma4-miot.filter-hour-used-debug = Filter Time - Filter Hour Used Debug +ch.zhimi.airpurifier.ma4-miot.filter-life-level = Filter - Filter Life Level +ch.zhimi.airpurifier.ma4-miot.filter-max-time = Filter Time - Filter Max Time +ch.zhimi.airpurifier.ma4-miot.filter-used-time = Filter - Filter Used Time +ch.zhimi.airpurifier.ma4-miot.hw-version = Others - Hw Version +ch.zhimi.airpurifier.ma4-miot.i2c-error-count = Others - I2c Error Count +ch.zhimi.airpurifier.ma4-miot.m1-favorite = Motor Speed - M1 Favorite +ch.zhimi.airpurifier.ma4-miot.m1-high = Motor Speed - M1 High +ch.zhimi.airpurifier.ma4-miot.m1-low = Motor Speed - M1 Low +ch.zhimi.airpurifier.ma4-miot.m1-med = Motor Speed - M1 Med +ch.zhimi.airpurifier.ma4-miot.m1-med-l = Motor Speed - M1 Med L +ch.zhimi.airpurifier.ma4-miot.m1-silent = Motor Speed - M1 Silent +ch.zhimi.airpurifier.ma4-miot.m1-strong = Motor Speed - M1 Strong +ch.zhimi.airpurifier.ma4-miot.main-channel = Others - Main Channel +ch.zhimi.airpurifier.ma4-miot.manual-level = Others - Manual Level +ch.zhimi.airpurifier.ma4-miot.mode = Air Purifier - Mode +ch.zhimi.airpurifier.ma4-miot.motor1-set-speed = Motor Speed - Motor1 Set Speed +ch.zhimi.airpurifier.ma4-miot.motor1-speed = Motor Speed - Motor1 Speed +ch.zhimi.airpurifier.ma4-miot.on = Air Purifier - Switch Status +ch.zhimi.airpurifier.ma4-miot.on1 = Indicator Light - Switch Status +ch.zhimi.airpurifier.ma4-miot.physical-controls-locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airpurifier.ma4-miot.pm2_5-density = Environment - Pm2.5 Density +ch.zhimi.airpurifier.ma4-miot.purify-volume = Aqi - Purify Volume +ch.zhimi.airpurifier.ma4-miot.reboot-cause = Others - Reboot_cause +ch.zhimi.airpurifier.ma4-miot.relative-humidity = Environment - Relative Humidity +ch.zhimi.airpurifier.ma4-miot.rfid-factory-id = Rfid - Rfid Factory Id +ch.zhimi.airpurifier.ma4-miot.rfid-product-id = Rfid - Rfid Product Id +ch.zhimi.airpurifier.ma4-miot.rfid-serial-num = Rfid - Rfid Serial Num +ch.zhimi.airpurifier.ma4-miot.rfid-tag = Rfid - Rfid Tag +ch.zhimi.airpurifier.ma4-miot.rfid-time = Rfid - Rfid Time +ch.zhimi.airpurifier.ma4-miot.sensor-state = Aqi - Sensor State +ch.zhimi.airpurifier.ma4-miot.slave-channel = Others - Slave Channel +ch.zhimi.airpurifier.ma4-miot.temperature = Environment - Temperature +ch.zhimi.airpurifier.ma4-miot.use-time = Use Time - Use Time +ch.zhimi.airpurifier.mb3-miot.alarm = Alarm - Alarm +ch.zhimi.airpurifier.mb3-miot.app-extra = Others - App Extra +ch.zhimi.airpurifier.mb3-miot.aqi-goodh = Aqi - Aqi Goodh +ch.zhimi.airpurifier.mb3-miot.aqi-runstate = Aqi - Aqi Runstate +ch.zhimi.airpurifier.mb3-miot.aqi-state = Aqi - Aqi State +ch.zhimi.airpurifier.mb3-miot.aqi-updata-heartbeat = Aqi - Aqi Updata Heartbeat +ch.zhimi.airpurifier.mb3-miot.aqi-zone = Aqi - Aqi Zone +ch.zhimi.airpurifier.mb3-miot.average-aqi = Aqi - Average Aqi +ch.zhimi.airpurifier.mb3-miot.average-aqi-cnt = Aqi - Average Aqi Cnt +ch.zhimi.airpurifier.mb3-miot.brightness = Indicator Light - Brightness +ch.zhimi.airpurifier.mb3-miot.buttom-door = Others - Buttom Door +ch.zhimi.airpurifier.mb3-miot.button-pressed = Button - Button Pressed +ch.zhimi.airpurifier.mb3-miot.cola = Others - Cola +ch.zhimi.airpurifier.mb3-miot.country-code = Others - National Code +ch.zhimi.airpurifier.mb3-miot.fan-level = Air Purifier - Fan Level +ch.zhimi.airpurifier.mb3-miot.fault = Air Purifier - Fault +ch.zhimi.airpurifier.mb3-miot.favorite-fan-level = Motor Speed - Favorite Fan Level +ch.zhimi.airpurifier.mb3-miot.filter-hour-debug = Filter Time - Filter Hour Debug +ch.zhimi.airpurifier.mb3-miot.filter-life-level = Filter - Filter Life Level +ch.zhimi.airpurifier.mb3-miot.filter-max-time = Filter Time - Filter Max Time +ch.zhimi.airpurifier.mb3-miot.filter-used-time = Filter - Filter Used Time +ch.zhimi.airpurifier.mb3-miot.hw-version = Others - Hw Version +ch.zhimi.airpurifier.mb3-miot.iic-error-count = Others - Iic Error Count +ch.zhimi.airpurifier.mb3-miot.main-channel = Others - Main Channel +ch.zhimi.airpurifier.mb3-miot.manual-level = Others - Manual Level +ch.zhimi.airpurifier.mb3-miot.mode = Air Purifier - Mode +ch.zhimi.airpurifier.mb3-miot.motor-favorite = Motor Speed - Motor Favorite +ch.zhimi.airpurifier.mb3-miot.motor-high = Motor Speed - Motor High +ch.zhimi.airpurifier.mb3-miot.motor-low = Motor Speed - Motor Low +ch.zhimi.airpurifier.mb3-miot.motor-med = Motor Speed - Motor Med +ch.zhimi.airpurifier.mb3-miot.motor-med-l = Motor Speed - Motor Med L +ch.zhimi.airpurifier.mb3-miot.motor-set-speed = Motor Speed - Motor Set Speed +ch.zhimi.airpurifier.mb3-miot.motor-silent = Motor Speed - Motor Silent +ch.zhimi.airpurifier.mb3-miot.motor-speed = Motor Speed - Motor Speed +ch.zhimi.airpurifier.mb3-miot.motor-strong = Motor Speed - Motor Strong +ch.zhimi.airpurifier.mb3-miot.on = Air Purifier - Switch Status +ch.zhimi.airpurifier.mb3-miot.on1 = Indicator Light - Switch Status +ch.zhimi.airpurifier.mb3-miot.physical-controls-locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airpurifier.mb3-miot.pm2_5-density = Environment - Pm2.5 density +ch.zhimi.airpurifier.mb3-miot.purify-volume = Aqi - Purify Volume +ch.zhimi.airpurifier.mb3-miot.reboot-cause = Others - Reboot Cause +ch.zhimi.airpurifier.mb3-miot.relative-humidity = Environment - Relative Humidity +ch.zhimi.airpurifier.mb3-miot.rfid-factory-id = Rfid - Rfid Factory Id +ch.zhimi.airpurifier.mb3-miot.rfid-product-id = Rfid - Rfid Product Id +ch.zhimi.airpurifier.mb3-miot.rfid-serial-num = Rfid - Rfid Serial Num +ch.zhimi.airpurifier.mb3-miot.rfid-tag = Rfid - Rfid Tag +ch.zhimi.airpurifier.mb3-miot.rfid-time = Rfid - Rfid Time +ch.zhimi.airpurifier.mb3-miot.sensor-state = Aqi - Sensor State +ch.zhimi.airpurifier.mb3-miot.slave-channel = Others - Slave Channel +ch.zhimi.airpurifier.mb3-miot.temperature = Environment - Temperature +ch.zhimi.airpurifier.mb3-miot.use-time = Use Time - Use Time +ch.zhimi.airpurifier.mb4-miot.alarm = Alarm - Alarm +ch.zhimi.airpurifier.mb4-miot.aqi_updata_heartbeat = Custom Service - Aqi Updata Heartbeat +ch.zhimi.airpurifier.mb4-miot.brightness = Screen - Brightness +ch.zhimi.airpurifier.mb4-miot.fault = Air Purifier - Device Fault +ch.zhimi.airpurifier.mb4-miot.favorite_speed = Custom Service - Favorite Speed +ch.zhimi.airpurifier.mb4-miot.filter_life_level = Filter - Filter Life Level +ch.zhimi.airpurifier.mb4-miot.filter_used_time = Filter - Filter Used Time +ch.zhimi.airpurifier.mb4-miot.miio_lib_version = Custom Service - Miio Lib Version +ch.zhimi.airpurifier.mb4-miot.mode = Mode +ch.zhimi.airpurifier.mb4-miot.moto_speed_rpm = Custom Service - Moto Speed Rpm +ch.zhimi.airpurifier.mb4-miot.on = Power +ch.zhimi.airpurifier.mb4-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airpurifier.mb4-miot.pm2_5_density = Environment - Pm2 5 Density +ch.zhimi.airpurifier.v1.act_det = Air AutoDetect +ch.zhimi.airpurifier.v1.aqi = Air Quality Index +ch.zhimi.airpurifier.v1.brightness = Brightness +ch.zhimi.airpurifier.v1.buzzer = Buzzer Status +ch.zhimi.airpurifier.v1.filterlive = Filter Life +ch.zhimi.airpurifier.v1.filtermaxlife = Filter Max Life +ch.zhimi.airpurifier.v1.humidity = Humidity +ch.zhimi.airpurifier.v1.led = LED Status +ch.zhimi.airpurifier.v1.mode = Mode +ch.zhimi.airpurifier.v1.power = Power +ch.zhimi.airpurifier.v6.aqi = Air Quality Index +ch.zhimi.airpurifier.v6.averageaqi = Average Air Quality Index +ch.zhimi.airpurifier.v6.bright = LED Brightness +ch.zhimi.airpurifier.v6.childlock = Child Lock +ch.zhimi.airpurifier.v6.favoritelevel = Favorite Level +ch.zhimi.airpurifier.v6.filterhours = Filter Hours used +ch.zhimi.airpurifier.v6.filterlife = Filter Life +ch.zhimi.airpurifier.v6.filtermaxlife = Filter Max Life +ch.zhimi.airpurifier.v6.humidity = Humidity +ch.zhimi.airpurifier.v6.led = LED Status +ch.zhimi.airpurifier.v6.mode = Mode +ch.zhimi.airpurifier.v6.motorspeed = Motor Speed +ch.zhimi.airpurifier.v6.power = Power +ch.zhimi.airpurifier.v6.purifyvolume = Purivied Volume +ch.zhimi.airpurifier.v6.temperature = Temperature +ch.zhimi.airpurifier.v6.usedhours = Run Time +ch.zhimi.airpurifier.v7.aqi = Air Quality Index +ch.zhimi.airpurifier.v7.averageaqi = Average Air Quality Index +ch.zhimi.airpurifier.v7.childlock = Child Lock +ch.zhimi.airpurifier.v7.favoritelevel = Favorite Level +ch.zhimi.airpurifier.v7.filterhours = Filter Hours used +ch.zhimi.airpurifier.v7.filterlife = Filter Life +ch.zhimi.airpurifier.v7.filtermaxlife = Filter Max Life +ch.zhimi.airpurifier.v7.humidity = Humidity +ch.zhimi.airpurifier.v7.illuminance = Illuminance +ch.zhimi.airpurifier.v7.led = LED Status +ch.zhimi.airpurifier.v7.mode = Mode +ch.zhimi.airpurifier.v7.motorspeed = Motor Speed +ch.zhimi.airpurifier.v7.motorspeed2 = Motor Speed 2 +ch.zhimi.airpurifier.v7.power = Power +ch.zhimi.airpurifier.v7.temperature = Temperature +ch.zhimi.airpurifier.v7.volume = Volume +ch.zhimi.airpurifier.vb2-miot.actions = Actions +ch.zhimi.airpurifier.vb2-miot.alarm = Alarm - Alarm +ch.zhimi.airpurifier.vb2-miot.app_extra = Others - App Extra +ch.zhimi.airpurifier.vb2-miot.aqi_goodh = Aqi - Aqi Goodh +ch.zhimi.airpurifier.vb2-miot.aqi_runstate = Aqi - Runstate +ch.zhimi.airpurifier.vb2-miot.aqi_state = Aqi - Aqi State +ch.zhimi.airpurifier.vb2-miot.aqi_zone = Aqi - Aqi Zone +ch.zhimi.airpurifier.vb2-miot.average_aqi = Aqi - Average Aqi +ch.zhimi.airpurifier.vb2-miot.average_aqi_cnt = Aqi - Average_aqi Read Times +ch.zhimi.airpurifier.vb2-miot.brightness = Indicator Light - Brightness +ch.zhimi.airpurifier.vb2-miot.buttom_door = Others - Buttom Door +ch.zhimi.airpurifier.vb2-miot.button_pressed = Button - Button_pressed +ch.zhimi.airpurifier.vb2-miot.cola = Others - Cola +ch.zhimi.airpurifier.vb2-miot.country_code = Others - Country Code +ch.zhimi.airpurifier.vb2-miot.fan_level = Air Purifier - Fan Level +ch.zhimi.airpurifier.vb2-miot.fault = Air Purifier - Device Fault +ch.zhimi.airpurifier.vb2-miot.favorite_level = Motor Speed - Favorite Level +ch.zhimi.airpurifier.vb2-miot.filter_hour_used_debug = Filter Time - Filter Hour Used Debug +ch.zhimi.airpurifier.vb2-miot.filter_life_level = Filter - Filter Life Level +ch.zhimi.airpurifier.vb2-miot.filter_max_time = Filter Time - Filter Max Time +ch.zhimi.airpurifier.vb2-miot.filter_used_time = Filter - Filter Used Time +ch.zhimi.airpurifier.vb2-miot.m1_favorite = Motor Speed - M1 Favorite +ch.zhimi.airpurifier.vb2-miot.m1_high = Motor Speed - M1 High +ch.zhimi.airpurifier.vb2-miot.m1_low = Motor Speed - M1 Low +ch.zhimi.airpurifier.vb2-miot.m1_med = Motor Speed - M1 Med +ch.zhimi.airpurifier.vb2-miot.m1_med_l = Motor Speed - M1 Med L +ch.zhimi.airpurifier.vb2-miot.m1_silent = Motor Speed - M1 Silent +ch.zhimi.airpurifier.vb2-miot.m1_strong = Motor Speed - M1 Strong +ch.zhimi.airpurifier.vb2-miot.main_channel = Others - Main Channel +ch.zhimi.airpurifier.vb2-miot.manual_level = Others - Manual Level +ch.zhimi.airpurifier.vb2-miot.mode = Air Purifier - Mode +ch.zhimi.airpurifier.vb2-miot.motor1_set_speed = Motor Speed - Motor1 Set Speed +ch.zhimi.airpurifier.vb2-miot.motor1_speed = Motor Speed - Motor1 Speed +ch.zhimi.airpurifier.vb2-miot.on = Air Purifier - Power +ch.zhimi.airpurifier.vb2-miot.on1 = Indicator Light - Switch Status +ch.zhimi.airpurifier.vb2-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airpurifier.vb2-miot.pm2_5_density = Environment - PM2 5 Density +ch.zhimi.airpurifier.vb2-miot.powertime = Others - Powertime +ch.zhimi.airpurifier.vb2-miot.purify_volume = Aqi - Purify Volume +ch.zhimi.airpurifier.vb2-miot.reboot_cause = Others - Reboot_cause +ch.zhimi.airpurifier.vb2-miot.relative_humidity = Environment - Relative Humidity +ch.zhimi.airpurifier.vb2-miot.rfid_factory_id = Rfid - Rfid Factory Id +ch.zhimi.airpurifier.vb2-miot.rfid_product_id = Rfid - Rfid Product Id +ch.zhimi.airpurifier.vb2-miot.rfid_serial_num = Rfid - Rfid Serial Num +ch.zhimi.airpurifier.vb2-miot.rfid_tag = Rfid - Rfid Tag +ch.zhimi.airpurifier.vb2-miot.rfid_time = Rfid - Rfid Time +ch.zhimi.airpurifier.vb2-miot.sensor_state = Aqi - Sensor State +ch.zhimi.airpurifier.vb2-miot.slave_channel = Others - Slave Channel +ch.zhimi.airpurifier.vb2-miot.temperature = Environment - Temperature +ch.zhimi.airpurifier.vb2-miot.use_time = Use Time - Use Time +ch.zhimi.airpurifier.vb2-miot.volume = Alarm - Volume +ch.zhimi.airpurifier.za1-miot.air_quality = Environment - Air Quality +ch.zhimi.airpurifier.za1-miot.alarm = Alarm - Alarm +ch.zhimi.airpurifier.za1-miot.aqi_zone = Aqi - Aqi Zone +ch.zhimi.airpurifier.za1-miot.average_aqi = Aqi - Average Aqi +ch.zhimi.airpurifier.za1-miot.brightness = Indicator Light - Brightness +ch.zhimi.airpurifier.za1-miot.country_code = Others - Country Code +ch.zhimi.airpurifier.za1-miot.fault = Air Purifier - Fault +ch.zhimi.airpurifier.za1-miot.favorite_fan_level = Motor Speed - Favorite Fan Level +ch.zhimi.airpurifier.za1-miot.filter_life_level = Filter - Filter Life Level +ch.zhimi.airpurifier.za1-miot.filter_max_time = Filter Time - Filter Max Time +ch.zhimi.airpurifier.za1-miot.filter_used_time = Filter - Filter Used Time +ch.zhimi.airpurifier.za1-miot.gesture_status = Others - Gesture Status +ch.zhimi.airpurifier.za1-miot.hw_version = Others - Hw Version +ch.zhimi.airpurifier.za1-miot.mode = Air Purifier - Mode +ch.zhimi.airpurifier.za1-miot.motor_speed = Motor Speed - Motor Speed +ch.zhimi.airpurifier.za1-miot.on = Air Purifier - Switch Status +ch.zhimi.airpurifier.za1-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airpurifier.za1-miot.pm2_5_density = Environment - PM2 5 Density +ch.zhimi.airpurifier.za1-miot.purify_volume = Aqi - Purify Volume +ch.zhimi.airpurifier.za1-miot.reboot_cause = Others - Reboot Cause +ch.zhimi.airpurifier.za1-miot.relative_humidity = Environment - Relative Humidity +ch.zhimi.airpurifier.za1-miot.rfid_factory_id = Rfid - Rfid Factory Id +ch.zhimi.airpurifier.za1-miot.rfid_product_id = Rfid - Rfid Product Id +ch.zhimi.airpurifier.za1-miot.rfid_serial_num = Rfid - Rfid Serial Num +ch.zhimi.airpurifier.za1-miot.rfid_tag = Rfid - Rfid Tag +ch.zhimi.airpurifier.za1-miot.rfid_time = Rfid - Rfid Time +ch.zhimi.airpurifier.za1-miot.sensor_state = Aqi - Sensor State +ch.zhimi.airpurifier.za1-miot.sgp_ethanol = Others - Sgp Ethanol +ch.zhimi.airpurifier.za1-miot.sgp_serial = Others - Sgp Serial +ch.zhimi.airpurifier.za1-miot.sgp_version = Others - Sgp Version +ch.zhimi.airpurifier.za1-miot.temperature = Environment - Temperature +ch.zhimi.airpurifier.za1-miot.use_time = Use Time - Use Time +ch.zhimi.fan.sa1.acPower = AC Power +ch.zhimi.fan.sa1.angle = Angle +ch.zhimi.fan.sa1.angleEnable = Rotation +ch.zhimi.fan.sa1.buzzer = Buzzer +ch.zhimi.fan.sa1.child_lock = Child Lock +ch.zhimi.fan.sa1.led_b = LED +ch.zhimi.fan.sa1.move = Move Direction +ch.zhimi.fan.sa1.naturalLevel = Natural Level +ch.zhimi.fan.sa1.power = Power +ch.zhimi.fan.sa1.poweroffTime = Power-Off Timer +ch.zhimi.fan.sa1.speed = Speed +ch.zhimi.fan.sa1.speedLevel = Speed Level +ch.zhimi.fan.sa1.usedhours = Run Time +ch.zhimi.fan.v3.acPower = AC Power +ch.zhimi.fan.v3.angle = Angle +ch.zhimi.fan.v3.angleEnable = Rotation +ch.zhimi.fan.v3.battery = Battery +ch.zhimi.fan.v3.buzzer = Buzzer +ch.zhimi.fan.v3.child_lock = Child Lock +ch.zhimi.fan.v3.humidity = Humidity +ch.zhimi.fan.v3.led_b = LED +ch.zhimi.fan.v3.mode = Battery Charge +ch.zhimi.fan.v3.move = Move Direction +ch.zhimi.fan.v3.naturalLevel = Natural Level +ch.zhimi.fan.v3.power = Power +ch.zhimi.fan.v3.poweroffTime = Power-Off Timer +ch.zhimi.fan.v3.speed = Speed +ch.zhimi.fan.v3.speedLevel = Speed Level +ch.zhimi.fan.v3.temp_dec = Temperature +ch.zhimi.fan.v3.usedhours = Run Time +ch.zhimi.fan.za4.angle = Angle +ch.zhimi.fan.za4.angleEnable = Rotation +ch.zhimi.fan.za4.buzzer = Buzzer +ch.zhimi.fan.za4.child_lock = Child Lock +ch.zhimi.fan.za4.led_b = LED +ch.zhimi.fan.za4.move = Move Direction +ch.zhimi.fan.za4.naturalLevel = Natural Level +ch.zhimi.fan.za4.power = Power +ch.zhimi.fan.za4.poweroffTime = Timer +ch.zhimi.fan.za4.speed = Speed +ch.zhimi.fan.za4.speedLevel = Speed Level +ch.zhimi.fan.za4.usedhours = Run Time +ch.zhimi.fan.za5-miot.ac_state = Custom Service - Ac State +ch.zhimi.fan.za5-miot.alarm = Alarm - Alarm +ch.zhimi.fan.za5-miot.anion = Fan - Anion +ch.zhimi.fan.za5-miot.battery_state = Custom Service - Battery State +ch.zhimi.fan.za5-miot.brightness = Indicator Light - Brightness +ch.zhimi.fan.za5-miot.button_press = Custom Service - Button Press +ch.zhimi.fan.za5-miot.fan_level = Fan - Fan Level +ch.zhimi.fan.za5-miot.horizontal_angle = Fan - Horizontal Angle +ch.zhimi.fan.za5-miot.horizontal_swing = Fan - Horizontal Swing +ch.zhimi.fan.za5-miot.mode = Fan - Mode +ch.zhimi.fan.za5-miot.off_delay = Fan - Power Off Delay +ch.zhimi.fan.za5-miot.on = Fan - Power +ch.zhimi.fan.za5-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.fan.za5-miot.relative_humidity = Environment - Relative Humidity +ch.zhimi.fan.za5-miot.speed_level = Custom Service - Speed Level +ch.zhimi.fan.za5-miot.speed_now = Custom Service - Speed Now +ch.zhimi.fan.za5-miot.temperature = Environment - Temperature +ch.zhimi.heater.ma2-miot.alarm = Alarm - Alarm +ch.zhimi.heater.ma2-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.ma2-miot.countdown_time = Countdown - Countdown Time +ch.zhimi.heater.ma2-miot.fault = Heater - Fault +ch.zhimi.heater.ma2-miot.hw_enable = Private Service - Hw Enable +ch.zhimi.heater.ma2-miot.on = Heater - Switch Status +ch.zhimi.heater.ma2-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.heater.ma2-miot.target_temperature = Heater - Target Temperature +ch.zhimi.heater.ma2-miot.temperature = Environment - Temperature +ch.zhimi.heater.ma2-miot.use_time = Private Service - Use Time +ch.zhimi.heater.ma3-miot.actions = Actions +ch.zhimi.heater.ma3-miot.alarm = Alarm - Alarm +ch.zhimi.heater.ma3-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.ma3-miot.countdown_time = Countdown - Countdown Time +ch.zhimi.heater.ma3-miot.fault = Heater - Fault +ch.zhimi.heater.ma3-miot.mode = Heater - Mode +ch.zhimi.heater.ma3-miot.on = Heater - Switch Status +ch.zhimi.heater.ma3-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.heater.ma3-miot.target_temperature = Heater - Target Temperature +ch.zhimi.heater.ma3-miot.temperature = Environment - Temperature +ch.zhimi.heater.ma3-miot.use_time = Private Service - Use Time +ch.zhimi.heater.mc2-miot.alarm = Alarm - Alarm +ch.zhimi.heater.mc2-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.mc2-miot.countdown_time = Countdown - Countdown Time +ch.zhimi.heater.mc2-miot.country_code = Private Service - Country Code +ch.zhimi.heater.mc2-miot.fault = Heater - Device Fault +ch.zhimi.heater.mc2-miot.hw_enable = Private Service - Hw Enable +ch.zhimi.heater.mc2-miot.on = Heater - Power +ch.zhimi.heater.mc2-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.heater.mc2-miot.target_temperature = Heater - Target Temperature +ch.zhimi.heater.mc2-miot.temperature = Environment - Temperature +ch.zhimi.heater.mc2-miot.use_time = Private Service - Use Time +ch.zhimi.heater.na1-miot.alarm = Alarm - Alarm +ch.zhimi.heater.na1-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.na1-miot.countdown_time = Countdown - Countdown Time +ch.zhimi.heater.na1-miot.fault = Heater - Device Fault +ch.zhimi.heater.na1-miot.heat_level = Heater - Heat Level +ch.zhimi.heater.na1-miot.mode = Heater - Mode +ch.zhimi.heater.na1-miot.on = Heater - Power +ch.zhimi.heater.na1-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.heater.na1-miot.return_to_middle = Private Service - Return To Middle +ch.zhimi.heater.nb1-miot.alarm = Alarm - Alarm +ch.zhimi.heater.nb1-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.nb1-miot.countdown_time = Countdown - Countdown Time +ch.zhimi.heater.nb1-miot.country_code = Private Service - Country Code +ch.zhimi.heater.nb1-miot.fault = Heater - Device Fault +ch.zhimi.heater.nb1-miot.heat_level = Heater - Heat Level +ch.zhimi.heater.nb1-miot.hw_en = Private Service - Hw En +ch.zhimi.heater.nb1-miot.mode = Heater - Mode +ch.zhimi.heater.nb1-miot.on = Heater - Power +ch.zhimi.heater.nb1-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.heater.nb1-miot.return_to_middle = Private Service - Return To Middle +ch.zhimi.heater.nb1-miot.target_temperature = Heater - Target Temperature +ch.zhimi.heater.nb1-miot.temperature = Environment - Temperature +ch.zhimi.heater.za1.HWSwitch = HW Switch +ch.zhimi.heater.za1.brightness = Brightness +ch.zhimi.heater.za1.buzzer = Buzzer Status +ch.zhimi.heater.za1.childlock = Child Lock +ch.zhimi.heater.za1.power = Power +ch.zhimi.heater.za1.relative_humidity = Relative Humidity +ch.zhimi.heater.za1.target_temperature = Target Temperature +ch.zhimi.heater.za1.temperature = Temperature +ch.zhimi.heater.za1.usedhours = Run Time +ch.zhimi.heater.za2-miot.alarm = Alarm - Alarm +ch.zhimi.heater.za2-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.za2-miot.countdown-time = Countdown - Countdown Time +ch.zhimi.heater.za2-miot.fault = Heater - Device Fault +ch.zhimi.heater.za2-miot.on = Heater - Power +ch.zhimi.heater.za2-miot.physical-controls-locked = Physical Control Locked - Physical Controls Locked +ch.zhimi.heater.za2-miot.relative-humidity = Environment - Relative Humidity +ch.zhimi.heater.za2-miot.target-temperature = Heater - Target Temperature +ch.zhimi.heater.za2-miot.temperature = Environment - Temperature +ch.zhimi.heater.za2-miot.use-time = Private-Service - Use Time +ch.zhimi.heater.zb1-miot.alarm = Alarm - Alarm +ch.zhimi.heater.zb1-miot.brightness = Indicator Light - Brightness +ch.zhimi.heater.zb1-miot.countdown-time = Countdown - Countdown Time +ch.zhimi.heater.zb1-miot.country-code = Private-Service - Country-Code +ch.zhimi.heater.zb1-miot.fault = Heater - Device Fault +ch.zhimi.heater.zb1-miot.on = Heater - Power +ch.zhimi.heater.zb1-miot.physical-controls-locked = Physical Control Locked - Physical Controls Locked +ch.zhimi.heater.zb1-miot.relative-humidity = Environment - Relative Humidity +ch.zhimi.heater.zb1-miot.target-temperature = Heater - Target Temperature +ch.zhimi.heater.zb1-miot.temperature = Environment - Temperature +ch.zhimi.heater.zb1-miot.use-time = Private-Service - Use Time +ch.zhimi.humidifier.ca4.ButtonPressed = Button Pressed +ch.zhimi.humidifier.ca4.Fault = Humidifier Device Fault +ch.zhimi.humidifier.ca4.actualmotorspeed = Actual Motor Speed +ch.zhimi.humidifier.ca4.bright = LED Brightness +ch.zhimi.humidifier.ca4.buzzer = Buzzer Status +ch.zhimi.humidifier.ca4.childlock = Child Lock +ch.zhimi.humidifier.ca4.clean = Clean Mode +ch.zhimi.humidifier.ca4.dry = Dry +ch.zhimi.humidifier.ca4.humidity = Humidity +ch.zhimi.humidifier.ca4.mode = Mode - Fan Level +ch.zhimi.humidifier.ca4.power = Power +ch.zhimi.humidifier.ca4.powerhours = Power Time +ch.zhimi.humidifier.ca4.targetHumidity = Target Humidity +ch.zhimi.humidifier.ca4.targetmotorspeed = Target Motor Speed +ch.zhimi.humidifier.ca4.temperature = Temperature +ch.zhimi.humidifier.ca4.usedhours = Run Time +ch.zhimi.humidifier.ca4.waterlevel = Water Level +ch.zhimi.humidifier.cb1.bright = LED Brightness +ch.zhimi.humidifier.cb1.buzzer = Buzzer Status +ch.zhimi.humidifier.cb1.childlock = Child Lock +ch.zhimi.humidifier.cb1.depth = Depth +ch.zhimi.humidifier.cb1.dry = Dry +ch.zhimi.humidifier.cb1.humidifierMode = Humidifier Mode +ch.zhimi.humidifier.cb1.humidity = Humidity +ch.zhimi.humidifier.cb1.motorspeed = Motor Speed +ch.zhimi.humidifier.cb1.power = Power +ch.zhimi.humidifier.cb1.setHumidity = Humidity Set +ch.zhimi.humidifier.cb1.temperature = Temperature +ch.zhimi.humidifier.cb1.usedhours = Run Time +ch.zhimi.humidifier.v1.aqi = Air Quality Index +ch.zhimi.humidifier.v1.bright = LED Brightness +ch.zhimi.humidifier.v1.buzzer = Buzzer Status +ch.zhimi.humidifier.v1.childlock = Child Lock +ch.zhimi.humidifier.v1.depth = Depth +ch.zhimi.humidifier.v1.dry = Dry +ch.zhimi.humidifier.v1.humidity = Humidity +ch.zhimi.humidifier.v1.mode = Mode +ch.zhimi.humidifier.v1.motorspeed = Motor Speed +ch.zhimi.humidifier.v1.power = Power +ch.zhimi.humidifier.v1.setHumidity = Humidity Set +ch.zhimi.humidifier.v1.temperature = Temperature +ch.zhimi.humidifier.v1.translevel = Trans_level +ch.zhimi.humidifier.v1.usedhours = Run Time +ch.zimi.powerstrip.v2.current = Current +ch.zimi.powerstrip.v2.led = wifi LED +ch.zimi.powerstrip.v2.lp_autooff = Low Power Auto Off +ch.zimi.powerstrip.v2.lp_autooff_delay = Low Power Limit Time +ch.zimi.powerstrip.v2.lp_threshold = Low Power Threshold +ch.zimi.powerstrip.v2.power = Power +ch.zimi.powerstrip.v2.powerUsage = Power Consumption +ch.zimi.powerstrip.v2.power_price = power_price +ch.zimi.powerstrip.v2.temperature = Temperature +option.careli.fryer.maf01-miot.actions-air-fryer-cancel-cooking = Air Fryer Cancel Cooking +option.careli.fryer.maf01-miot.actions-air-fryer-pause = Air Fryer Pause +option.careli.fryer.maf01-miot.actions-air-fryer-start-cook = Air Fryer Start Cook +option.careli.fryer.maf01-miot.actions-custom-resume-cook = Custom Resume Cook +option.careli.fryer.maf01-miot.actions-custom-start-cook = Custom Start Cook +option.careli.fryer.maf01-miot.fault-0 = No Faults +option.careli.fryer.maf01-miot.fault-1 = E1 +option.careli.fryer.maf01-miot.fault-2 = E2 +option.careli.fryer.maf01-miot.food_quantity-0 = Null +option.careli.fryer.maf01-miot.food_quantity-1 = Single +option.careli.fryer.maf01-miot.food_quantity-2 = Double +option.careli.fryer.maf01-miot.food_quantity-3 = Half +option.careli.fryer.maf01-miot.food_quantity-4 = Full +option.careli.fryer.maf01-miot.preheat_switch-0 = Null +option.careli.fryer.maf01-miot.preheat_switch-1 = Off +option.careli.fryer.maf01-miot.preheat_switch-2 = On +option.careli.fryer.maf01-miot.status-0 = Shutdown +option.careli.fryer.maf01-miot.status-1 = Standby +option.careli.fryer.maf01-miot.status-2 = Pause +option.careli.fryer.maf01-miot.status-3 = Appointment +option.careli.fryer.maf01-miot.status-4 = Cooking +option.careli.fryer.maf01-miot.status-5 = Preheat +option.careli.fryer.maf01-miot.status-6 = Cooked +option.careli.fryer.maf01-miot.status-7 = Preheat Finish +option.careli.fryer.maf01-miot.status-8 = Preheat Pause +option.careli.fryer.maf01-miot.status-9 = Pause2 +option.careli.fryer.maf01-miot.turn_pot-0 = Not Turn Pot +option.careli.fryer.maf01-miot.turn_pot-1 = Switch Off +option.careli.fryer.maf01-miot.turn_pot-2 = Turn Pot +option.careli.fryer.maf02-miot.actions-air-fryer-cancel-cooking = Air Fryer Cancel Cooking +option.careli.fryer.maf02-miot.actions-air-fryer-pause = Air Fryer Pause +option.careli.fryer.maf02-miot.actions-air-fryer-start-cook = Air Fryer Start Cook +option.careli.fryer.maf02-miot.actions-custom-resume-cooking = Custom Resume Cooking +option.careli.fryer.maf02-miot.actions-custom-start-custom-cook = Custom Start Custom Cook +option.careli.fryer.maf02-miot.fault-0 = No Faults +option.careli.fryer.maf02-miot.fault-1 = E1 +option.careli.fryer.maf02-miot.fault-2 = E2 +option.careli.fryer.maf02-miot.food_quantity-0 = Null +option.careli.fryer.maf02-miot.food_quantity-1 = Single +option.careli.fryer.maf02-miot.food_quantity-2 = Double +option.careli.fryer.maf02-miot.food_quantity-3 = Half +option.careli.fryer.maf02-miot.food_quantity-4 = Full +option.careli.fryer.maf02-miot.preheat_switch-0 = Null +option.careli.fryer.maf02-miot.preheat_switch-1 = Off +option.careli.fryer.maf02-miot.preheat_switch-2 = On +option.careli.fryer.maf02-miot.status-0 = Shutdown +option.careli.fryer.maf02-miot.status-1 = Standby +option.careli.fryer.maf02-miot.status-2 = Pause +option.careli.fryer.maf02-miot.status-3 = Appointment +option.careli.fryer.maf02-miot.status-4 = Cooking +option.careli.fryer.maf02-miot.status-5 = Preheat +option.careli.fryer.maf02-miot.status-6 = Cooked +option.careli.fryer.maf02-miot.status-7 = Preheat Finish +option.careli.fryer.maf02-miot.status-8 = Preheat Pause +option.careli.fryer.maf02-miot.status-9 = Pause2 +option.careli.fryer.maf02-miot.turn_pot-0 = Not Turn Pot +option.careli.fryer.maf02-miot.turn_pot-1 = Switch Off +option.careli.fryer.maf02-miot.turn_pot-2 = Turn Pot +option.cgllc.airm.cgdn1-miot.actions-settings-set-device-off = Set Device Off +option.cgllc.airm.cgdn1-miot.actions-settings-set-end-time = Set End Time +option.cgllc.airm.cgdn1-miot.actions-settings-set-frequency = Set Frequency +option.cgllc.airm.cgdn1-miot.actions-settings-set-screen-off = Set Screen Off +option.cgllc.airm.cgdn1-miot.actions-settings-set-start-time = Set Start Time +option.cgllc.airm.cgdn1-miot.actions-settings-set-temp-unit = Set Temp Unit +option.cgllc.airm.cgdn1-miot.charging_state-1 = Charging +option.cgllc.airm.cgdn1-miot.charging_state-2 = Not charging +option.cgllc.airm.cgdn1-miot.charging_state-3 = Not chargeable +option.cgllc.airm.cgdn1-miot.device_off-0 = Null +option.cgllc.airm.cgdn1-miot.device_off-15 = Minute +option.cgllc.airm.cgdn1-miot.device_off-30 = Minute +option.cgllc.airm.cgdn1-miot.device_off-60 = Minute +option.cgllc.airm.cgdn1-miot.monitoring_frequency-0 = Null +option.cgllc.airm.cgdn1-miot.monitoring_frequency-1 = Second +option.cgllc.airm.cgdn1-miot.monitoring_frequency-300 = Second +option.cgllc.airm.cgdn1-miot.monitoring_frequency-60 = Second +option.cgllc.airm.cgdn1-miot.monitoring_frequency-600 = Second +option.cgllc.airm.cgdn1-miot.screen_off-0 = Null +option.cgllc.airm.cgdn1-miot.screen_off-15 = Second +option.cgllc.airm.cgdn1-miot.screen_off-30 = Second +option.cgllc.airm.cgdn1-miot.screen_off-300 = Second +option.cgllc.airm.cgdn1-miot.screen_off-60 = Second +option.deerma.humidifier.jsq1.mode-1 = Low +option.deerma.humidifier.jsq1.mode-2 = Medium +option.deerma.humidifier.jsq1.mode-3 = High +option.deerma.humidifier.jsq1.mode-4 = Humidity +option.deerma.humidifier.mjjsq.mode-1 = Low +option.deerma.humidifier.mjjsq.mode-2 = Medium +option.deerma.humidifier.mjjsq.mode-3 = High +option.deerma.humidifier.mjjsq.mode-4 = Humidity +option.dmaker.fan.p15-miot.actions-off-delay-time-toggle = Off Delay Time Toggle +option.dmaker.fan.p15-miot.fan_level-1 = Level1 +option.dmaker.fan.p15-miot.fan_level-2 = Level2 +option.dmaker.fan.p15-miot.fan_level-3 = Level3 +option.dmaker.fan.p15-miot.fan_level-4 = Level4 +option.dmaker.fan.p15-miot.fault-0 = No Faults +option.dmaker.fan.p15-miot.horizontal_angle-120 = 120 +option.dmaker.fan.p15-miot.horizontal_angle-140 = 140 +option.dmaker.fan.p15-miot.horizontal_angle-30 = 30 +option.dmaker.fan.p15-miot.horizontal_angle-60 = 60 +option.dmaker.fan.p15-miot.horizontal_angle-90 = 90 +option.dmaker.fan.p15-miot.mode-0 = Straight Wind +option.dmaker.fan.p15-miot.mode-1 = Natural Wind +option.dmaker.fan.p18-miot.actions-fan-toggle = Fan Toggle +option.dmaker.fan.p18-miot.fan_level-1 = Level1 +option.dmaker.fan.p18-miot.fan_level-2 = Level2 +option.dmaker.fan.p18-miot.fan_level-3 = Level3 +option.dmaker.fan.p18-miot.fan_level-4 = Level4 +option.dmaker.fan.p18-miot.horizontal_angle-120 = 120 +option.dmaker.fan.p18-miot.horizontal_angle-140 = 140 +option.dmaker.fan.p18-miot.horizontal_angle-30 = 30 +option.dmaker.fan.p18-miot.horizontal_angle-60 = 60 +option.dmaker.fan.p18-miot.horizontal_angle-90 = 90 +option.dmaker.fan.p18-miot.mode-0 = Straight Wind +option.dmaker.fan.p18-miot.mode-1 = Natural Wind +option.dmaker.fan.p18-miot.motor_control-0 = NO +option.dmaker.fan.p18-miot.motor_control-1 = LEFT +option.dmaker.fan.p18-miot.motor_control-2 = RIGHT +option.dmaker.fan.p8-miot.FanLevel-1 = Level1 +option.dmaker.fan.p8-miot.FanLevel-2 = Level2 +option.dmaker.fan.p8-miot.FanLevel-3 = Level3 +option.dmaker.fan.p8-miot.Mode-0 = Straight Wind +option.dmaker.fan.p8-miot.Mode-1 = Sleep +option.dmaker.fan.p8-miot.actions-fan-toggle = Fan Toggle +option.dmaker.fan.p9-miot.FanLevel-1 = Level1 +option.dmaker.fan.p9-miot.FanLevel-2 = Level2 +option.dmaker.fan.p9-miot.FanLevel-3 = Level3 +option.dmaker.fan.p9-miot.FanLevel-4 = Level4 +option.dmaker.fan.p9-miot.HorizontalAngle-120 = 120 +option.dmaker.fan.p9-miot.HorizontalAngle-150 = 150 +option.dmaker.fan.p9-miot.HorizontalAngle-30 = 30 +option.dmaker.fan.p9-miot.HorizontalAngle-60 = 60 +option.dmaker.fan.p9-miot.HorizontalAngle-90 = 90 +option.dmaker.fan.p9-miot.Mode-0 = Straight Wind +option.dmaker.fan.p9-miot.Mode-1 = Natural Wind +option.dmaker.fan.p9-miot.Mode-2 = Sleep +option.dmaker.fan.p9-miot.actions-fan-toggle = Fan Toggle +option.dreame.vacuum.mc1808-miot.ChargingState-1 = Charging +option.dreame.vacuum.mc1808-miot.ChargingState-2 = Not Charging +option.dreame.vacuum.mc1808-miot.ChargingState-4 = Charging +option.dreame.vacuum.mc1808-miot.ChargingState-5 = Go Charging +option.dreame.vacuum.mc1808-miot.Fault-0 = No faults +option.dreame.vacuum.mc1808-miot.Mode-0 = quiet +option.dreame.vacuum.mc1808-miot.Mode-1 = standard +option.dreame.vacuum.mc1808-miot.Mode-2 = medium +option.dreame.vacuum.mc1808-miot.Mode-3 = strong +option.dreame.vacuum.mc1808-miot.Status-1 = Sweeping +option.dreame.vacuum.mc1808-miot.Status-2 = Idle +option.dreame.vacuum.mc1808-miot.Status-3 = Paused +option.dreame.vacuum.mc1808-miot.Status-4 = Error +option.dreame.vacuum.mc1808-miot.Status-5 = Go Charging +option.dreame.vacuum.mc1808-miot.Status-6 = Charging +option.dreame.vacuum.mc1808-miot.TaskDone-0 = in progress +option.dreame.vacuum.mc1808-miot.TaskDone-1 = done +option.dreame.vacuum.mc1808-miot.vacuumaction-dock = Goto Dock +option.dreame.vacuum.mc1808-miot.vacuumaction-stop = Stop +option.dreame.vacuum.mc1808-miot.vacuumaction-stopsweep = Stop Sweep +option.dreame.vacuum.mc1808-miot.vacuumaction-sweep = Sweep +option.dreame.vacuum.mc1808-miot.vacuumaction-vacuum = Vacuum +option.dreame.vacuum.mc1808-miot.water-mode-1 = Low +option.dreame.vacuum.mc1808-miot.water-mode-2 = Medium +option.dreame.vacuum.mc1808-miot.water-mode-4 = High +option.dreame.vacuum.p2008-miot.break-point-restart-0 = Off +option.dreame.vacuum.p2008-miot.break-point-restart-1 = On +option.dreame.vacuum.p2008-miot.carpet-press-0 = Off +option.dreame.vacuum.p2008-miot.carpet-press-1 = On +option.dreame.vacuum.p2008-miot.charging-state-1 = Charging +option.dreame.vacuum.p2008-miot.charging-state-2 = Not Charging +option.dreame.vacuum.p2008-miot.charging-state-5 = Go Charging +option.dreame.vacuum.p2008-miot.cleaning-mode-0 = mode 0 +option.dreame.vacuum.p2008-miot.cleaning-mode-1 = mode 1 +option.dreame.vacuum.p2008-miot.cleaning-mode-2 = mode 2 +option.dreame.vacuum.p2008-miot.cleaning-mode-3 = mode 3 +option.dreame.vacuum.p2008-miot.fault-0 = No Faults +option.dreame.vacuum.p2008-miot.mop-mode-1 = low water +option.dreame.vacuum.p2008-miot.mop-mode-2 = medium water +option.dreame.vacuum.p2008-miot.mop-mode-3 = high water +option.dreame.vacuum.p2008-miot.save-map-status--1 = Not Enabled +option.dreame.vacuum.p2008-miot.save-map-status-0 = Off +option.dreame.vacuum.p2008-miot.save-map-status-1 = On +option.dreame.vacuum.p2008-miot.status-1 = Sweeping +option.dreame.vacuum.p2008-miot.status-2 = Idle +option.dreame.vacuum.p2008-miot.status-3 = Paused +option.dreame.vacuum.p2008-miot.status-4 = Error +option.dreame.vacuum.p2008-miot.status-5 = Go Charging +option.dreame.vacuum.p2008-miot.status-6 = Charging +option.dreame.vacuum.p2008-miot.task-status-0 = Status 0 +option.dreame.vacuum.p2008-miot.task-status-1 = Status 1 +option.dreame.vacuum.p2008-miot.waterbox-status-0 = Status 0 +option.dreame.vacuum.p2008-miot.waterbox-status-1 = Status 1 +option.dreame.vacuum.p2009-miot.break-point-restart-0 = Off +option.dreame.vacuum.p2009-miot.break-point-restart-1 = On +option.dreame.vacuum.p2009-miot.carpet-press-0 = Off +option.dreame.vacuum.p2009-miot.carpet-press-1 = On +option.dreame.vacuum.p2009-miot.charging-state-1 = Charging +option.dreame.vacuum.p2009-miot.charging-state-2 = Not Charging +option.dreame.vacuum.p2009-miot.charging-state-5 = Go Charging +option.dreame.vacuum.p2009-miot.cleaning-mode-0 = mode 0 +option.dreame.vacuum.p2009-miot.cleaning-mode-1 = mode 1 +option.dreame.vacuum.p2009-miot.cleaning-mode-2 = mode 2 +option.dreame.vacuum.p2009-miot.cleaning-mode-3 = mode 3 +option.dreame.vacuum.p2009-miot.fault-0 = No Error +option.dreame.vacuum.p2009-miot.fault-1 = Drop +option.dreame.vacuum.p2009-miot.fault-10 = Waterbox Empty +option.dreame.vacuum.p2009-miot.fault-11 = Box full +option.dreame.vacuum.p2009-miot.fault-12 = Brush +option.dreame.vacuum.p2009-miot.fault-13 = Side Brush +option.dreame.vacuum.p2009-miot.fault-14 = Fan +option.dreame.vacuum.p2009-miot.fault-15 = Left Wheel motor +option.dreame.vacuum.p2009-miot.fault-16 = Right Wheel motor +option.dreame.vacuum.p2009-miot.fault-17 = Turn suffocate +option.dreame.vacuum.p2009-miot.fault-18 = Forward suffocate +option.dreame.vacuum.p2009-miot.fault-19 = Charger get +option.dreame.vacuum.p2009-miot.fault-2 = Cliff +option.dreame.vacuum.p2009-miot.fault-20 = Battery low +option.dreame.vacuum.p2009-miot.fault-21 = Charge fault +option.dreame.vacuum.p2009-miot.fault-22 = Battery percentage +option.dreame.vacuum.p2009-miot.fault-23 = Heart +option.dreame.vacuum.p2009-miot.fault-24 = Camera occlusion +option.dreame.vacuum.p2009-miot.fault-25 = Camera fault +option.dreame.vacuum.p2009-miot.fault-26 = Event battery +option.dreame.vacuum.p2009-miot.fault-27 = Forward looking +option.dreame.vacuum.p2009-miot.fault-28 = Gyroscope +option.dreame.vacuum.p2009-miot.fault-3 = Bumper +option.dreame.vacuum.p2009-miot.fault-4 = Gesture +option.dreame.vacuum.p2009-miot.fault-5 = Bumper Repeat +option.dreame.vacuum.p2009-miot.fault-6 = Drop Repeat +option.dreame.vacuum.p2009-miot.fault-7 = Optical Flow +option.dreame.vacuum.p2009-miot.fault-8 = No Box +option.dreame.vacuum.p2009-miot.fault-9 = No Tankbox +option.dreame.vacuum.p2009-miot.mop-mode-1 = low water +option.dreame.vacuum.p2009-miot.mop-mode-2 = medium water +option.dreame.vacuum.p2009-miot.mop-mode-3 = high water +option.dreame.vacuum.p2009-miot.resetConsumable-filter-reset-filter-life = Reset Filter +option.dreame.vacuum.p2009-miot.resetConsumable-mainbrush-cleaner-reset-brush-life = Reset Main Brush +option.dreame.vacuum.p2009-miot.resetConsumable-sidebrush-cleaner-reset-brush-life = Reset Side Brush +option.dreame.vacuum.p2009-miot.status-1 = Sweeping +option.dreame.vacuum.p2009-miot.status-2 = Idle +option.dreame.vacuum.p2009-miot.status-3 = Paused +option.dreame.vacuum.p2009-miot.status-4 = Error +option.dreame.vacuum.p2009-miot.status-5 = Go Charging +option.dreame.vacuum.p2009-miot.status-6 = Charging +option.dreame.vacuum.p2009-miot.status-7 = Mopping +option.dreame.vacuum.p2009-miot.task-status-0 = Notask +option.dreame.vacuum.p2009-miot.task-status-1 = AutoClean +option.dreame.vacuum.p2009-miot.task-status-2 = CustomClean +option.dreame.vacuum.p2009-miot.task-status-3 = SelectAreanClean +option.dreame.vacuum.p2009-miot.task-status-4 = SpotArea +option.dreame.vacuum.p2009-miot.vacuumaction-dock = Goto Dock +option.dreame.vacuum.p2009-miot.vacuumaction-findme = Find me +option.dreame.vacuum.p2009-miot.vacuumaction-stopsweep = Stop Sweep +option.dreame.vacuum.p2009-miot.vacuumaction-sweep = Sweep +option.dreame.vacuum.p2009-miot.vacuumaction-testsound = Test Sound +option.dreame.vacuum.p2009-miot.waterbox-status-0 = Status 0 +option.dreame.vacuum.p2009-miot.waterbox-status-1 = Status 1 +option.dreame.vacuum.p2156o-miot.actions-audio-play-sound = Audio Play Sound +option.dreame.vacuum.p2156o-miot.actions-audio-position = Audio Position +option.dreame.vacuum.p2156o-miot.actions-battery-start-charge = Start Charge +option.dreame.vacuum.p2156o-miot.actions-brush-cleaner-reset-brush-life = Brush Cleaner Reset Brush Life +option.dreame.vacuum.p2156o-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.dreame.vacuum.p2156o-miot.actions-map-map-req = Map Map Req +option.dreame.vacuum.p2156o-miot.actions-map-update-map = Map Update Map +option.dreame.vacuum.p2156o-miot.actions-time-delete-timer = Time Delete Timer +option.dreame.vacuum.p2156o-miot.actions-vacuum-extend-start-clean = Vacuum Extend Start Clean +option.dreame.vacuum.p2156o-miot.actions-vacuum-extend-stop-clean = Vacuum Extend Stop Clean +option.dreame.vacuum.p2156o-miot.actions-vacuum-start-sweep = Start Sweep +option.dreame.vacuum.p2156o-miot.actions-vacuum-stop-sweeping = Stop Sweeping +option.dreame.vacuum.p2156o-miot.break_point_restart-0 = Off +option.dreame.vacuum.p2156o-miot.break_point_restart-1 = On +option.dreame.vacuum.p2156o-miot.carpet_press-0 = Off +option.dreame.vacuum.p2156o-miot.carpet_press-1 = On +option.dreame.vacuum.p2156o-miot.charging_state-1 = Charging +option.dreame.vacuum.p2156o-miot.charging_state-2 = Not Charging +option.dreame.vacuum.p2156o-miot.charging_state-5 = Go Charging +option.dreame.vacuum.p2156o-miot.cleaning_mode-0 = mode 0 +option.dreame.vacuum.p2156o-miot.cleaning_mode-1 = mode 1 +option.dreame.vacuum.p2156o-miot.cleaning_mode-2 = mode 2 +option.dreame.vacuum.p2156o-miot.cleaning_mode-3 = mode 3 +option.dreame.vacuum.p2156o-miot.mode-0 = Silent +option.dreame.vacuum.p2156o-miot.mode-1 = Basic +option.dreame.vacuum.p2156o-miot.mode-2 = Strong +option.dreame.vacuum.p2156o-miot.mode-3 = Full Speed +option.dreame.vacuum.p2156o-miot.mop_mode-1 = low water +option.dreame.vacuum.p2156o-miot.mop_mode-2 = medium water +option.dreame.vacuum.p2156o-miot.mop_mode-3 = high water +option.dreame.vacuum.p2156o-miot.save_map_status-0 = Off +option.dreame.vacuum.p2156o-miot.save_map_status-1 = On +option.dreame.vacuum.p2156o-miot.status-1 = Sweeping +option.dreame.vacuum.p2156o-miot.status-2 = Idle +option.dreame.vacuum.p2156o-miot.status-3 = Paused +option.dreame.vacuum.p2156o-miot.status-4 = Error +option.dreame.vacuum.p2156o-miot.status-5 = Go Charging +option.dreame.vacuum.p2156o-miot.status-6 = Charging +option.dreame.vacuum.p2156o-miot.status-7 = Mopping +option.dreame.vacuum.p2156o-miot.task_status-0 = Notask +option.dreame.vacuum.p2156o-miot.task_status-1 = AutoClean +option.dreame.vacuum.p2156o-miot.task_status-2 = CustomClean +option.dreame.vacuum.p2156o-miot.task_status-3 = SelectAreanClean +option.dreame.vacuum.p2156o-miot.task_status-4 = SpotArea +option.dreame.vacuum.p2156o-miot.waterbox_status-0 = Status 0 +option.dreame.vacuum.p2156o-miot.waterbox_status-1 = Status 1 +option.huayi.light.fanwy-miot.mode-1 = Normal Wind +option.huayi.light.fanwy-miot.mode-2 = Natural Wind +option.huayi.light.fanwy2-miot.mode-0 = Basic +option.huayi.light.fanwy2-miot.mode-1 = Natural Wind +option.huayi.light.fanwy2-miot.pre-custom-0 = Switch Off +option.huayi.light.fanwy2-miot.pre-custom-1 = Open +option.huayi.light.fanwy2-miot.reversal-0 = Postitive +option.huayi.light.fanwy2-miot.reversal-1 = Reverse +option.huayi.light.wyheat-miot.fault-0 = No Faults +option.lumi.curtain.hagl05-miot.en-night-tip-light-0 = Disable +option.lumi.curtain.hagl05-miot.en-night-tip-light-1 = Enable +option.lumi.curtain.hagl05-miot.fault-0 = No faults +option.lumi.curtain.hagl05-miot.manual-enabled-0 = Disable +option.lumi.curtain.hagl05-miot.manual-enabled-1 = Enable +option.lumi.curtain.hagl05-miot.polarity-0 = Positive +option.lumi.curtain.hagl05-miot.polarity-1 = Reverse +option.lumi.curtain.hagl05-miot.pos-limit-0 = Unlimit +option.lumi.curtain.hagl05-miot.pos-limit-1 = Limit +option.lumi.curtain.hagl05-miot.status-0 = Stopped +option.lumi.curtain.hagl05-miot.status-1 = Opening +option.lumi.curtain.hagl05-miot.status-2 = Closing +option.mijia.vacuum.v2-miot.charging-state-0 = Not-charging +option.mijia.vacuum.v2-miot.charging-state-1 = Charging +option.mijia.vacuum.v2-miot.charging-state-2 = Charging-competely +option.mijia.vacuum.v2-miot.direction_key-0 = direction 0 +option.mijia.vacuum.v2-miot.direction_key-1 = direction 1 +option.mijia.vacuum.v2-miot.direction_key-2 = direction 2 +option.mijia.vacuum.v2-miot.direction_key-3 = direction 3 +option.mijia.vacuum.v2-miot.direction_key-4 = direction 4 +option.mijia.vacuum.v2-miot.fan-level-0 = Silence +option.mijia.vacuum.v2-miot.fan-level-1 = Stanrd +option.mijia.vacuum.v2-miot.fan-level-2 = Middle +option.mijia.vacuum.v2-miot.fan-level-3 = Enchance +option.mijia.vacuum.v2-miot.fault-0 = No Faults +option.mijia.vacuum.v2-miot.fault-1 = Left-wheel-error +option.mijia.vacuum.v2-miot.fault-10 = Charging-error +option.mijia.vacuum.v2-miot.fault-11 = No-wate-error +option.mijia.vacuum.v2-miot.fault-12 = Pick-up-error +option.mijia.vacuum.v2-miot.fault-2 = Right-wheel-error +option.mijia.vacuum.v2-miot.fault-3 = Cliff-error +option.mijia.vacuum.v2-miot.fault-4 = Low-battery-error +option.mijia.vacuum.v2-miot.fault-5 = Bump-error +option.mijia.vacuum.v2-miot.fault-6 = Main-brush-error +option.mijia.vacuum.v2-miot.fault-7 = Side-brush-error +option.mijia.vacuum.v2-miot.fault-8 = Fan-motor-error +option.mijia.vacuum.v2-miot.fault-9 = Dustbin-error +option.mijia.vacuum.v2-miot.language-0 = English +option.mijia.vacuum.v2-miot.language-1 = 简体中文 +option.mijia.vacuum.v2-miot.language-2 = Español +option.mijia.vacuum.v2-miot.language-3 = Русский +option.mijia.vacuum.v2-miot.language-4 = Italiano +option.mijia.vacuum.v2-miot.language-5 = Français +option.mijia.vacuum.v2-miot.language-6 = Deutsch +option.mijia.vacuum.v2-miot.language-7 = 한국어 +option.mijia.vacuum.v2-miot.language-8 = Polski +option.mijia.vacuum.v2-miot.mode-1 = Auto-clean +option.mijia.vacuum.v2-miot.mode-2 = Spot-clean +option.mijia.vacuum.v2-miot.mode-3 = Wallflow-clean +option.mijia.vacuum.v2-miot.mop-status-0 = Mop Uninstall +option.mijia.vacuum.v2-miot.mop-status-1 = Mop Install +option.mijia.vacuum.v2-miot.status-1 = Idle +option.mijia.vacuum.v2-miot.status-2 = Sweeping +option.mijia.vacuum.v2-miot.status-3 = Paused +option.mijia.vacuum.v2-miot.status-4 = Error +option.mijia.vacuum.v2-miot.status-5 = Charging +option.mijia.vacuum.v2-miot.status-6 = Go Charging +option.mijia.vacuum.v2-miot.target-water-level-1 = Level1 +option.mijia.vacuum.v2-miot.target-water-level-2 = Level2 +option.mijia.vacuum.v2-miot.target-water-level-3 = Level3 +option.mmgg.pet_waterer.s1-miot.fault-0 = No faults +option.mmgg.pet_waterer.s1-miot.mode-1 = Common +option.mmgg.pet_waterer.s1-miot.mode-2 = Smart +option.mmgg.pet_waterer.s1-miot.resetConsumable-filter-cotton-reset-cotton-life = Reset Cotton Time +option.mmgg.pet_waterer.s1-miot.resetConsumable-filter-reset-filter-life = Reset Filter Life +option.mmgg.pet_waterer.s1-miot.resetConsumable-remain-clean-time-reset-clean-time = Reset Clean Time +option.mmgg.pet_waterer.s2-miot.fault-0 = No faults +option.mmgg.pet_waterer.s2-miot.mode-1 = Common +option.mmgg.pet_waterer.s2-miot.mode-2 = Smart +option.mmgg.pet_waterer.s2-miot.resetConsumable-filter-cotton-reset-cotton-life = Reset Cotton Time +option.mmgg.pet_waterer.s2-miot.resetConsumable-filter-reset-filter-life = Reset Filter Life +option.mmgg.pet_waterer.s2-miot.resetConsumable-remain-clean-time-reset-clean-time = Reset Clean Time +option.qmi.powerstrip.v1.mode-green = Green +option.qmi.powerstrip.v1.mode-normal = Normal +option.viomi.vacuum.v18-miot.clean-mode-0 = Everywhere +option.viomi.vacuum.v18-miot.clean-mode-1 = Edges +option.viomi.vacuum.v18-miot.clean-mode-2 = Surface +option.viomi.vacuum.v18-miot.clean-mode-3 = Fixed Location +option.viomi.vacuum.v18-miot.clean-way-0 = Sweep Floor +option.viomi.vacuum.v18-miot.clean-way-1 = Sweep +option.viomi.vacuum.v18-miot.clean-way-2 = Mop +option.viomi.vacuum.v18-miot.contact-state-0 = Off +option.viomi.vacuum.v18-miot.contact-state-1 = On +option.viomi.vacuum.v18-miot.dnd-enable-0 = Disabled +option.viomi.vacuum.v18-miot.dnd-enable-1 = Enabled +option.viomi.vacuum.v18-miot.door-state-0 = Door 0 +option.viomi.vacuum.v18-miot.door-state-1 = Door 1 +option.viomi.vacuum.v18-miot.door-state-2 = Door 2 +option.viomi.vacuum.v18-miot.door-state-3 = Door 3 +option.viomi.vacuum.v18-miot.download-status-0 = Free +option.viomi.vacuum.v18-miot.download-status-1 = Downloading +option.viomi.vacuum.v18-miot.dust-collection-0 = Close +option.viomi.vacuum.v18-miot.dust-collection-1 = Open +option.viomi.vacuum.v18-miot.fault-0 = No Error +option.viomi.vacuum.v18-miot.fault-1 = Low Battery Find Charge +option.viomi.vacuum.v18-miot.fault-10 = Side Brush Err +option.viomi.vacuum.v18-miot.fault-11 = Fan Err +option.viomi.vacuum.v18-miot.fault-12 = Lidar Cover +option.viomi.vacuum.v18-miot.fault-13 = Garbage Full +option.viomi.vacuum.v18-miot.fault-14 = Garbage Out +option.viomi.vacuum.v18-miot.fault-15 = Garbage Full Out +option.viomi.vacuum.v18-miot.fault-16 = Trapped +option.viomi.vacuum.v18-miot.fault-17 = Pick Up +option.viomi.vacuum.v18-miot.fault-18 = Garbage Out +option.viomi.vacuum.v18-miot.fault-2 = Low Bat Need Poweroff +option.viomi.vacuum.v18-miot.fault-20 = Cannot Arrive +option.viomi.vacuum.v18-miot.fault-21 = Start From Forbid +option.viomi.vacuum.v18-miot.fault-22 = Drop +option.viomi.vacuum.v18-miot.fault-23 = Kit Water Pump +option.viomi.vacuum.v18-miot.fault-24 = Find Charge Failed +option.viomi.vacuum.v18-miot.fault-25 = No Mop Clean +option.viomi.vacuum.v18-miot.fault-26 = Low Battery Cant Clean +option.viomi.vacuum.v18-miot.fault-3 = Wheel Trap +option.viomi.vacuum.v18-miot.fault-4 = Collision Error +option.viomi.vacuum.v18-miot.fault-5 = Tile Do Task +option.viomi.vacuum.v18-miot.fault-6 = Lidar Point Err +option.viomi.vacuum.v18-miot.fault-7 = Front Wall Err +option.viomi.vacuum.v18-miot.fault-8 = Along Wall Err +option.viomi.vacuum.v18-miot.fault-9 = Mid Brush Err +option.viomi.vacuum.v18-miot.has-map-0 = No map in memory +option.viomi.vacuum.v18-miot.has-map-1 = Map in memory +option.viomi.vacuum.v18-miot.has-newmap-0 = None +option.viomi.vacuum.v18-miot.has-newmap-1 = New +option.viomi.vacuum.v18-miot.has-newmap-2 = Cover +option.viomi.vacuum.v18-miot.map-type-0 = Upload to url0 +option.viomi.vacuum.v18-miot.map-type-1 = Upload to url1 +option.viomi.vacuum.v18-miot.map-type-2 = Upload to url2 +option.viomi.vacuum.v18-miot.mode-0 = Silent +option.viomi.vacuum.v18-miot.mode-1 = Basic +option.viomi.vacuum.v18-miot.mode-2 = Medium +option.viomi.vacuum.v18-miot.mode-3 = Strong +option.viomi.vacuum.v18-miot.mop-route-0 = C-Curved +option.viomi.vacuum.v18-miot.mop-route-1 = Y-Route +option.viomi.vacuum.v18-miot.status-0 = Sleep +option.viomi.vacuum.v18-miot.status-1 = Idle +option.viomi.vacuum.v18-miot.status-2 = Paused +option.viomi.vacuum.v18-miot.status-3 = Go Charging +option.viomi.vacuum.v18-miot.status-4 = Charging +option.viomi.vacuum.v18-miot.status-5 = Sweeping +option.viomi.vacuum.v18-miot.status-6 = Sweeping and Mopping +option.viomi.vacuum.v18-miot.status-7 = Mopping +option.viomi.vacuum.v18-miot.suction-grade-0 = Silent +option.viomi.vacuum.v18-miot.suction-grade-1 = Standard +option.viomi.vacuum.v18-miot.suction-grade-2 = Medium +option.viomi.vacuum.v18-miot.suction-grade-3 = Strong +option.viomi.vacuum.v18-miot.sweep-type-0 = Total +option.viomi.vacuum.v18-miot.sweep-type-2 = Wall +option.viomi.vacuum.v18-miot.sweep-type-3 = Zone +option.viomi.vacuum.v18-miot.sweep-type-4 = Point +option.viomi.vacuum.v18-miot.sweep-type-5 = Control +option.viomi.vacuum.v18-miot.vacuumaction-pause = Pause +option.viomi.vacuum.v18-miot.vacuumaction-start-charge = Goto Dock +option.viomi.vacuum.v18-miot.vacuumaction-start-mop = Start Mop +option.viomi.vacuum.v18-miot.vacuumaction-start-only-sweep = Start Sweep Only +option.viomi.vacuum.v18-miot.vacuumaction-start-sweep = Sweep +option.viomi.vacuum.v18-miot.vacuumaction-start-sweep-mop = Start Sweep Mop +option.viomi.vacuum.v18-miot.vacuumaction-stop-massage = Stop Sweep +option.viomi.vacuum.v18-miot.vacuumaction-stop-sweeping = Stop Sweep +option.viomi.vacuum.v18-miot.water-grade-0 = 1 Block +option.viomi.vacuum.v18-miot.water-grade-1 = 2 Blocks +option.viomi.vacuum.v18-miot.water-grade-2 = 3 Blocks +option.viomi.vacuum.v18-miot.wdr-mode-0 = Mode 0 +option.viomi.vacuum.v18-miot.wdr-mode-1 = Mode 1 +option.viomi.vacuum.v18-miot.wdr-mode-2 = Mode 2 +option.xiaomi.aircondition.ma1-miot.fan-level-0 = Auto +option.xiaomi.aircondition.ma1-miot.fan-level-1 = Level1 +option.xiaomi.aircondition.ma1-miot.fan-level-2 = Level2 +option.xiaomi.aircondition.ma1-miot.fan-level-3 = Level3 +option.xiaomi.aircondition.ma1-miot.fan-level-4 = Level4 +option.xiaomi.aircondition.ma1-miot.fan-level-5 = Level5 +option.xiaomi.aircondition.ma1-miot.fan-level-6 = Level6 +option.xiaomi.aircondition.ma1-miot.fan-level-7 = Level7 +option.xiaomi.aircondition.ma1-miot.mode-1 = Cool +option.xiaomi.aircondition.ma1-miot.mode-2 = Dry +option.xiaomi.aircondition.ma1-miot.mode-3 = Heat +option.xiaomi.aircondition.ma1-miot.mode-4 = Fan +option.xiaomi.aircondition.mc1-miot.fan-level-0 = Auto +option.xiaomi.aircondition.mc1-miot.fan-level-1 = Level1 +option.xiaomi.aircondition.mc1-miot.fan-level-2 = Level2 +option.xiaomi.aircondition.mc1-miot.fan-level-3 = Level3 +option.xiaomi.aircondition.mc1-miot.fan-level-4 = Level4 +option.xiaomi.aircondition.mc1-miot.fan-level-5 = Level5 +option.xiaomi.aircondition.mc1-miot.fan-level-6 = Level6 +option.xiaomi.aircondition.mc1-miot.fan-level-7 = Level7 +option.xiaomi.aircondition.mc1-miot.mode-2 = Cool +option.xiaomi.aircondition.mc1-miot.mode-3 = Dry +option.xiaomi.aircondition.mc1-miot.mode-4 = Fan +option.xiaomi.aircondition.mc1-miot.mode-5 = Heat +option.yeelink.light.ceiling.colorMode-0 = Default +option.yeelink.light.ceiling.colorMode-1 = RGB mode +option.yeelink.light.ceiling.colorMode-2 = CT mode +option.yeelink.light.ceiling.colorMode-3 = HSV mode +option.yeelink.light.ceiling.colorMode-4 = Color Flow mode +option.yeelink.light.ceiling.colorMode-5 = Night Light mode +option.yeelink.light.ceiling2.colorMode-0 = Default +option.yeelink.light.ceiling2.colorMode-1 = RGB mode +option.yeelink.light.ceiling2.colorMode-2 = CT mode +option.yeelink.light.ceiling2.colorMode-3 = HSV mode +option.yeelink.light.ceiling2.colorMode-4 = Color Flow mode +option.yeelink.light.ceiling2.colorMode-5 = Night Light mode +option.yeelink.light.ceiling4.colorMode-0 = Default +option.yeelink.light.ceiling4.colorMode-1 = RGB mode +option.yeelink.light.ceiling4.colorMode-2 = CT mode +option.yeelink.light.ceiling4.colorMode-3 = HSV mode +option.yeelink.light.ceiling4.colorMode-4 = Color Flow mode +option.yeelink.light.ceiling4.colorMode-5 = Night Light mode +option.yeelink.light.color1.colorMode-0 = Default +option.yeelink.light.color1.colorMode-1 = RGB mode +option.yeelink.light.color1.colorMode-2 = CT mode +option.yeelink.light.color1.colorMode-3 = HSV mode +option.yeelink.light.color1.colorMode-4 = Color Flow mode +option.yeelink.light.color1.colorMode-5 = Night Light mode +option.yeelink.light.lamp1.colorMode-0 = Default +option.yeelink.light.lamp1.colorMode-1 = RGB mode +option.yeelink.light.lamp1.colorMode-2 = CT mode +option.yeelink.light.lamp1.colorMode-3 = HSV mode +option.yeelink.light.lamp1.colorMode-4 = Color Flow mode +option.yeelink.light.lamp1.colorMode-5 = Night Light mode +option.yeelink.light.light15.colorMode-0 = Default +option.yeelink.light.light15.colorMode-1 = RGB mode +option.yeelink.light.light15.colorMode-2 = CT mode +option.yeelink.light.light15.colorMode-3 = HSV mode +option.yeelink.light.light15.colorMode-4 = Color Flow mode +option.yeelink.light.light15.colorMode-5 = Night Light mode +option.yeelink.switch.sw1-miot.mode-0 = Off +option.yeelink.switch.sw1-miot.mode-1 = On +option.yeelink.switch.sw1-miot.mode2-0 = Off +option.yeelink.switch.sw1-miot.mode2-1 = On +option.yunmi.waterpurifier.lightMode-0 = Simple Mode +option.yunmi.waterpurifier.lightMode-1 = Special Mode +option.yunmi.waterpurifier.lx8.lightMode-0 = Simple Mode +option.yunmi.waterpurifier.lx8.lightMode-1 = Special Mode +option.zhimi.airfresh.va4.led_level-0 = High +option.zhimi.airfresh.va4.led_level-1 = Low +option.zhimi.airfresh.va4.led_level-2 = Idle +option.zhimi.airfresh.va4.mode-auto = Auto +option.zhimi.airfresh.va4.mode-interval = Interval +option.zhimi.airfresh.va4.mode-low = 1 +option.zhimi.airfresh.va4.mode-middle = 2 +option.zhimi.airfresh.va4.mode-silent = Night +option.zhimi.airfresh.va4.mode-strong = 3 +option.zhimi.airpurifier.m1.favoritelevel-0 = Favorite 0 +option.zhimi.airpurifier.m1.favoritelevel-1 = Favorite 1 +option.zhimi.airpurifier.m1.favoritelevel-10 = Favorite 10 +option.zhimi.airpurifier.m1.favoritelevel-11 = Favorite 11 +option.zhimi.airpurifier.m1.favoritelevel-12 = Favorite 13 +option.zhimi.airpurifier.m1.favoritelevel-13 = Favorite 13 +option.zhimi.airpurifier.m1.favoritelevel-14 = Favorite 14 +option.zhimi.airpurifier.m1.favoritelevel-15 = Favorite 15 +option.zhimi.airpurifier.m1.favoritelevel-2 = Favorite 2 +option.zhimi.airpurifier.m1.favoritelevel-3 = Favorite 3 +option.zhimi.airpurifier.m1.favoritelevel-4 = Favorite 4 +option.zhimi.airpurifier.m1.favoritelevel-5 = Favorite 5 +option.zhimi.airpurifier.m1.favoritelevel-6 = Favorite 6 +option.zhimi.airpurifier.m1.favoritelevel-7 = Favorite 7 +option.zhimi.airpurifier.m1.favoritelevel-8 = Favorite 8 +option.zhimi.airpurifier.m1.favoritelevel-9 = Favorite 9 +option.zhimi.airpurifier.m1.mode-auto = Auto +option.zhimi.airpurifier.m1.mode-favorite = Favorite +option.zhimi.airpurifier.m1.mode-high = High +option.zhimi.airpurifier.m1.mode-idle = Idle +option.zhimi.airpurifier.m1.mode-medium = Medium +option.zhimi.airpurifier.m1.mode-silent = Silent +option.zhimi.airpurifier.m1.mode-strong = Strong +option.zhimi.airpurifier.ma4-miot.aqi-runstate-0 = continue +option.zhimi.airpurifier.ma4-miot.aqi-runstate-1 = hold +option.zhimi.airpurifier.ma4-miot.aqi-runstate-2 = sleep +option.zhimi.airpurifier.ma4-miot.aqi-state-0 = AQI_GOOD_L +option.zhimi.airpurifier.ma4-miot.aqi-state-1 = AQI_GOOD_H +option.zhimi.airpurifier.ma4-miot.aqi-state-2 = AQI_MID_L +option.zhimi.airpurifier.ma4-miot.aqi-state-3 = AQI_MID_H +option.zhimi.airpurifier.ma4-miot.aqi-state-4 = AQI_BAD_L +option.zhimi.airpurifier.ma4-miot.aqi-state-5 = AQI_BAD_H +option.zhimi.airpurifier.ma4-miot.brightness-0 = brightest +option.zhimi.airpurifier.ma4-miot.brightness-1 = glimmer +option.zhimi.airpurifier.ma4-miot.brightness-2 = led_closed +option.zhimi.airpurifier.ma4-miot.fan-level-1 = Level1 +option.zhimi.airpurifier.ma4-miot.fan-level-2 = Level2 +option.zhimi.airpurifier.ma4-miot.fan-level-3 = Level3 +option.zhimi.airpurifier.ma4-miot.fault-0 = No faults +option.zhimi.airpurifier.ma4-miot.fault-1 = m1_run +option.zhimi.airpurifier.ma4-miot.fault-2 = m1_stuck +option.zhimi.airpurifier.ma4-miot.fault-3 = no_sensor +option.zhimi.airpurifier.ma4-miot.fault-4 = error_hum +option.zhimi.airpurifier.ma4-miot.fault-5 = error_temp +option.zhimi.airpurifier.ma4-miot.manual-level-1 = Level1 +option.zhimi.airpurifier.ma4-miot.manual-level-2 = Level2 +option.zhimi.airpurifier.ma4-miot.manual-level-3 = Level3 +option.zhimi.airpurifier.ma4-miot.mode-0 = Auto +option.zhimi.airpurifier.ma4-miot.mode-1 = Sleep +option.zhimi.airpurifier.ma4-miot.mode-2 = Favorite +option.zhimi.airpurifier.ma4-miot.mode-3 = None +option.zhimi.airpurifier.ma4-miot.reboot-cause-0 = REASON_HW_BOOT +option.zhimi.airpurifier.ma4-miot.reboot-cause-1 = REASON_USER_REBOOT +option.zhimi.airpurifier.ma4-miot.reboot-cause-2 = REASON_UPDATE +option.zhimi.airpurifier.ma4-miot.reboot-cause-3 = REASON_WDT +option.zhimi.airpurifier.mb3-miot.aqi-runstate-0 = continuous sampling +option.zhimi.airpurifier.mb3-miot.aqi-runstate-1 = preparing sampling +option.zhimi.airpurifier.mb3-miot.aqi-runstate-2 = stop sampling +option.zhimi.airpurifier.mb3-miot.aqi-state-0 = best +option.zhimi.airpurifier.mb3-miot.aqi-state-1 = good +option.zhimi.airpurifier.mb3-miot.aqi-state-2 = normal +option.zhimi.airpurifier.mb3-miot.aqi-state-3 = bad +option.zhimi.airpurifier.mb3-miot.aqi-state-4 = worse +option.zhimi.airpurifier.mb3-miot.aqi-state-5 = unhealthy +option.zhimi.airpurifier.mb3-miot.brightness-0 = Brightest +option.zhimi.airpurifier.mb3-miot.brightness-1 = Glimmer +option.zhimi.airpurifier.mb3-miot.brightness-2 = Led Closed +option.zhimi.airpurifier.mb3-miot.country-code-44 = 分销英文 +option.zhimi.airpurifier.mb3-miot.country-code-82 = 韩国 +option.zhimi.airpurifier.mb3-miot.country-code-852 = 中国香港 +option.zhimi.airpurifier.mb3-miot.country-code-886 = 中国台湾 +option.zhimi.airpurifier.mb3-miot.country-code-91 = 印度 +option.zhimi.airpurifier.mb3-miot.fan-level-1 = Level1 +option.zhimi.airpurifier.mb3-miot.fan-level-2 = Level2 +option.zhimi.airpurifier.mb3-miot.fan-level-3 = Level3 +option.zhimi.airpurifier.mb3-miot.fault-0 = No faults +option.zhimi.airpurifier.mb3-miot.fault-1 = m1_run +option.zhimi.airpurifier.mb3-miot.fault-2 = m1_stuck +option.zhimi.airpurifier.mb3-miot.fault-3 = no_sensor +option.zhimi.airpurifier.mb3-miot.fault-4 = error_hum +option.zhimi.airpurifier.mb3-miot.fault-5 = error_temp +option.zhimi.airpurifier.mb3-miot.manual-level-1 = Level1 +option.zhimi.airpurifier.mb3-miot.manual-level-2 = Level2 +option.zhimi.airpurifier.mb3-miot.manual-level-3 = Level3 +option.zhimi.airpurifier.mb3-miot.mode-0 = Auto +option.zhimi.airpurifier.mb3-miot.mode-1 = Sleep +option.zhimi.airpurifier.mb3-miot.mode-2 = Favorite +option.zhimi.airpurifier.mb3-miot.mode-3 = None +option.zhimi.airpurifier.mb3-miot.reboot-cause-0 = hardware reboot +option.zhimi.airpurifier.mb3-miot.reboot-cause-1 = software reboot +option.zhimi.airpurifier.mb3-miot.reboot-cause-2 = update reboot +option.zhimi.airpurifier.mb3-miot.reboot-cause-3 = dog reboot +option.zhimi.airpurifier.mb4-miot.mode-0 = Auto +option.zhimi.airpurifier.mb4-miot.mode-1 = Sleep +option.zhimi.airpurifier.mb4-miot.mode-2 = Favorite +option.zhimi.airpurifier.vb2-miot.actions-button-toggle = Toggle +option.zhimi.airpurifier.vb2-miot.actions-button-toggle-mode = Toggle Mode +option.zhimi.airpurifier.vb2-miot.aqi_runstate-0 = continue +option.zhimi.airpurifier.vb2-miot.aqi_runstate-1 = hold +option.zhimi.airpurifier.vb2-miot.aqi_runstate-2 = sleep +option.zhimi.airpurifier.vb2-miot.aqi_state-0 = AQI_GOOD_L +option.zhimi.airpurifier.vb2-miot.aqi_state-1 = AQI_GOOD_H +option.zhimi.airpurifier.vb2-miot.aqi_state-2 = AQI_MID_L +option.zhimi.airpurifier.vb2-miot.aqi_state-3 = AQI_MID_H +option.zhimi.airpurifier.vb2-miot.aqi_state-4 = AQI_BAD_L +option.zhimi.airpurifier.vb2-miot.aqi_state-5 = AQI_BAD_H +option.zhimi.airpurifier.vb2-miot.brightness-0 = brightest +option.zhimi.airpurifier.vb2-miot.brightness-1 = glimmer +option.zhimi.airpurifier.vb2-miot.brightness-2 = not bright +option.zhimi.airpurifier.vb2-miot.country_code-44 = UK +option.zhimi.airpurifier.vb2-miot.country_code-82 = Korea +option.zhimi.airpurifier.vb2-miot.country_code-852 = Hong Kong +option.zhimi.airpurifier.vb2-miot.country_code-886 = Taiwan +option.zhimi.airpurifier.vb2-miot.country_code-91 = India +option.zhimi.airpurifier.vb2-miot.fan_level-0 = Sleep +option.zhimi.airpurifier.vb2-miot.fan_level-1 = Level1 +option.zhimi.airpurifier.vb2-miot.fan_level-2 = Level2 +option.zhimi.airpurifier.vb2-miot.fan_level-3 = Level3 +option.zhimi.airpurifier.vb2-miot.fault-0 = No faults +option.zhimi.airpurifier.vb2-miot.fault-1 = m1_run +option.zhimi.airpurifier.vb2-miot.fault-2 = m1_stuck +option.zhimi.airpurifier.vb2-miot.fault-3 = no_sensor +option.zhimi.airpurifier.vb2-miot.fault-4 = error_hum +option.zhimi.airpurifier.vb2-miot.fault-5 = error_temp +option.zhimi.airpurifier.vb2-miot.fault-6 = timer_error1 +option.zhimi.airpurifier.vb2-miot.fault-7 = timer_error2 +option.zhimi.airpurifier.vb2-miot.manual_level-1 = level1 +option.zhimi.airpurifier.vb2-miot.manual_level-2 = level2 +option.zhimi.airpurifier.vb2-miot.manual_level-3 = level3 +option.zhimi.airpurifier.vb2-miot.mode-0 = Auto +option.zhimi.airpurifier.vb2-miot.mode-1 = Night +option.zhimi.airpurifier.vb2-miot.mode-2 = Favourite +option.zhimi.airpurifier.vb2-miot.mode-3 = Manual +option.zhimi.airpurifier.vb2-miot.reboot_cause-0 = REASON_HW_BOOT +option.zhimi.airpurifier.vb2-miot.reboot_cause-1 = REASON_USER_REBOOT +option.zhimi.airpurifier.vb2-miot.reboot_cause-2 = REASON_UPDATE +option.zhimi.airpurifier.vb2-miot.reboot_cause-3 = REASON_WDT +option.zhimi.airpurifier.vb2-miot.sensor_state-0 = waiting +option.zhimi.airpurifier.vb2-miot.sensor_state-1 = ready +option.zhimi.airpurifier.za1-miot.brightness-0 = Bright +option.zhimi.airpurifier.za1-miot.brightness-1 = Light +option.zhimi.airpurifier.za1-miot.brightness-2 = Off +option.zhimi.airpurifier.za1-miot.country_code-1 = America +option.zhimi.airpurifier.za1-miot.country_code-10 = Taiwan +option.zhimi.airpurifier.za1-miot.country_code-2 = Canada +option.zhimi.airpurifier.za1-miot.country_code-3 = Singapore +option.zhimi.airpurifier.za1-miot.country_code-4 = Europe +option.zhimi.airpurifier.za1-miot.country_code-5 = Australian +option.zhimi.airpurifier.za1-miot.country_code-6 = Korea +option.zhimi.airpurifier.za1-miot.country_code-7 = China +option.zhimi.airpurifier.za1-miot.country_code-8 = France +option.zhimi.airpurifier.za1-miot.country_code-9 = Japanese +option.zhimi.airpurifier.za1-miot.fault-0 = No faults +option.zhimi.airpurifier.za1-miot.fault-1 = m1_run +option.zhimi.airpurifier.za1-miot.fault-2 = m1_stuck +option.zhimi.airpurifier.za1-miot.fault-3 = no_sensor +option.zhimi.airpurifier.za1-miot.fault-4 = error_hum +option.zhimi.airpurifier.za1-miot.fault-5 = error_temp +option.zhimi.airpurifier.za1-miot.fault-6 = timer_error1 +option.zhimi.airpurifier.za1-miot.fault-7 = timer_error2 +option.zhimi.airpurifier.za1-miot.mode-0 = Auto +option.zhimi.airpurifier.za1-miot.mode-1 = Sleep +option.zhimi.airpurifier.za1-miot.mode-2 = Favorite +option.zhimi.airpurifier.za1-miot.reboot_cause-0 = hardware +option.zhimi.airpurifier.za1-miot.reboot_cause-1 = human +option.zhimi.airpurifier.za1-miot.reboot_cause-2 = upgrade +option.zhimi.airpurifier.za1-miot.reboot_cause-3 = watchdog +option.zhimi.airpurifier.za1-miot.sensor_state-0 = waiting +option.zhimi.airpurifier.za1-miot.sensor_state-1 = ready +option.zhimi.fan.sa1.angle-120 = 120 +option.zhimi.fan.sa1.angle-30 = 30 +option.zhimi.fan.sa1.angle-60 = 60 +option.zhimi.fan.sa1.angle-90 = 90 +option.zhimi.fan.sa1.led_b-0 = Bright +option.zhimi.fan.sa1.led_b-1 = Dimmed +option.zhimi.fan.sa1.led_b-2 = Off +option.zhimi.fan.sa1.move- = None +option.zhimi.fan.sa1.move-left = Left +option.zhimi.fan.sa1.move-right = Right +option.zhimi.fan.v3.angle-120 = 120 +option.zhimi.fan.v3.angle-30 = 30 +option.zhimi.fan.v3.angle-60 = 60 +option.zhimi.fan.v3.angle-90 = 90 +option.zhimi.fan.v3.led_b-0 = Bright +option.zhimi.fan.v3.led_b-1 = Dimmed +option.zhimi.fan.v3.led_b-2 = Off +option.zhimi.fan.v3.move- = None +option.zhimi.fan.v3.move-left = Left +option.zhimi.fan.v3.move-right = Right +option.zhimi.fan.za5-miot.button_press-0 = No Button Pressed +option.zhimi.fan.za5-miot.button_press-1 = power +option.zhimi.fan.za5-miot.button_press-2 = swing +option.zhimi.fan.za5-miot.fan_level-1 = Level 1 +option.zhimi.fan.za5-miot.fan_level-2 = Level 2 +option.zhimi.fan.za5-miot.fan_level-3 = Level 3 +option.zhimi.fan.za5-miot.fan_level-4 = Level 4 +option.zhimi.fan.za5-miot.mode-0 = Natural Wind +option.zhimi.fan.za5-miot.mode-1 = Straight Wind +option.zhimi.heater.ma2-miot.brightness-0 = Bright +option.zhimi.heater.ma2-miot.brightness-1 = Dark +option.zhimi.heater.ma2-miot.brightness-2 = Extinguished +option.zhimi.heater.ma2-miot.fault-0 = No Error +option.zhimi.heater.ma2-miot.fault-1 = NTC Connect Error +option.zhimi.heater.ma2-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.ma2-miot.fault-3 = EEPROM Error +option.zhimi.heater.ma2-miot.fault-4 = Multi Errors +option.zhimi.heater.ma3-miot.actions-private-service-toggle-switch = Toggle Private Service +option.zhimi.heater.ma3-miot.brightness-0 = Bright +option.zhimi.heater.ma3-miot.brightness-1 = Dark +option.zhimi.heater.ma3-miot.brightness-2 = Extinguished +option.zhimi.heater.ma3-miot.fault-0 = No Error +option.zhimi.heater.ma3-miot.fault-1 = NTC Connect Error +option.zhimi.heater.ma3-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.ma3-miot.fault-3 = EEPROM Error +option.zhimi.heater.ma3-miot.fault-4 = Multi Errors +option.zhimi.heater.ma3-miot.mode-0 = Auto +option.zhimi.heater.ma3-miot.mode-1 = LL Mode +option.zhimi.heater.ma3-miot.mode-2 = HH Mode +option.zhimi.heater.mc2-miot.brightness-0 = Bright +option.zhimi.heater.mc2-miot.brightness-1 = Dark +option.zhimi.heater.mc2-miot.brightness-2 = Extinguished +option.zhimi.heater.mc2-miot.country_code-0 = Unknown +option.zhimi.heater.mc2-miot.country_code-1 = US +option.zhimi.heater.mc2-miot.country_code-33 = FR +option.zhimi.heater.mc2-miot.country_code-44 = EU +option.zhimi.heater.mc2-miot.country_code-7 = RU +option.zhimi.heater.mc2-miot.country_code-81 = JP +option.zhimi.heater.mc2-miot.country_code-82 = KR +option.zhimi.heater.mc2-miot.country_code-852 = HK +option.zhimi.heater.mc2-miot.country_code-86 = CN +option.zhimi.heater.mc2-miot.country_code-886 = TW +option.zhimi.heater.mc2-miot.fault-0 = No Error +option.zhimi.heater.mc2-miot.fault-1 = NTC Connect Error +option.zhimi.heater.mc2-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.mc2-miot.fault-3 = EEPROM Error +option.zhimi.heater.mc2-miot.fault-4 = Multi Errors +option.zhimi.heater.na1-miot.brightness-0 = Bright +option.zhimi.heater.na1-miot.brightness-1 = Dark +option.zhimi.heater.na1-miot.brightness-2 = Extinguished +option.zhimi.heater.na1-miot.fault-0 = No Error +option.zhimi.heater.na1-miot.fault-1 = NTC Connect Error +option.zhimi.heater.na1-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.na1-miot.fault-3 = EEPROM Error +option.zhimi.heater.na1-miot.fault-4 = Multi Errors +option.zhimi.heater.na1-miot.heat_level-1 = High +option.zhimi.heater.na1-miot.heat_level-2 = Low +option.zhimi.heater.na1-miot.mode-0 = Fan not swing +option.zhimi.heater.na1-miot.mode-1 = Fan swing +option.zhimi.heater.nb1-miot.brightness-0 = Bright +option.zhimi.heater.nb1-miot.brightness-1 = Dark +option.zhimi.heater.nb1-miot.brightness-2 = Extinguished +option.zhimi.heater.nb1-miot.country_code-0 = Unknown +option.zhimi.heater.nb1-miot.country_code-1 = US +option.zhimi.heater.nb1-miot.country_code-33 = FR +option.zhimi.heater.nb1-miot.country_code-44 = EU +option.zhimi.heater.nb1-miot.country_code-7 = RU +option.zhimi.heater.nb1-miot.country_code-81 = JP +option.zhimi.heater.nb1-miot.country_code-82 = KR +option.zhimi.heater.nb1-miot.country_code-852 = HK +option.zhimi.heater.nb1-miot.country_code-86 = CN +option.zhimi.heater.nb1-miot.country_code-886 = TW +option.zhimi.heater.nb1-miot.fault-0 = No Error +option.zhimi.heater.nb1-miot.fault-1 = NTC Connect Error +option.zhimi.heater.nb1-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.nb1-miot.fault-3 = EEPROM Error +option.zhimi.heater.nb1-miot.fault-4 = Multi Errors +option.zhimi.heater.nb1-miot.heat_level-1 = High +option.zhimi.heater.nb1-miot.heat_level-2 = Low +option.zhimi.heater.nb1-miot.mode-0 = Fan not swing +option.zhimi.heater.nb1-miot.mode-1 = Fan swing +option.zhimi.heater.za2-miot.brightness-0 = Bright +option.zhimi.heater.za2-miot.brightness-1 = Dark +option.zhimi.heater.za2-miot.brightness-2 = Extinguished +option.zhimi.heater.za2-miot.fault-0 = No Error +option.zhimi.heater.za2-miot.fault-1 = NTC Connect Error +option.zhimi.heater.za2-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.za2-miot.fault-3 = EEPROM Error +option.zhimi.heater.za2-miot.fault-4 = Multi Errors +option.zhimi.heater.zb1-miot.brightness-0 = Bright +option.zhimi.heater.zb1-miot.brightness-1 = Dark +option.zhimi.heater.zb1-miot.brightness-2 = Extinguished +option.zhimi.heater.zb1-miot.country-code-0 = Unknown +option.zhimi.heater.zb1-miot.country-code-1 = US +option.zhimi.heater.zb1-miot.country-code-33 = FR +option.zhimi.heater.zb1-miot.country-code-44 = EU +option.zhimi.heater.zb1-miot.country-code-7 = RU +option.zhimi.heater.zb1-miot.country-code-81 = JP +option.zhimi.heater.zb1-miot.country-code-82 = KR +option.zhimi.heater.zb1-miot.country-code-852 = HK +option.zhimi.heater.zb1-miot.country-code-86 = CN +option.zhimi.heater.zb1-miot.country-code-886 = TW +option.zhimi.heater.zb1-miot.fault-0 = No Error +option.zhimi.heater.zb1-miot.fault-1 = NTC Connect Error +option.zhimi.heater.zb1-miot.fault-2 = High Temperature Alarm +option.zhimi.heater.zb1-miot.fault-3 = EEPROM Error +option.zhimi.heater.zb1-miot.fault-4 = Multi Errors +option.zhimi.humidifier.ca4.ButtonPressed-0 = none +option.zhimi.humidifier.ca4.ButtonPressed-1 = led +option.zhimi.humidifier.ca4.ButtonPressed-2 = power +option.zhimi.humidifier.ca4.bright-0 = Dark +option.zhimi.humidifier.ca4.bright-1 = Dimmed +option.zhimi.humidifier.ca4.bright-2 = Brightest +option.zhimi.humidifier.ca4.mode-0 = Auto +option.zhimi.humidifier.ca4.mode-1 = Silent +option.zhimi.humidifier.ca4.mode-2 = Normal +option.zhimi.humidifier.ca4.mode-3 = Maximum + diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ReadmeHelper.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ReadmeHelper.java index 353fc1078883e..440c142ad12bb 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ReadmeHelper.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ReadmeHelper.java @@ -12,7 +12,10 @@ */ package org.openhab.binding.miio.internal; +import static org.openhab.binding.miio.internal.MiIoBindingConstants.*; + import java.io.File; +import java.io.FileFilter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; @@ -24,6 +27,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -59,6 +65,7 @@ public class ReadmeHelper { private static final String BASEFILE = "./README.base.md"; private static final String OUTPUTFILE = "./README.md"; private static final String DEVICE_NAMES_FILE = "./src/main/resources/misc/device_names.json"; + private static final String I18N_CHANNEL_FILE = "./src/main/resources/OH-INF/i18n/basic.properties"; private static final boolean UPDATE_OPTION_MAPPING_README_COMMENTS = true; @Disabled @@ -71,7 +78,6 @@ public static void main(String[] args) { StringWriter channelList = rm.channelList(); LOGGER.info("## Creating Item Files for miio:basic devices"); StringWriter itemFileExamples = rm.itemFileExamples(); - LOGGER.info("## Done"); try { String baseDoc = new String(Files.readAllBytes(Paths.get(BASEFILE)), StandardCharsets.UTF_8); String newDoc = baseDoc.replaceAll("!!!devices", deviceList.toString()) @@ -79,8 +85,34 @@ public static void main(String[] args) { .replaceAll("!!!itemFileExamples", itemFileExamples.toString()); Files.write(Paths.get(OUTPUTFILE), newDoc.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { - LOGGER.warn("IO exception", e); + LOGGER.warn("IO exception writing readme", e); + } + + LOGGER.info("## Creating i18n entries for devices and miio:basic channels"); + StringBuilder sb = new StringBuilder(); + sb.append("# Automatic created list by miio readme maker for miio devices & database channels\n\n"); + sb.append("# Devices\n\n"); + for (MiIoDevices d : Arrays.asList(MiIoDevices.values())) { + sb.append(I18N_THING_PREFIX); + sb.append(d.getModel()); + sb.append(" = "); + sb.append(d.getDescription()); + sb.append("\n"); + } + sb.append("\n# Channels\n\n"); + for (Entry e : sortByKeys(rm.createI18nEntries()).entrySet()) { + sb.append(e.getKey()); + sb.append(" = "); + sb.append(e.getValue()); + sb.append("\n"); + } + sb.append("\n"); + try { + Files.write(Paths.get(I18N_CHANNEL_FILE), sb.toString().getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + LOGGER.warn("IO exception creating i18n file", e); } + LOGGER.info("## Done"); } private StringWriter deviceList() { @@ -163,25 +195,21 @@ private StringWriter channelList() { } public static String readmeOptionMapping(MiIoBasicChannel channel, String model) { - StateDescriptionDTO stateDescription = channel.getStateDescription(); - if (stateDescription != null && stateDescription.getOptions() != null) { - final List options = stateDescription.getOptions(); - if (options != null && !options.isEmpty()) { - StringBuilder mapping = new StringBuilder(); - mapping.append("Value mapping `["); - options.forEach((option) -> { - mapping.append(String.format("\"%s\"=\"%s\",", String.valueOf(option.value), - String.valueOf(option.label))); - }); - mapping.deleteCharAt(mapping.length() - 1); - mapping.append("]`"); - String newComment = mapping.toString(); - if (!channel.getReadmeComment().contentEquals(newComment)) { - LOGGER.info("Channel {} - {} readme comment updated to '{}'", model, channel.getChannel(), - newComment); - } - return newComment; + final List options = getChannelOptions(channel); + if (!options.isEmpty()) { + StringBuilder mapping = new StringBuilder(); + mapping.append("Value mapping `["); + options.forEach((option) -> { + mapping.append( + String.format("\"%s\"=\"%s\",", String.valueOf(option.value), String.valueOf(option.label))); + }); + mapping.deleteCharAt(mapping.length() - 1); + mapping.append("]`"); + String newComment = mapping.toString(); + if (!channel.getReadmeComment().contentEquals(newComment)) { + LOGGER.info("Channel {} - {} readme comment updated to '{}'", model, channel.getChannel(), newComment); } + return newComment; } return channel.getReadmeComment(); } @@ -264,25 +292,80 @@ private List findDatabaseEntrys() { List arrayList = new ArrayList<>(); String path = "./src/main/resources/database/"; File dir = new File(path); - File[] filesList = dir.listFiles(); + FileFilter fileFilter = file -> !file.isDirectory() && file.getName().toLowerCase().endsWith(".json"); + File[] filesList = dir.listFiles(fileFilter); + if (filesList == null) { + return arrayList; + } for (File file : filesList) { - if (file.isFile()) { - try { - JsonObject deviceMapping = convertFileToJSON(path + file.getName()); - Gson gson = new GsonBuilder().serializeNulls().create(); - @Nullable - MiIoBasicDevice devdb = gson.fromJson(deviceMapping, MiIoBasicDevice.class); - if (devdb != null) { - arrayList.add(devdb); - } - } catch (Exception e) { - LOGGER.info("Error while searching in database '{}': {}", file.getName(), e.getMessage()); + try { + JsonObject deviceMapping = convertFileToJSON(path + file.getName()); + Gson gson = new GsonBuilder().serializeNulls().create(); + @Nullable + MiIoBasicDevice devdb = gson.fromJson(deviceMapping, MiIoBasicDevice.class); + if (devdb != null) { + arrayList.add(devdb); } + } catch (Exception e) { + LOGGER.info("Error while searching in database '{}': {}", file.getName(), e.getMessage()); } } return arrayList; } + public static List getChannelOptions(MiIoBasicChannel channel) { + StateDescriptionDTO state = channel.getStateDescription(); + if (state != null) { + List options = state.getOptions(); + if (options != null) { + return options; + } + } + return List.of(); + } + + private Map createI18nEntries() { + Map i18nEntries = new HashMap<>(); + String path = "./src/main/resources/database/"; + File dir = new File(path); + FileFilter fileFilter = file -> !file.isDirectory() && file.getName().toLowerCase().endsWith(".json"); + File[] filesList = dir.listFiles(fileFilter); + if (filesList == null) { + return i18nEntries; + } + for (File file : filesList) { + try { + String key = file.getName().toLowerCase().split("json")[0]; + JsonObject deviceMapping = convertFileToJSON(path + file.getName()); + Gson gson = new GsonBuilder().serializeNulls().create(); + @Nullable + MiIoBasicDevice devdb = gson.fromJson(deviceMapping, MiIoBasicDevice.class); + if (devdb == null) { + continue; + } + for (MiIoBasicChannel channel : devdb.getDevice().getChannels()) { + i18nEntries.put(I18N_CHANNEL_PREFIX + key + channel.getChannel(), channel.getFriendlyName()); + List options = getChannelOptions(channel); + for (OptionsValueListDTO channelOption : options) { + String optionValue = channelOption.value; + String optionLabel = channelOption.label; + if (optionValue != null && optionLabel != null) { + i18nEntries.put(I18N_OPTION_PREFIX + key + channel.getChannel() + "-" + optionValue, + optionLabel); + } + } + } + } catch (Exception e) { + LOGGER.info("Error while searching in database '{}': {}", file.getName(), e.getMessage()); + } + } + return i18nEntries; + } + + public static Map sortByKeys(Map map) { + return new TreeMap<>(map); + } + private static String minLengthString(String string, int length) { return String.format("%-" + length + "s", string); } @@ -290,7 +373,6 @@ private static String minLengthString(String string, int length) { JsonObject convertFileToJSON(String fileName) { // Read from File to String JsonObject jsonObject = new JsonObject(); - try { JsonElement jsonElement = JsonParser.parseReader(new FileReader(fileName)); jsonObject = jsonElement.getAsJsonObject(); From 61be0dd6755ec3312eae15835fb731e50d6c05a8 Mon Sep 17 00:00:00 2001 From: Matthew Davies <84205523+raveydavies@users.noreply.github.com> Date: Sat, 4 Dec 2021 10:49:22 +0100 Subject: [PATCH 162/361] [venstarthermostat] more functions issue enhancement 10823 (#11305) * Adding several functions to binding to mimic local API Signed-off-by: raveydavies * Adding functionality according to API Signed-off-by: raveydavies * Updating Read me with new capability Signed-off-by: raveydavies * Additional commit with requested changes to pull request Signed-off-by: raveydavies * Updates to address all comments on previous commit. Signed-off-by: raveydavies * Updates as requested in review. Signed-off-by: raveydavies * Corrections for check style warnings Signed-off-by: raveydavies * Updates to address feedback from lolodomo. Signed-off-by: raveydavies * Changes to address feedback from lolodomo's review Signed-off-by: raveydavies * FanState changed to Switch, Exception handling added as per review. Signed-off-by: raveydavies Signed-off-by: Michael Schmidt --- .../README.md | 102 +++++++-- .../VenstarThermostatBindingConstants.java | 18 ++ .../internal/dto/VenstarAwayMode.java | 2 +- .../dto/VenstarAwayModeSerializer.java | 6 +- .../internal/dto/VenstarFanMode.java | 59 ++++++ .../dto/VenstarFanModeSerializer.java | 40 ++++ .../internal/dto/VenstarFanState.java | 59 ++++++ .../dto/VenstarFanStateSerializer.java | 40 ++++ .../internal/dto/VenstarInfoData.java | 67 ++++-- .../internal/dto/VenstarRuntime.java | 96 +++++++++ .../internal/dto/VenstarRuntimeData.java | 45 ++++ .../internal/dto/VenstarScheduleMode.java | 59 ++++++ .../dto/VenstarScheduleModeSerializer.java | 39 ++++ .../internal/dto/VenstarSchedulePart.java | 62 ++++++ .../dto/VenstarSchedulePartSerializer.java | 39 ++++ .../internal/dto/VenstarSystemMode.java | 5 +- .../dto/VenstarSystemModeSerializer.java | 7 +- .../internal/dto/VenstarSystemState.java | 5 +- .../dto/VenstarSystemStateSerializer.java | 7 +- .../handler/VenstarThermostatHandler.java | 192 +++++++++++++---- .../resources/OH-INF/thing/thing-types.xml | 193 ++++++++++++++++++ 21 files changed, 1064 insertions(+), 78 deletions(-) create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanMode.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanModeSerializer.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanState.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanStateSerializer.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntime.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntimeData.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleMode.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleModeSerializer.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePart.java create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePartSerializer.java diff --git a/bundles/org.openhab.binding.venstarthermostat/README.md b/bundles/org.openhab.binding.venstarthermostat/README.md index 1e82441aa1724..751460a23bd5c 100644 --- a/bundles/org.openhab.binding.venstarthermostat/README.md +++ b/bundles/org.openhab.binding.venstarthermostat/README.md @@ -41,20 +41,63 @@ After adding the Inbox item, enter the user name and password from the physical ### Channels -| Channel | Type | Description | Notes | -|--------------------|--------------------|------------------------------|--------------------------------------------------------| -| awayMode | String | Home or Away Mode | | -| awayModeRaw | Number | Away Mode Raw (Read Only) | 0 (Home) 1 (Away) | -| systemMode | String | System Mode | | -| systemModeRaw | Number | System Mode Raw (Read Only) | 0 (Off) 1 (Heat) 2 (Cool) 3 (Auto) | -| systemState | String | System State (Read Only) | | -| systemStateRaw | Number | System State Raw (Read Only) | 0 (Idle) 1 (Heating) 2 (Cooling) 3 (Lockout) 4 (Error) | -| heatingSetpoint | Number:Temperature | Heating Set Point | | -| coolingSetpoint | Number:Temperature | Cooling Set Point | | -| temperature | Number:Temperature | Current Temperature | | -| outdoorTemperature | Number:Temperature | Outdoor Temperature | | -| humidity | Number | Humidity | | - +| Channel | Type | Description | Notes | +|--------------------|--------------------|---------------------------------------|--------------------------------------------------------| +| awayMode | String | Home or Away Mode | | +| awayModeRaw | Number | Away Mode Raw (Read Only) | 0 (Home) 1 (Away) | +| systemMode | String | System Mode | | +| systemModeRaw | Number | System Mode Raw (Read Only) | 0 (Off) 1 (Heat) 2 (Cool) 3 (Auto) | +| systemState | String | System State (Read Only) | | +| systemStateRaw | Number | System State Raw (Read Only) | 0 (Idle) 1 (Heating) 2 (Cooling) 3 (Lockout) 4 (Error) | +| heatingSetpoint | Number:Temperature | Heating Set Point | | +| coolingSetpoint | Number:Temperature | Cooling Set Point | | +| temperature | Number:Temperature | Current Temperature | | +| outdoorTemperature | Number:Temperature | Outdoor Temperature | | +| humidity | Number | Humidity | | +| fanMode | String | Fan Mode | | +| fanModeRaw | Number | Fan Mode Raw (Read Only) | 0 (Auto) 1 (On) | +| fanState | String | Fan State (Read Only) | | +| fanStateRaw | Number | Fan State Raw (Read Only) | 0 (Off) 1 (On) | +| scheduleMode | String | Current Schedule Mode | | +| scheduleModeRaw | Number | Current Schedule mode Raw (Read Only) | 0(Disabled) 1(Enabled) | +| schedulePart | String | Current Schedule Part | | +| schedulePartRaw | Number | Schedule Part Raw (Read Only) | 0(Morning) 1(Day) 2(Evening) 3 (Night) 255 (Inactive) | + + +### Runtime data + +The Venstar thermostat provides data about how many minutes the system has been running in each of the different modes (heat1, heat2, cool1, cool2, aux1, aux2, free cool) every day for the last 7 days. +A time stamp is provided with each runtime data set which represents the end of each day. +The binding reads the runtime data and time stamps and provides them all as separate channels. + +| Channel | Type | Description | Notes | +|------------------------|----------------------|----------------------------------------------|------------------------------------------------------------| +| timestampDay0 | DateTime | Time Stamp of last runtime update | This is always the current time today | +| timestampDay1 | DateTime | Time Stamp of 00:00, end of yesterday | This represents the end of 1 day ago | +| timestampDay2 | DateTime | Time Stamp of 00:00 end of 2 days ago | This represents the end of 2 days ago | +| timestampDay3 | DateTime | Time Stamp of 00:00, end of 3 days ago | This represents the end of 3 days ago | +| timestampDay4 | DateTime | Time Stamp of 00:00, end of 4 days ago | This represents the end of 4 days ago | +| timestampDay5 | DateTime | Time Stamp of 00:00, end of 5 days ago | This represents the end of 5 days ago | +| timestampDay6 | DateTime | Time Stamp of 00:00, end of 6 days ago | This represents the end of 6 days ago | +| heat1RuntimeDay0 | Number:Dimensionless | Runtime in heat1 mode (minutes) today | This is the runtime between the Day 1 and Day 0 timestamps | +| heat1RuntimeDay1 | Number:Dimensionless | Runtime in heat1 mode (minutes) yesterday | This is the runtime between the Day 2 and Day 1 timestamps | +| heat1RuntimeDay2 | Number:Dimensionless | Runtime in heat1 mode (minutes) 2 days ago | This is the runtime between the Day 3 and Day 2 timestamps | +| heat1RuntimeDay3 | Number:Dimensionless | Runtime in heat1 mode (minutes) 3 days ago | This is the runtime between the Day 4 and Day 3 timestamps | +| heat1RuntimeDay4 | Number:Dimensionless | Runtime in heat1 mode (minutes) 4 days ago | This is the runtime between the Day 5 and Day 4 timestamps | +| heat1RuntimeDay5 | Number:Dimensionless | Runtime in heat1 mode (minutes) 5 days ago | This is the runtime between the Day 6 and Day 5 timestamps | +| heat1RuntimeDay6 | Number:Dimensionless | Runtime in heat1 mode (minutes) 6 days ago | This is the runtime in the 24hrs up to the Day 6 timestamp | +| | | | | +| heat2RuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in heat2 mode (minutes) | | +| | | | | +| cool1RuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in cool1 mode (minutes) | | +| | | | | +| cool2RuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in cool2 mode (minutes) | | +| | | | | +| aux1RuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in aux1 mode (minutes) | | +| | | | | +| aux2RuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in aux2 mode (minutes) | | +| | | | | +| freeCoolRuntimeDay0..6 | Number:Dimensionless | Similar Runtimes in free cool mode (minutes) | | ## Example @@ -71,10 +114,22 @@ Thing venstarthermostat:colorTouchThermostat:001122334455 "Venstar Thermostat (G Number:Temperature Guest_HVAC_Temperature "Temperature [%d °F]" {channel="venstarthermostat:colorTouchThermostat:001122334455:temperature"} Number:Temperature Guest_HVAC_HeatSetpoint "Heat Setpoint [%d °F]" {channel="venstarthermostat:colorTouchThermostat:001122334455:heatingSetpoint"} Number:Temperature Guest_HVAC_CoolSetpoint "Cool Setpoint [%d °F]" {channel="venstarthermostat:colorTouchThermostat:001122334455:coolingSetpoint"} -Number Guest_HVAC_Mode "Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:systemMode"} +String Guest_HVAC_Mode "System Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:systemMode"} Number Guest_HVAC_Humidity "Humidity [%d %%]" {channel="venstarthermostat:colorTouchThermostat:001122334455:humidity"} -Number Guest_HVAC_State "State [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:systemState"} -Number Guest_Away_Mode "Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:awayMode"} +String Guest_HVAC_State "State [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:systemState"} +String Guest_Away_Mode "Away Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:awayMode"} +String Guest_Fan_Mode "Fan Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:fanMode"} +String Guest_Fan_State "Fan State [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:fanState"} +String Guest_Schedule_Mode "Schedule Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:scheduleMode"} +String Guest_Schedule_Part "Schedule Part [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:schedulePart"} +DateTime Guest_timestampDay0 "Date/Time Last Update [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:timestampDay0"} +Number Guest_heat1RuntimeDay0 "Heat1 Day0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:heat1RuntimeDay0"} +Number Guest_heat2RuntimeDay0 "Heat2 Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:heat2RuntimeDay0"} +Number Guest_cool1RuntimeDay0 "Cool1 Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:cool1RuntimeDay0"} +Number Guest_cool2RuntimeDay0 "Cool2 Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:cool2RuntimeDay0"} +Number Guest_aux1RuntimeDay0 "Aux1 Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:aux1RuntimeDay0"} +Number Guest_aux2RuntimeDay0 "Aux2 Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:aux2RuntimeDay0"} +Number Guest_freeCoolRuntimeDay0 "Free Cool Day 0 Run Time [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:freeCoolRuntimeDay0"} ``` ### thermostat.sitemap @@ -88,6 +143,19 @@ sitemap demo label="Venstar Color Thermostat Demo" Switch item=Guest_HVAC_Mode mappings=[off=Off,heat=Heat,cool=Cool,auto=Auto] Switch item=Guest_Away_Mode mappings=[home=Home,away=Away] Text item=Guest_HVAC_State + Switch item=Guest_Fan_Mode mappings=[auto=Auto, on=On] + Text item=Guest_Fan_State + Switch item=Guest_Schedule_Mode mappings=[enabled=Enabled,disabled=Disabled] + Text item=Guest_Schedule_Part + Text item=Guest_timestampDay0 + Text item=Guest_heat1RuntimeDay0 + Text item=Guest_heat2RuntimeDay0 + Text item=Guest_cool1RuntimeDay0 + Text item=Guest_cool2RuntimeDay0 + Text item=Guest_aux1RuntimeDay0 + Text item=Guest_aux2RuntimeDay0 + Text item=Guest_freeCoolRuntimeDay0 + } } ``` diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/VenstarThermostatBindingConstants.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/VenstarThermostatBindingConstants.java index 87378b210b990..035050be3cacb 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/VenstarThermostatBindingConstants.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/VenstarThermostatBindingConstants.java @@ -24,6 +24,7 @@ * * @author William Welliver - Initial contribution * @author Matthew Davies - added awayMode and awayModeRaw to include thermostat away mode in binding + * @author Matthew Davies - added more binding functionality to get close to the API functionality */ @NonNullByDefault public class VenstarThermostatBindingConstants { @@ -47,6 +48,23 @@ public class VenstarThermostatBindingConstants { public static final String CHANNEL_SYSTEM_MODE_RAW = "systemModeRaw"; public static final String CHANNEL_AWAY_MODE = "awayMode"; public static final String CHANNEL_AWAY_MODE_RAW = "awayModeRaw"; + public static final String CHANNEL_FAN_MODE = "fanMode"; + public static final String CHANNEL_FAN_MODE_RAW = "fanModeRaw"; + public static final String CHANNEL_FAN_STATE = "fanState"; + public static final String CHANNEL_FAN_STATE_RAW = "fanStateRaw"; + public static final String CHANNEL_SCHEDULE_MODE = "scheduleMode"; + public static final String CHANNEL_SCHEDULE_MODE_RAW = "scheduleModeRaw"; + public static final String CHANNEL_SCHEDULE_PART = "schedulePart"; + public static final String CHANNEL_SCHEDULE_PART_RAW = "schedulePartRaw"; + public static final String CHANNEL_TIMESTAMP_RUNTIME_DAY = "timestampDay"; + public static final String CHANNEL_HEAT1_RUNTIME_DAY = "heat1RuntimeDay"; + public static final String CHANNEL_HEAT2_RUNTIME_DAY = "heat2RuntimeDay"; + public static final String CHANNEL_COOL1_RUNTIME_DAY = "cool1RuntimeDay"; + public static final String CHANNEL_COOL2_RUNTIME_DAY = "cool2RuntimeDay"; + public static final String CHANNEL_AUX1_RUNTIME_DAY = "aux1RuntimeDay"; + public static final String CHANNEL_AUX2_RUNTIME_DAY = "aux2RuntimeDay"; + public static final String CHANNEL_FC_RUNTIME_DAY = "freeCoolRuntimeDay"; + // add query/runtimes and query/alerts - these will need an additional class similar to Venstar.infodata - more work public static final String CONFIG_USERNAME = "username"; public static final String CONFIG_PASSWORD = "password"; diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayMode.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayMode.java index 589929bfc295c..bf2bf13140def 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayMode.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayMode.java @@ -44,7 +44,7 @@ public String friendlyName() { return friendlyName; } - public static VenstarAwayMode fromInt(int mode) { + public static VenstarAwayMode fromInt(int mode) throws IllegalArgumentException { for (VenstarAwayMode am : values()) { if (am.mode == mode) { return am; diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayModeSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayModeSerializer.java index 8ae818805d457..912d95f7d1361 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayModeSerializer.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarAwayModeSerializer.java @@ -30,6 +30,10 @@ public class VenstarAwayModeSerializer implements JsonDeserializer { + @Override + public VenstarFanMode deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + int key = element.getAsInt(); + try { + return VenstarFanMode.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanState.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanState.java new file mode 100644 index 0000000000000..f63034d1bfd20 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanState.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link VenstarFanState} represents the state of the fan returned + * from the REST API. + * + * @author Matthew Davies - Initial contribution + */ +@NonNullByDefault +public enum VenstarFanState { + OFF(0, "off", "Off"), + ON(1, "on", "On"); + + private int state; + private String name; + private String friendlyName; + + VenstarFanState(int state, String name, String friendlyName) { + this.state = state; + this.name = name; + this.friendlyName = friendlyName; + } + + public int state() { + return state; + } + + public String stateName() { + return name; + } + + public String friendlyName() { + return friendlyName; + } + + public static VenstarFanState fromInt(int state) throws IllegalArgumentException { + for (VenstarFanState fs : values()) { + if (fs.state == state) { + return fs; + } + } + + throw (new IllegalArgumentException("Invalid fan state " + state)); + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanStateSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanStateSerializer.java new file mode 100644 index 0000000000000..c59023a6087fd --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarFanStateSerializer.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import java.lang.reflect.Type; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +/** + * The {@link VenstarFanStateSerializer} parses system mode values + * from the REST API JSON. + * + * @author Matthew Davies - Initial contribution + */ +public class VenstarFanStateSerializer implements JsonDeserializer { + @Override + public VenstarFanState deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + + int key = element.getAsInt(); + try { + return VenstarFanState.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarInfoData.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarInfoData.java index b5a4aa9540d03..f123cbd84d5c8 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarInfoData.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarInfoData.java @@ -19,26 +19,35 @@ * @author Matthew Davies - added VenstarAwayMode to include away mode in binding */ public class VenstarInfoData { - double cooltemp; - double heattemp; - - VenstarSystemState state; - VenstarSystemMode mode; - VenstarAwayMode away; - int tempunits; + private double cooltemp; + private double heattemp; + + private VenstarSystemState state; + private VenstarSystemMode mode; + private VenstarAwayMode away; + private VenstarFanMode fan; + private VenstarFanState fanstate; + private VenstarScheduleMode schedule; + private VenstarSchedulePart schedulepart; + private int tempunits; public VenstarInfoData() { super(); } public VenstarInfoData(double cooltemp, double heattemp, VenstarSystemState state, VenstarSystemMode mode, - VenstarAwayMode away) { + VenstarAwayMode away, VenstarFanMode fan, VenstarFanState fanstate, VenstarScheduleMode schedule, + VenstarSchedulePart schedulepart) { super(); this.cooltemp = cooltemp; this.heattemp = heattemp; this.state = state; this.mode = mode; this.away = away; + this.fan = fan; + this.fanstate = fanstate; + this.schedule = schedule; + this.schedulepart = schedulepart; } public double getCooltemp() { @@ -57,19 +66,19 @@ public void setHeattemp(double heattemp) { this.heattemp = heattemp; } - public VenstarSystemState getState() { + public VenstarSystemState getSystemState() { return state; } - public void setState(VenstarSystemState state) { + public void setSystemState(VenstarSystemState state) { this.state = state; } - public VenstarSystemMode getMode() { + public VenstarSystemMode getSystemMode() { return mode; } - public void setMode(VenstarSystemMode mode) { + public void setSystemMode(VenstarSystemMode mode) { this.mode = mode; } @@ -81,11 +90,43 @@ public void setTempunits(int tempunits) { this.tempunits = tempunits; } - public VenstarAwayMode getAway() { + public VenstarAwayMode getAwayMode() { return away; } public void setAwayMode(VenstarAwayMode away) { this.away = away; } + + public VenstarFanMode getFanMode() { + return fan; + } + + public void setFanMode(VenstarFanMode fan) { + this.fan = fan; + } + + public VenstarFanState getFanState() { + return fanstate; + } + + public void setFanState(VenstarFanState fanstate) { + this.fanstate = fanstate; + } + + public VenstarScheduleMode getScheduleMode() { + return schedule; + } + + public void setScheduleMode(VenstarScheduleMode schedule) { + this.schedule = schedule; + } + + public VenstarSchedulePart getSchedulePart() { + return schedulepart; + } + + public void setSchedulePart(VenstarSchedulePart schedulepart) { + this.schedulepart = schedulepart; + } } diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntime.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntime.java new file mode 100644 index 0000000000000..80ab2e48b6328 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntime.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link VenstarRunTime} represents one Runtime from the RuntimeData returned from the REST API + * + * @author Matthew Davies - Initial contribution + */ +@NonNullByDefault +public class VenstarRuntime { + private long ts; + private int heat1; + private int heat2; + private int cool1; + private int cool2; + private int aux1; + private int aux2; + private int fc; + + public long getTimeStamp() { + return ts; + } + + public void setTimeStamp(long ts) { + this.ts = ts; + } + + public int getHeat1Runtime() { + return heat1; + } + + public void setHeat1Runtime(int heat1) { + this.heat1 = heat1; + } + + public int getHeat2Runtime() { + return heat2; + } + + public void setHeat2Runtime(int heat2) { + this.heat2 = heat2; + } + + public int getCool1Runtime() { + return cool1; + } + + public void setCool1Runtime(int cool1) { + this.cool1 = cool1; + } + + public int getCool2Runtime() { + return cool2; + } + + public void setCool2Runtime(int cool2) { + this.cool2 = cool2; + } + + public int getAux1Runtime() { + return aux1; + } + + public void setAux1Runtime(int aux1) { + this.aux1 = aux1; + } + + public int getAux2Runtime() { + return aux2; + } + + public void setAux2Runtime(int aux2) { + this.aux2 = aux2; + } + + public int getFreeCoolRuntime() { + return fc; + } + + public void setFreeCoolRuntime(int fc) { + this.fc = fc; + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntimeData.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntimeData.java new file mode 100644 index 0000000000000..c2b86ceabfcb7 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarRuntimeData.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link VenstarRunTimeData} represents the list of runtimes returned from the REST API. + * + * @author Matthew Davies - Initial contribution + */ +@NonNullByDefault +public class VenstarRuntimeData { + private List runtimes; + + public VenstarRuntimeData() { + super(); + runtimes = List.of(); + } + + public VenstarRuntimeData(List runtimes) { + super(); + this.runtimes = runtimes; + } + + public List getRuntimes() { + return runtimes; + } + + public void setRuntimes(List runtimes) { + this.runtimes = runtimes; + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleMode.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleMode.java new file mode 100644 index 0000000000000..ef2126feeed3b --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleMode.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link VenstarScheduleMode} represents the value of the schedule mode returned + * from the REST API. + * + * @author Matthew Davies - Initial contribution + */ +@NonNullByDefault +public enum VenstarScheduleMode { + DISABLED(0, "disabled", "Disabled"), + ENABLED(1, "enabled", "Enabled"); + + private int mode; + private String name; + private String friendlyName; + + VenstarScheduleMode(int mode, String name, String friendlyName) { + this.mode = mode; + this.name = name; + this.friendlyName = friendlyName; + } + + public int mode() { + return mode; + } + + public String modeName() { + return name; + } + + public String friendlyName() { + return friendlyName; + } + + public static VenstarScheduleMode fromInt(int mode) throws IllegalArgumentException { + for (VenstarScheduleMode sm : values()) { + if (sm.mode == mode) { + return sm; + } + } + + throw (new IllegalArgumentException("Invalid schedule mode " + mode)); + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleModeSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleModeSerializer.java new file mode 100644 index 0000000000000..3b5a08e06d763 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarScheduleModeSerializer.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import java.lang.reflect.Type; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +/** + * The {@link VenstarScheduleModeSerializer} parses schedule mode values + * from the REST API JSON. + * + * @author Matthew Davies - Initial contribution + */ +public class VenstarScheduleModeSerializer implements JsonDeserializer { + @Override + public VenstarScheduleMode deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + int key = element.getAsInt(); + try { + return VenstarScheduleMode.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePart.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePart.java new file mode 100644 index 0000000000000..379f6fa801e88 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePart.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link VenstarSchedulePart} represents the schedule part (part of day) returned + * from the REST API. + * + * @author Matthew Davies - Initial contribution + */ +@NonNullByDefault +public enum VenstarSchedulePart { + MORNING(0, "morning", "Morning"), + DAY(1, "day", "Day"), + EVENING(2, "evening", "Evening"), + NIGHT(3, "night", "Night"), + INACTIVE(255, "inactive", "Inactive"); + + private int part; + private String name; + private String friendlyName; + + VenstarSchedulePart(int part, String name, String friendlyName) { + this.part = part; + this.name = name; + this.friendlyName = friendlyName; + } + + public int part() { + return part; + } + + public String partName() { + return name; + } + + public String friendlyName() { + return friendlyName; + } + + public static VenstarSchedulePart fromInt(int part) throws IllegalArgumentException { + for (VenstarSchedulePart sp : values()) { + if (sp.part == part) { + return sp; + } + } + + throw (new IllegalArgumentException("Invalid schedule part " + part)); + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePartSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePartSerializer.java new file mode 100644 index 0000000000000..5a7f67f90673f --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSchedulePartSerializer.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.venstarthermostat.internal.dto; + +import java.lang.reflect.Type; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +/** + * The {@link VenstarSchedulePartSerializer} parses Schedule Part values + * from the REST API JSON. + * + * @author Matthew Davies - Initial contribution + */ +public class VenstarSchedulePartSerializer implements JsonDeserializer { + @Override + public VenstarSchedulePart deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + int key = element.getAsInt(); + try { + return VenstarSchedulePart.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } +} diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemMode.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemMode.java index 680354958e567..357c3a4083736 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemMode.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemMode.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.venstarthermostat.internal.dto; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link VenstarSystemMode} represents the value of the system mode returned * from the REST API. * * @author William Welliver - Initial contribution */ +@NonNullByDefault public enum VenstarSystemMode { OFF(0, "off", "Off"), HEAT(1, "heat", "Heat"), @@ -46,7 +49,7 @@ public String friendlyName() { return friendlyName; } - public static VenstarSystemMode fromInt(int mode) { + public static VenstarSystemMode fromInt(int mode) throws IllegalArgumentException { for (VenstarSystemMode sm : values()) { if (sm.mode == mode) { return sm; diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemModeSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemModeSerializer.java index cbb3a104a19fb..acb13fb33f05b 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemModeSerializer.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemModeSerializer.java @@ -24,12 +24,17 @@ * from the REST API JSON. * * @author William Welliver - Initial contribution + * @author Matthew Davies - added IllegalArgumentException handling */ public class VenstarSystemModeSerializer implements JsonDeserializer { @Override public VenstarSystemMode deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) throws JsonParseException { int key = element.getAsInt(); - return VenstarSystemMode.fromInt(key); + try { + return VenstarSystemMode.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } } } diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemState.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemState.java index ec0e9e9403503..af4eceb58cbbf 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemState.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemState.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.venstarthermostat.internal.dto; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link VenstarSystemState} represents the value of the system state * returneda from the REST API. * * @author William Welliver - Initial contribution */ +@NonNullByDefault public enum VenstarSystemState { IDLE(0, "idle", "Idle"), HEATING(1, "heating", "Heating"), @@ -47,7 +50,7 @@ public String friendlyName() { return friendlyName; } - public static VenstarSystemState fromInt(int state) { + public static VenstarSystemState fromInt(int state) throws IllegalArgumentException { for (VenstarSystemState ss : values()) { if (ss.state == state) { return ss; diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemStateSerializer.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemStateSerializer.java index f7e1798d69570..79098cc91f660 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemStateSerializer.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/dto/VenstarSystemStateSerializer.java @@ -24,12 +24,17 @@ * from the REST API JSON. * * @author William Welliver - Initial contribution + * @author Matthew Davies - added IllegalArgumentException handling */ public class VenstarSystemStateSerializer implements JsonDeserializer { @Override public VenstarSystemState deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) throws JsonParseException { int key = element.getAsInt(); - return VenstarSystemState.fromInt(key); + try { + return VenstarSystemState.fromInt(key); + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } } } diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/handler/VenstarThermostatHandler.java b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/handler/VenstarThermostatHandler.java index 5041eaff9c062..03927e7337058 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/handler/VenstarThermostatHandler.java +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/java/org/openhab/binding/venstarthermostat/internal/handler/VenstarThermostatHandler.java @@ -20,6 +20,10 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -49,8 +53,18 @@ import org.openhab.binding.venstarthermostat.internal.VenstarThermostatConfiguration; import org.openhab.binding.venstarthermostat.internal.dto.VenstarAwayMode; import org.openhab.binding.venstarthermostat.internal.dto.VenstarAwayModeSerializer; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarFanMode; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarFanModeSerializer; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarFanState; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarFanStateSerializer; import org.openhab.binding.venstarthermostat.internal.dto.VenstarInfoData; import org.openhab.binding.venstarthermostat.internal.dto.VenstarResponse; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarRuntime; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarRuntimeData; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarScheduleMode; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarScheduleModeSerializer; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarSchedulePart; +import org.openhab.binding.venstarthermostat.internal.dto.VenstarSchedulePartSerializer; import org.openhab.binding.venstarthermostat.internal.dto.VenstarSensor; import org.openhab.binding.venstarthermostat.internal.dto.VenstarSensorData; import org.openhab.binding.venstarthermostat.internal.dto.VenstarSystemMode; @@ -58,7 +72,9 @@ import org.openhab.binding.venstarthermostat.internal.dto.VenstarSystemState; import org.openhab.binding.venstarthermostat.internal.dto.VenstarSystemStateSerializer; import org.openhab.core.config.core.status.ConfigStatusMessage; +import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; import org.openhab.core.library.unit.ImperialUnits; @@ -90,13 +106,12 @@ */ @NonNullByDefault public class VenstarThermostatHandler extends ConfigStatusThingHandler { - private static final int TIMEOUT_SECONDS = 30; private static final int UPDATE_AFTER_COMMAND_SECONDS = 2; - private Logger log = LoggerFactory.getLogger(VenstarThermostatHandler.class); private List sensorData = new ArrayList<>(); private VenstarInfoData infoData = new VenstarInfoData(); + private VenstarRuntimeData runtimeData = new VenstarRuntimeData(); private Map stateMap = Collections.synchronizedMap(new HashMap<>()); private @Nullable Future updatesTask; private @Nullable URL baseURL; @@ -112,7 +127,11 @@ public VenstarThermostatHandler(Thing thing) { httpClient = new HttpClient(new SslContextFactory.Client(true)); gson = new GsonBuilder().registerTypeAdapter(VenstarSystemState.class, new VenstarSystemStateSerializer()) .registerTypeAdapter(VenstarSystemMode.class, new VenstarSystemModeSerializer()) - .registerTypeAdapter(VenstarAwayMode.class, new VenstarAwayModeSerializer()).create(); + .registerTypeAdapter(VenstarAwayMode.class, new VenstarAwayModeSerializer()) + .registerTypeAdapter(VenstarFanMode.class, new VenstarFanModeSerializer()) + .registerTypeAdapter(VenstarFanState.class, new VenstarFanStateSerializer()) + .registerTypeAdapter(VenstarScheduleMode.class, new VenstarScheduleModeSerializer()) + .registerTypeAdapter(VenstarSchedulePart.class, new VenstarSchedulePartSerializer()).create(); log.trace("VenstarThermostatHandler for thing {}", getThing().getUID()); } @@ -168,25 +187,63 @@ public void handleCommand(ChannelUID channelUID, Command command) { setCoolingSetpoint(value); } else if (channelUID.getId().equals(CHANNEL_SYSTEM_MODE)) { VenstarSystemMode value; - if (command instanceof StringType) { - value = VenstarSystemMode.valueOf(((StringType) command).toString().toUpperCase()); - } else { - value = VenstarSystemMode.fromInt(((DecimalType) command).intValue()); + try { + if (command instanceof StringType) { + value = VenstarSystemMode.valueOf(((StringType) command).toString().toUpperCase()); + } else { + value = VenstarSystemMode.fromInt(((DecimalType) command).intValue()); + } + log.debug("Setting system mode to {}", value); + setSystemMode(value); + updateIfChanged(CHANNEL_SYSTEM_MODE_RAW, new StringType(value.toString())); + } catch (IllegalArgumentException e) { + log.warn("Invalid System Mode"); } - log.debug("Setting system mode to {}", value); - setSystemMode(value); - updateIfChanged(CHANNEL_SYSTEM_MODE_RAW, new StringType(value.toString())); } else if (channelUID.getId().equals(CHANNEL_AWAY_MODE)) { VenstarAwayMode value; - if (command instanceof StringType) { - value = VenstarAwayMode.valueOf(((StringType) command).toString().toUpperCase()); - } else { - value = VenstarAwayMode.fromInt(((DecimalType) command).intValue()); + try { + if (command instanceof StringType) { + value = VenstarAwayMode.valueOf(((StringType) command).toString().toUpperCase()); + } else { + value = VenstarAwayMode.fromInt(((DecimalType) command).intValue()); + } + log.debug("Setting away mode to {}", value); + setAwayMode(value); + updateIfChanged(CHANNEL_AWAY_MODE_RAW, new StringType(value.toString())); + } catch (IllegalArgumentException e) { + log.warn("Invalid Away Mode"); + } + + } else if (channelUID.getId().equals(CHANNEL_FAN_MODE)) { + VenstarFanMode value; + try { + if (command instanceof StringType) { + value = VenstarFanMode.valueOf(((StringType) command).toString().toUpperCase()); + } else { + value = VenstarFanMode.fromInt(((DecimalType) command).intValue()); + } + log.debug("Setting fan mode to {}", value); + setFanMode(value); + updateIfChanged(CHANNEL_FAN_MODE_RAW, new StringType(value.toString())); + } catch (IllegalArgumentException e) { + log.warn("Invalid Fan Mode"); + } + } else if (channelUID.getId().equals(CHANNEL_SCHEDULE_MODE)) { + VenstarScheduleMode value; + try { + if (command instanceof StringType) { + value = VenstarScheduleMode.valueOf(((StringType) command).toString().toUpperCase()); + } else { + value = VenstarScheduleMode.fromInt(((DecimalType) command).intValue()); + } + log.debug("Setting schedule mode to {}", value); + setScheduleMode(value); + updateIfChanged(CHANNEL_SCHEDULE_MODE_RAW, new StringType(value.toString())); + } catch (IllegalArgumentException e) { + log.warn("Invalid Schedule Mode"); } - log.debug("Setting away mode to {}", value); - setAwayMode(value); - updateIfChanged(CHANNEL_AWAY_MODE_RAW, new StringType(value.toString())); } + startUpdatesTask(UPDATE_AFTER_COMMAND_SECONDS); } } @@ -298,24 +355,40 @@ private State getOutdoorTemperature() { private void setCoolingSetpoint(double cool) { double heat = getHeatingSetpoint().doubleValue(); - VenstarSystemMode mode = getSystemMode(); - updateControls(heat, cool, mode); + VenstarSystemMode mode = infoData.getSystemMode(); + VenstarFanMode fanmode = infoData.getFanMode(); + updateControls(heat, cool, mode, fanmode); } private void setSystemMode(VenstarSystemMode mode) { double cool = getCoolingSetpoint().doubleValue(); double heat = getHeatingSetpoint().doubleValue(); - updateControls(heat, cool, mode); + VenstarFanMode fanmode = infoData.getFanMode(); + updateControls(heat, cool, mode, fanmode); } private void setHeatingSetpoint(double heat) { double cool = getCoolingSetpoint().doubleValue(); - VenstarSystemMode mode = getSystemMode(); - updateControls(heat, cool, mode); + VenstarSystemMode mode = infoData.getSystemMode(); + VenstarFanMode fanmode = infoData.getFanMode(); + updateControls(heat, cool, mode, fanmode); + } + + private void setFanMode(VenstarFanMode fanmode) { + double cool = getCoolingSetpoint().doubleValue(); + double heat = getHeatingSetpoint().doubleValue(); + VenstarSystemMode mode = infoData.getSystemMode(); + updateControls(heat, cool, mode, fanmode); } private void setAwayMode(VenstarAwayMode away) { - updateSettings(away); + VenstarScheduleMode schedule = infoData.getScheduleMode(); + updateSettings(away, schedule); + } + + private void setScheduleMode(VenstarScheduleMode schedule) { + VenstarAwayMode away = infoData.getAwayMode(); + updateSettings(away, schedule); } private QuantityType getCoolingSetpoint() { @@ -326,35 +399,37 @@ private QuantityType getHeatingSetpoint() { return new QuantityType(infoData.getHeattemp(), unitSystem); } - private VenstarSystemState getSystemState() { - return infoData.getState(); - } - - private VenstarSystemMode getSystemMode() { - return infoData.getMode(); + private ZonedDateTime getTimestampRuntime(VenstarRuntime runtime) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime now = LocalDateTime.now().atZone(zoneId); + int diff = now.getOffset().getTotalSeconds(); + ZonedDateTime z = ZonedDateTime.ofInstant(Instant.ofEpochSecond(runtime.getTimeStamp() - diff), zoneId); + return z; } - private VenstarAwayMode getAwayMode() { - return infoData.getAway(); - } - - private void updateSettings(VenstarAwayMode away) { + private void updateSettings(VenstarAwayMode away, VenstarScheduleMode schedule) { // this function corresponds to the thermostat local API POST /settings instruction // the function can be expanded with other parameters which are changed via POST /settings + // settings that can be included are tempunits, away mode, schedule mode, humidifier setpoint, dehumidifier + // setpoint + // (hum/dehum are the only ones missing) Map params = new HashMap<>(); params.put("away", String.valueOf(away.mode())); + params.put("schedule", String.valueOf(schedule.mode())); VenstarResponse res = updateThermostat("/settings", params); if (res != null) { log.debug("Updated thermostat"); // update our local copy until the next refresh occurs infoData.setAwayMode(away); + infoData.setScheduleMode(schedule); // add other parameters here in the same way } } - private void updateControls(double heat, double cool, VenstarSystemMode mode) { + private void updateControls(double heat, double cool, VenstarSystemMode mode, VenstarFanMode fanmode) { // this function corresponds to the thermostat local API POST /control instruction // the function can be expanded with other parameters which are changed via POST /control + // controls that can be included are thermostat mode, fan mode, heat temp, cool temp (all done already) Map params = new HashMap<>(); if (heat > 0) { params.put("heattemp", String.valueOf(heat)); @@ -363,13 +438,15 @@ private void updateControls(double heat, double cool, VenstarSystemMode mode) { params.put("cooltemp", String.valueOf(cool)); } params.put("mode", String.valueOf(mode.mode())); + params.put("fan", String.valueOf(fanmode.mode())); VenstarResponse res = updateThermostat("/control", params); if (res != null) { log.debug("Updated thermostat"); // update our local copy until the next refresh occurs infoData.setCooltemp(cool); infoData.setHeattemp(heat); - infoData.setMode(mode); + infoData.setSystemMode(mode); + infoData.setFanMode(fanmode); // add other parameters here in the same way } } @@ -415,6 +492,29 @@ private void updateData() { updateIfChanged(CHANNEL_EXTERNAL_TEMPERATURE, getOutdoorTemperature()); updateIfChanged(CHANNEL_HUMIDITY, getHumidity()); + response = getData("/query/runtimes"); + if (!isFutureValid(localUpdatesTask)) { + return; + } + + runtimeData = Objects.requireNonNull(gson.fromJson(response, VenstarRuntimeData.class)); + List runtimes = runtimeData.getRuntimes(); + Collections.reverse(runtimes);// reverse the list so that the most recent runtime data is first in the list + int nRuntimes = Math.min(7, runtimes.size());// check how many runtimes are available, might be less than + // seven if equipment + // was reset, and also might be more than 7, so limit to 7 + for (int i = 0; i < nRuntimes; i++) { + VenstarRuntime rt = runtimes.get(i); + updateIfChanged(CHANNEL_TIMESTAMP_RUNTIME_DAY + i, new DateTimeType(getTimestampRuntime(rt))); + updateIfChanged(CHANNEL_HEAT1_RUNTIME_DAY + i, new DecimalType(rt.getHeat1Runtime())); + updateIfChanged(CHANNEL_HEAT2_RUNTIME_DAY + i, new DecimalType(rt.getHeat2Runtime())); + updateIfChanged(CHANNEL_COOL1_RUNTIME_DAY + i, new DecimalType(rt.getCool1Runtime())); + updateIfChanged(CHANNEL_COOL2_RUNTIME_DAY + i, new DecimalType(rt.getCool2Runtime())); + updateIfChanged(CHANNEL_AUX1_RUNTIME_DAY + i, new DecimalType(rt.getAux1Runtime())); + updateIfChanged(CHANNEL_AUX2_RUNTIME_DAY + i, new DecimalType(rt.getAux2Runtime())); + updateIfChanged(CHANNEL_FC_RUNTIME_DAY + i, new DecimalType(rt.getFreeCoolRuntime())); + } + response = getData("/query/info"); if (!isFutureValid(localUpdatesTask)) { return; @@ -423,12 +523,20 @@ private void updateData() { updateUnits(infoData); updateIfChanged(CHANNEL_HEATING_SETPOINT, getHeatingSetpoint()); updateIfChanged(CHANNEL_COOLING_SETPOINT, getCoolingSetpoint()); - updateIfChanged(CHANNEL_SYSTEM_STATE, new StringType(getSystemState().stateName())); - updateIfChanged(CHANNEL_SYSTEM_MODE, new StringType(getSystemMode().modeName())); - updateIfChanged(CHANNEL_SYSTEM_STATE_RAW, new DecimalType(getSystemState().state())); - updateIfChanged(CHANNEL_SYSTEM_MODE_RAW, new DecimalType(getSystemMode().mode())); - updateIfChanged(CHANNEL_AWAY_MODE, new StringType(getAwayMode().modeName())); - updateIfChanged(CHANNEL_AWAY_MODE_RAW, new DecimalType(getAwayMode().mode())); + updateIfChanged(CHANNEL_SYSTEM_STATE, new StringType(infoData.getSystemState().stateName())); + updateIfChanged(CHANNEL_SYSTEM_MODE, new StringType(infoData.getSystemMode().modeName())); + updateIfChanged(CHANNEL_SYSTEM_STATE_RAW, new DecimalType(infoData.getSystemState().state())); + updateIfChanged(CHANNEL_SYSTEM_MODE_RAW, new DecimalType(infoData.getSystemMode().mode())); + updateIfChanged(CHANNEL_AWAY_MODE, new StringType(infoData.getAwayMode().modeName())); + updateIfChanged(CHANNEL_AWAY_MODE_RAW, new DecimalType(infoData.getAwayMode().mode())); + updateIfChanged(CHANNEL_FAN_MODE, new StringType(infoData.getFanMode().modeName())); + updateIfChanged(CHANNEL_FAN_MODE_RAW, new DecimalType(infoData.getFanMode().mode())); + updateIfChanged(CHANNEL_FAN_STATE, OnOffType.from(infoData.getFanState().stateName())); + updateIfChanged(CHANNEL_FAN_STATE_RAW, new DecimalType(infoData.getFanState().state())); + updateIfChanged(CHANNEL_SCHEDULE_MODE, new StringType(infoData.getScheduleMode().modeName())); + updateIfChanged(CHANNEL_SCHEDULE_MODE_RAW, new DecimalType(infoData.getScheduleMode().mode())); + updateIfChanged(CHANNEL_SCHEDULE_PART, new StringType(infoData.getSchedulePart().partName())); + updateIfChanged(CHANNEL_SCHEDULE_PART_RAW, new DecimalType(infoData.getSchedulePart().part())); goOnline(); } catch (VenstarCommunicationException | JsonSyntaxException e) { diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/thing/thing-types.xml index a9c6d5061c672..b027573541532 100644 --- a/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/thing/thing-types.xml @@ -21,6 +21,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -89,6 +152,136 @@ + + String + + Current Fan Mode + + + + + + + + + + Number + + Current Fan Mode, as an integer number + + + + + Switch + + Current Fan State + + + + + Number + + Current Fan State, as an integer number + + + + + String + + Current Schedule Mode + + + + + + + + + + Number + + Current Schedule Mode, as an integer number + + + + + String + + Current Schedule Part + + + + + + + + + + + + + Number + + Current Schedule Part, as an integer number + + + + + DateTime + + Time stamp of Runtime Update (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in heat1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in heat2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in cool1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in cool2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in aux1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in aux2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + + + Number + + Run time in Free Cool mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) + + + String From b4d1eaaee1e82f9b83363d41f13f90ac6cab9c56 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sat, 4 Dec 2021 14:50:13 +0100 Subject: [PATCH 163/361] Added pattern for DateTime channel types (#11681) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/thing/channels.xml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/thing/channels.xml index 4b9db8aa39768..6cc27f0185da0 100644 --- a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/thing/channels.xml @@ -8,62 +8,60 @@ String Displays contents of last [ERROR] event - + String Displays contents of last [WARN] event - + String Displays contents of last custom event - + Number Displays number of [WARN] lines matched to search pattern + Number Displays number of [ERROR] lines matched to search pattern + Number Displays number of custom lines matched to search pattern + DateTime Last time when log rotated recognized - + Time + trigger Fires when a new [ERROR] appears in the log - - trigger Fires when a new [WARN] appears in the log - - trigger Fires when a new [CUSTOM] appears in the log - - From 56e9bfe1978fea30fafbb86891b6dfca2cbe33ad Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sat, 4 Dec 2021 15:03:29 +0100 Subject: [PATCH 164/361] [chromecast] Added configuration flag to disable background discovery (#11689) * Added configuration flag to disable background discovery Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../org.openhab.binding.chromecast/README.md | 10 ++- .../ChromecastDiscoveryParticipant.java | 67 ++++++++++++------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/bundles/org.openhab.binding.chromecast/README.md b/bundles/org.openhab.binding.chromecast/README.md index f4d3f2f59e49c..2d9fd4b3c0597 100644 --- a/bundles/org.openhab.binding.chromecast/README.md +++ b/bundles/org.openhab.binding.chromecast/README.md @@ -28,15 +28,21 @@ Configure a Callback URL when the Chromecast cannot connect using the Primary Ad ## Discovery -Chromecast devices are discovered on the network using UPnP. +Chromecast devices are discovered on the network using mDNS. No authentication is required for accessing the devices on the network. +Auto-discovery is enabled by default. +To disable it, you can add the following line to `/services/runtime.cfg`: + +``` +discovery.chromecast:background=false +``` ## Thing Configuration Chromecast devices can also be manually added. The only configuration parameter is the `ipAddress`. For an audio group also the port is necessary. -The autodiscovery process finds the port automatically. +The auto-discovery process finds the port automatically. With manual thing configuration the parameter `port` must be determined manually. Example for audio group: diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/discovery/ChromecastDiscoveryParticipant.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/discovery/ChromecastDiscoveryParticipant.java index 2475b6578fff5..aaa187b0fc1ba 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/discovery/ChromecastDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/discovery/ChromecastDiscoveryParticipant.java @@ -14,7 +14,7 @@ import static org.openhab.binding.chromecast.internal.ChromecastBindingConstants.*; -import java.util.HashMap; +import java.util.Dictionary; import java.util.Map; import java.util.Set; @@ -24,22 +24,28 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Modified; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * The {@link ChromecastDiscoveryParticipant} is responsible for discovering Chromecast devices through UPnP. + * The {@link ChromecastDiscoveryParticipant} is responsible for discovering Chromecast devices through mDNS. * * @author Kai Kreuzer - Initial contribution * @author Daniel Walters - Change discovery protocol to mDNS + * @author Christoph Weitkamp - Use "discovery.chromecast:background=false" to disable discovery service */ -@Component +@Component(configurationPid = "discovery.chromecast") @NonNullByDefault public class ChromecastDiscoveryParticipant implements MDNSDiscoveryParticipant { + private final Logger logger = LoggerFactory.getLogger(ChromecastDiscoveryParticipant.class); private static final String PROPERTY_MODEL = "md"; @@ -47,6 +53,27 @@ public class ChromecastDiscoveryParticipant implements MDNSDiscoveryParticipant private static final String PROPERTY_DEVICE_ID = "id"; private static final String SERVICE_TYPE = "_googlecast._tcp.local."; + private boolean isAutoDiscoveryEnabled = true; + + @Activate + protected void activate(ComponentContext componentContext) { + activateOrModifyService(componentContext); + } + + @Modified + protected void modified(ComponentContext componentContext) { + activateOrModifyService(componentContext); + } + + private void activateOrModifyService(ComponentContext componentContext) { + Dictionary properties = componentContext.getProperties(); + String autoDiscoveryPropertyValue = (String) properties + .get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY); + if (autoDiscoveryPropertyValue != null && !autoDiscoveryPropertyValue.isBlank()) { + isAutoDiscoveryEnabled = Boolean.valueOf(autoDiscoveryPropertyValue); + } + } + @Override public Set getSupportedThingTypeUIDs() { return SUPPORTED_THING_TYPES_UIDS; @@ -59,25 +86,20 @@ public String getServiceType() { @Override public @Nullable DiscoveryResult createResult(ServiceInfo service) { - final ThingUID uid = getThingUID(service); - if (uid == null) { - return null; + if (isAutoDiscoveryEnabled) { + ThingUID uid = getThingUID(service); + if (uid != null) { + String host = service.getHostAddresses()[0]; + int port = service.getPort(); + logger.debug("Chromecast Found: {} {}", host, port); + String id = service.getPropertyString(PROPERTY_DEVICE_ID); + String friendlyName = service.getPropertyString(PROPERTY_FRIENDLY_NAME); // friendly name; + return DiscoveryResultBuilder.create(uid).withThingType(getThingType(service)) + .withProperties(Map.of(HOST, host, PORT, port, DEVICE_ID, id)) + .withRepresentationProperty(DEVICE_ID).withLabel(friendlyName).build(); + } } - - final Map properties = new HashMap<>(5); - String host = service.getHostAddresses()[0]; - properties.put(HOST, host); - int port = service.getPort(); - properties.put(PORT, port); - logger.debug("Chromecast Found: {} {}", host, port); - String id = service.getPropertyString(PROPERTY_DEVICE_ID); - properties.put(DEVICE_ID, id); - String friendlyName = service.getPropertyString(PROPERTY_FRIENDLY_NAME); // friendly name; - - final DiscoveryResult result = DiscoveryResultBuilder.create(uid).withThingType(getThingType(service)) - .withProperties(properties).withRepresentationProperty(DEVICE_ID).withLabel(friendlyName).build(); - - return result; + return null; } private @Nullable ThingTypeUID getThingType(final ServiceInfo service) { @@ -102,8 +124,7 @@ public String getServiceType() { if (thingTypeUID != null) { String id = service.getPropertyString(PROPERTY_DEVICE_ID); // device id return new ThingUID(thingTypeUID, id); - } else { - return null; } + return null; } } From 2a435f381b577613af10ac350a8360b28a208a86 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 4 Dec 2021 15:31:52 +0100 Subject: [PATCH 165/361] [miio] add support for Mi Smart Humidifer S (deerma.humidifier.jsqs) (#11687) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 34 +++++++++++++++++++ .../binding/miio/internal/MiIoDevices.java | 1 + .../database/deerma.humidifier.jsq5.json | 3 +- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 59695ffb27196..21d711a5d3729 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -206,6 +206,7 @@ Currently the miio binding supports more than 300 different models. | Mi Smart Antibacterial Humidifier | miio:basic | [deerma.humidifier.jsq](#deerma-humidifier-jsq) | Yes | | | Mi S Smart Humidifer | miio:basic | [deerma.humidifier.jsq1](#deerma-humidifier-jsq1) | Yes | | | Mi Smart Antibacterial Humidifier | miio:basic | [deerma.humidifier.jsq5](#deerma-humidifier-jsq5) | Yes | | +| Mi Smart Humidifer S | miio:basic | [deerma.humidifier.jsqs](#deerma-humidifier-jsqs) | Yes | | | Mi Smart Humidifier | miio:basic | [deerma.humidifier.mjjsq](#deerma-humidifier-mjjsq) | Yes | | | Mi Fresh Air Ventilator A1-150 | miio:basic | [dmaker.airfresh.a1](#dmaker-airfresh-a1) | Yes | | | Mi Fresh Air Ventilator | miio:basic | [dmaker.airfresh.t2017](#dmaker-airfresh-t2017) | Yes | | @@ -812,6 +813,21 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | water_shortage_fault | Switch | Custom - Water Shortage Fault | | | the_tank_filed | Switch | Custom - The Tank Filed | | +### Mi Smart Humidifer S (deerma.humidifier.jsqs) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| on | Switch | Humidifier - Switch Status | | +| fault | Number | Humidifier - Device Fault | Value mapping `["0"="No Faults","1"="Insufficient Water","2"="Water Separation"]` | +| fan_level | Number | Humidifier - Fan Level | Value mapping `["1"="Level1","2"="Level2","3"="Level3","4"="Humidity"]` | +| target_humidity | Number:Dimensionless | Humidifier - Target Humidity | | +| relative_humidity | Number:Dimensionless | Environment - Relative Humidity | | +| temperature | Number:Temperature | Environment - Temperature | | +| alarm | Switch | Alarm - Alarm | | +| on1 | Switch | Indicator Light - Switch Status | | +| water_shortage_fault | Switch | Custom - Water Shortage Fault | | +| the_tank_filed | Switch | Custom - The Tank Filed | | + ### Mi Smart Humidifier (deerma.humidifier.mjjsq) Channels | Channel | Type | Description | Comment | @@ -5644,6 +5660,24 @@ Switch water_shortage_fault "Custom - Water Shortage Fault" (G_humidifier) {chan Switch the_tank_filed "Custom - The Tank Filed" (G_humidifier) {channel="miio:basic:humidifier:the_tank_filed"} ``` +### Mi Smart Humidifer S (deerma.humidifier.jsqs) item file lines + +note: Autogenerated example. Replace the id (humidifier) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_humidifier "Mi Smart Humidifer S" +Switch on "Humidifier - Switch Status" (G_humidifier) {channel="miio:basic:humidifier:on"} +Number fault "Humidifier - Device Fault" (G_humidifier) {channel="miio:basic:humidifier:fault"} +Number fan_level "Humidifier - Fan Level" (G_humidifier) {channel="miio:basic:humidifier:fan_level"} +Number:Dimensionless target_humidity "Humidifier - Target Humidity" (G_humidifier) {channel="miio:basic:humidifier:target_humidity"} +Number:Dimensionless relative_humidity "Environment - Relative Humidity" (G_humidifier) {channel="miio:basic:humidifier:relative_humidity"} +Number:Temperature temperature "Environment - Temperature" (G_humidifier) {channel="miio:basic:humidifier:temperature"} +Switch alarm "Alarm - Alarm" (G_humidifier) {channel="miio:basic:humidifier:alarm"} +Switch on1 "Indicator Light - Switch Status" (G_humidifier) {channel="miio:basic:humidifier:on1"} +Switch water_shortage_fault "Custom - Water Shortage Fault" (G_humidifier) {channel="miio:basic:humidifier:water_shortage_fault"} +Switch the_tank_filed "Custom - The Tank Filed" (G_humidifier) {channel="miio:basic:humidifier:the_tank_filed"} +``` + ### Mi Smart Humidifier (deerma.humidifier.mjjsq) item file lines note: Autogenerated example. Replace the id (humidifier) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java index 931eb258fdeb3..5f925592cbb7a 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java @@ -52,6 +52,7 @@ public enum MiIoDevices { DEERMA_HUMIDIFIER_JSQ("deerma.humidifier.jsq", "Mi Smart Antibacterial Humidifier", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_JSQ1("deerma.humidifier.jsq1", "Mi S Smart Humidifer ", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_JSQ5("deerma.humidifier.jsq5", "Mi Smart Antibacterial Humidifier", THING_TYPE_BASIC), + DEERMA_HUMIDIFIER_JSQS("deerma.humidifier.jsqs", "Mi Smart Humidifer S", THING_TYPE_BASIC), DEERMA_HUMIDIFIER_MJJSQ("deerma.humidifier.mjjsq", "Mi Smart Humidifier", THING_TYPE_BASIC), DMAKER_AIRFRESH_A1("dmaker.airfresh.a1", "Mi Fresh Air Ventilator A1-150", THING_TYPE_BASIC), DMAKER_AIRFRESH_T2017("dmaker.airfresh.t2017", "Mi Fresh Air Ventilator", THING_TYPE_BASIC), diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json b/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json index 9a8cfbc9a93f0..0bb5fa2f1c17b 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/deerma.humidifier.jsq5.json @@ -1,7 +1,8 @@ { "deviceMapping": { "id": [ - "deerma.humidifier.jsq5" + "deerma.humidifier.jsq5", + "deerma.humidifier.jsqs" ], "propertyMethod": "get_properties", "maxProperties": 1, From 87b658bdd3c3db8ee626ca66dca1308ef1e563ce Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 4 Dec 2021 16:36:05 +0100 Subject: [PATCH 166/361] [miio] Improve binding description (#11690) * [miio] Improve binding description Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.base.md | 11 ++++++----- bundles/org.openhab.binding.miio/README.md | 11 ++++++----- bundles/org.openhab.binding.miio/pom.xml | 2 +- .../src/main/feature/feature.xml | 2 +- .../src/main/resources/OH-INF/binding/binding.xml | 5 +++-- .../src/main/resources/OH-INF/i18n/miio.properties | 4 ++-- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.base.md b/bundles/org.openhab.binding.miio/README.base.md index 7cde488e60f66..1171656d94dc1 100644 --- a/bundles/org.openhab.binding.miio/README.base.md +++ b/bundles/org.openhab.binding.miio/README.base.md @@ -1,7 +1,8 @@ -# Xiaomi Mi IO Binding +# Xiaomi Wifi devices (Mi IO) Binding This binding is used to control Xiaomi products implementing the Mi IO protocol. -This is a set of wifi devices from Xiaomi that are part of the Mi Ecosystem which is branded as MiJia. +This protocol is used for most of Xiaomi Mi Ecosystem wifi devices which is branded as MiJia. +If your Xiaomi wifi device is controlled by the mihome app, most likely it communicates using the Mi IO protocol and can communicate with openHAB using this binding. ![MIIO logo](doc/miio.png) @@ -12,9 +13,9 @@ The following things types are available: | ThingType | Description | |------------------|--------------------------------------------------------------------------------------------------------------------------| | miio:generic | Generic type for discovered devices. Once the token is available and the device model is determined, this ThingType will automatically change to the appropriate ThingType | -| miio:vacuum | For Xiaomi Robot Vacuum products | -| miio:basic | For several basic devices like yeelights, airpurifiers. Channels and commands are determined by database configuration | -| miio:unsupported | For experimenting with other devices which use the Mi IO protocol | +| miio:vacuum | For Xiaomi/RoboRock Robot Vacuum products | +| miio:basic | For most other devices like yeelights, airpurifiers. Channels and commands are determined by database configuration | +| miio:unsupported | For experimenting with other devices which use the Mi IO protocol or to build experimental support | # Discovery diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 21d711a5d3729..d7f875f9ed390 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -1,7 +1,8 @@ -# Xiaomi Mi IO Binding +# Xiaomi Wifi devices (Mi IO) Binding This binding is used to control Xiaomi products implementing the Mi IO protocol. -This is a set of wifi devices from Xiaomi that are part of the Mi Ecosystem which is branded as MiJia. +This protocol is used for most of Xiaomi Mi Ecosystem wifi devices which is branded as MiJia. +If your Xiaomi wifi device is controlled by the mihome app, most likely it communicates using the Mi IO protocol and can communicate with openHAB using this binding. ![MIIO logo](doc/miio.png) @@ -12,9 +13,9 @@ The following things types are available: | ThingType | Description | |------------------|--------------------------------------------------------------------------------------------------------------------------| | miio:generic | Generic type for discovered devices. Once the token is available and the device model is determined, this ThingType will automatically change to the appropriate ThingType | -| miio:vacuum | For Xiaomi Robot Vacuum products | -| miio:basic | For several basic devices like yeelights, airpurifiers. Channels and commands are determined by database configuration | -| miio:unsupported | For experimenting with other devices which use the Mi IO protocol | +| miio:vacuum | For Xiaomi/RoboRock Robot Vacuum products | +| miio:basic | For most other devices like yeelights, airpurifiers. Channels and commands are determined by database configuration | +| miio:unsupported | For experimenting with other devices which use the Mi IO protocol or to build experimental support | # Discovery diff --git a/bundles/org.openhab.binding.miio/pom.xml b/bundles/org.openhab.binding.miio/pom.xml index 0efd79fbc4ebb..1cd8342be88b2 100644 --- a/bundles/org.openhab.binding.miio/pom.xml +++ b/bundles/org.openhab.binding.miio/pom.xml @@ -8,5 +8,5 @@ 3.2.0-SNAPSHOT org.openhab.binding.miio - openHAB Add-ons :: Bundles :: Xiaomi Mi IO Binding + openHAB Add-ons :: Bundles :: Xiaomi Wifi devices (Mi IO) Binding diff --git a/bundles/org.openhab.binding.miio/src/main/feature/feature.xml b/bundles/org.openhab.binding.miio/src/main/feature/feature.xml index 1ab32f26fa245..e730cb7abb5af 100644 --- a/bundles/org.openhab.binding.miio/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.miio/src/main/feature/feature.xml @@ -2,7 +2,7 @@ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features - + openhab-runtime-base openhab-transport-mdns mvn:org.openhab.addons.bundles/org.openhab.binding.miio/${project.version} diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/binding/binding.xml index 4dc76012096cf..899afad15bdbe 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/binding/binding.xml +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/binding/binding.xml @@ -2,8 +2,9 @@ - Xiaomi Mi IO Binding - Binding for Xiaomi Mi IO (Wifi) devices like Mi Robot Vacuum, Yeelights, Humidifiers, Fans etc. + Xiaomi Wifi devices (Mi IO) Binding + Binding for Xiaomi wifi devices (Mi IO protocol) which are normally controlled by the mihome app like Mi + Robot Vacuums, Yeelights, Humidifiers, Fans etc. diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/miio.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/miio.properties index cebf94f06556b..6386ec4497477 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/miio.properties +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/miio.properties @@ -1,7 +1,7 @@ # binding -binding.miio.name = Xiaomi Mi IO Binding -binding.miio.description = Binding for Xiaomi Mi IO (Wifi) devices like Mi Robot Vacuum, Yeelights, Humidifiers, Fans etc. +binding.miio.name = Xiaomi Wifi devices (Mi IO) Binding +binding.miio.description = Binding for Xiaomi wifi devices (Mi IO protocol) which are normally controlled by the mihome app like Mi Robot Vacuums, Yeelights, Humidifiers, Fans etc. # binding config From 748115857f80c743138ad268d2ab611fa52e9576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Sat, 4 Dec 2021 16:55:48 +0100 Subject: [PATCH 167/361] [Sagercaster] Reintroducing timestamp channel (#11665) [Sagercaster] Reintroducing timestamp channel Signed-off-by: clinique Signed-off-by: Michael Schmidt --- .../org.openhab.binding.sagercaster/README.md | 9 +- .../internal/SagerCasterBindingConstants.java | 2 + .../internal/SagerCasterHandlerFactory.java | 1 + .../internal/caster/SagerPrediction.java | 49 ++++++ .../{ => caster}/SagerWeatherCaster.java | 73 ++++----- .../internal/handler/SagerCasterHandler.java | 141 ++++++++---------- .../OH-INF/i18n/sagercaster.properties | 24 +-- .../OH-INF/i18n/sagercaster_fr.properties | 2 + .../resources/OH-INF/thing/thing-types.xml | 18 ++- 9 files changed, 189 insertions(+), 130 deletions(-) create mode 100644 bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerPrediction.java rename bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/{ => caster}/SagerWeatherCaster.java (89%) diff --git a/bundles/org.openhab.binding.sagercaster/README.md b/bundles/org.openhab.binding.sagercaster/README.md index 485b76918219b..c9eadf8a16753 100644 --- a/bundles/org.openhab.binding.sagercaster/README.md +++ b/bundles/org.openhab.binding.sagercaster/README.md @@ -6,7 +6,8 @@ The Sager Weathercaster is a scientific instrument for accurate prediction of th * To operate, this binding will need to use channel values provided by other means (e.g. Weather Binding, Netatmo, a 1-Wire personal weather station...) -* This binding buffers readings for some hours before producing weather forecasts(wind direction and sea level pressure). SagerWeatherCaster needs an observation period of minimum 6 hours. +* This binding buffers readings for some hours before producing weather forecasts(wind direction and sea level pressure). +SagerWeatherCaster needs an observation period of minimum 6 hours. For these reasons, this binding is not a binding in the usual sense. @@ -24,9 +25,11 @@ The binding itself does not require any configuration. | Name | Type | Description | |--------------------|----------|--------------------------------------------------------------------------| -| location | Location | Latitude and longitude of the desired weather forecast. | +| location (*) | Location | Latitude and longitude of the desired weather forecast. | | observation-period | int | Minimum delay (in hours) before producing forecasts. Defaulted to 6. | +(*) Only latitude is used by the algorithm. + ## Channels The binding will use some input channels, that can be configured directly with profiles (sample below). @@ -41,6 +44,8 @@ The binding will use some input channels, that can be configured directly with p | wind-speed-beaufort | input |Number | Wind speed expressed using the Beaufort scale | | pressure | input |Number:Pressure | Sea level pressure | | wind-angle | input |Number:Angle | Wind direction | +| temperature | input |Number:Temperature | Outside temperature | +| timestamp | output |DateTime | Timestamp of the last forecast update | | forecast | output |String | Description of the weather forecast | | velocity | output |String | Description of the expected wind evolution | | velocity-beaufort | output |Number | Expected wind evolution using the Beaufort scale | diff --git a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterBindingConstants.java b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterBindingConstants.java index f4865f6121bf1..7b1eef6214784 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterBindingConstants.java +++ b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterBindingConstants.java @@ -48,6 +48,8 @@ public class SagerCasterBindingConstants { public static final String CHANNEL_WINDEVOLUTION = "wind-evolution"; public static final String CHANNEL_PRESSURETREND = "pressure-trend"; public static final String CHANNEL_TEMPERATURETREND = "temperature-trend"; + public static final String CHANNEL_TIMESTAMP = "timestamp"; + // Input channel ids public static final String CHANNEL_CLOUDINESS = "cloudiness"; public static final String CHANNEL_IS_RAINING = "is-raining"; diff --git a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterHandlerFactory.java b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterHandlerFactory.java index aa8b7ff7998fd..ad9f8c6448366 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterHandlerFactory.java +++ b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerCasterHandlerFactory.java @@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.sagercaster.internal.caster.SagerWeatherCaster; import org.openhab.binding.sagercaster.internal.handler.SagerCasterHandler; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; diff --git a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerPrediction.java b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerPrediction.java new file mode 100644 index 0000000000000..dae13ba4e85d3 --- /dev/null +++ b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerPrediction.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sagercaster.internal.caster; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * This class holds the result of the SagerCaster algorithm + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class SagerPrediction { + private final String prediction; + + public SagerPrediction(String sagerCode) { + this.prediction = sagerCode; + } + + public String getSagerCode() { + return prediction; + } + + public String getForecast() { + return Character.toString(prediction.charAt(0)); + } + + public String getWindVelocity() { + return Character.toString(prediction.charAt(1)); + } + + public String getWindDirection() { + return Character.toString(prediction.charAt(2)); + } + + public String getWindDirection2() { + return prediction.length() > 3 ? Character.toString(prediction.charAt(3)) : SagerWeatherCaster.UNDEF; + } +} diff --git a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerWeatherCaster.java b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerWeatherCaster.java similarity index 89% rename from bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerWeatherCaster.java rename to bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerWeatherCaster.java index 21f05dc296a8b..fbaa8eaac3c89 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/SagerWeatherCaster.java +++ b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/caster/SagerWeatherCaster.java @@ -53,7 +53,7 @@ * 378 possible forecasts determined from 4996 dial codes. */ -package org.openhab.binding.sagercaster.internal; +package org.openhab.binding.sagercaster.internal.caster; import java.io.IOException; import java.io.InputStream; @@ -76,6 +76,7 @@ @Component(service = SagerWeatherCaster.class, scope = ServiceScope.SINGLETON) @NonNullByDefault public class SagerWeatherCaster { + public final static String UNDEF = "-"; // Northern Polar Zone & Northern Tropical Zone private final static String[] NPZDIRECTIONS = { "S", "SW", "W", "NW", "N", "NE", "E", "SE" }; // Northern Temperate Zone @@ -88,7 +89,7 @@ public class SagerWeatherCaster { private final Logger logger = LoggerFactory.getLogger(SagerWeatherCaster.class); private final Properties forecaster = new Properties(); - private Optional prevision = Optional.empty(); + private Optional prevision = Optional.empty(); private String[] usedDirections = NTZDIRECTIONS; // Defaulted to Northern Zone private int currentBearing = -1; @@ -238,7 +239,7 @@ private String getCompass() { private void updatePrediction() { int zWind = Arrays.asList(usedDirections).indexOf(getCompass()); - String d1 = "-"; + String d1 = UNDEF; switch (zWind) { case 0: if (windEvolution == 3) { @@ -319,39 +320,27 @@ private void updatePrediction() { } String forecast = forecaster.getProperty( d1 + String.valueOf(sagerPressure) + String.valueOf(pressureEvolution) + String.valueOf(nubes)); - prevision = (forecast != null) ? Optional.of(new Prevision(forecast)) : Optional.empty(); + prevision = Optional.ofNullable(forecast != null ? new SagerPrediction(forecast) : null); } public String getForecast() { - if (prevision.isPresent()) { - char forecast = prevision.get().zForecast; - return Character.toString(forecast); - } - return "-"; + return prevision.map(p -> p.getForecast()).orElse(UNDEF); } public String getWindVelocity() { - if (prevision.isPresent()) { - char windVelocity = prevision.get().zWindVelocity; - return Character.toString(windVelocity); - } - return "-"; + return prevision.map(p -> p.getWindVelocity()).orElse(UNDEF); } public String getWindDirection() { - if (prevision.isPresent()) { - int direction = prevision.get().zWindDirection; - return String.valueOf(direction); - } - return "-"; + return prevision.map(p -> p.getWindDirection()).orElse(UNDEF); } public String getWindDirection2() { - if (prevision.isPresent()) { - int direction = prevision.get().zWindDirection2; - return String.valueOf(direction); - } - return "-"; + return prevision.map(p -> p.getWindDirection2()).orElse(UNDEF); + } + + public String getSagerCode() { + return prevision.map(p -> p.getSagerCode()).orElse(UNDEF); } public void setLatitude(double latitude) { @@ -370,17 +359,31 @@ public void setLatitude(double latitude) { } } - private class Prevision { - public final char zForecast; - public final char zWindVelocity; - public final int zWindDirection; - public final int zWindDirection2; - - public Prevision(String forecast) { - zForecast = forecast.charAt(0); - zWindVelocity = forecast.charAt(1); - zWindDirection = Character.getNumericValue(forecast.charAt(2)); - zWindDirection2 = (forecast.length() > 3) ? Character.getNumericValue(forecast.charAt(3)) : -1; + public int getPredictedBeaufort() { + int result = currentBeaufort; + switch (getWindVelocity()) { + case "N": + result += 1; + break; + case "F": + result = 4; + break; + case "S": + result = 6; + break; + case "G": + result = 8; + break; + case "W": + result = 10; + break; + case "H": + result = 12; + break; + case "D": + result -= 1; + break; } + return result; } } diff --git a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/handler/SagerCasterHandler.java b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/handler/SagerCasterHandler.java index 79065e6ac662b..b2e91af137431 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/handler/SagerCasterHandler.java +++ b/bundles/org.openhab.binding.sagercaster/src/main/java/org/openhab/binding/sagercaster/internal/handler/SagerCasterHandler.java @@ -16,9 +16,9 @@ import static org.openhab.core.library.unit.MetricPrefix.HECTO; import java.math.BigDecimal; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.TimeUnit; import javax.measure.quantity.Angle; @@ -26,8 +26,9 @@ import javax.measure.quantity.Temperature; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.sagercaster.internal.SagerWeatherCaster; import org.openhab.binding.sagercaster.internal.WindDirectionStateDescriptionProvider; +import org.openhab.binding.sagercaster.internal.caster.SagerWeatherCaster; +import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; @@ -36,6 +37,7 @@ import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; @@ -58,11 +60,12 @@ public class SagerCasterHandler extends BaseThingHandler { private final WindDirectionStateDescriptionProvider stateDescriptionProvider; - private final ExpiringMap> pressureCache = new ExpiringMap<>(); - private final ExpiringMap> temperatureCache = new ExpiringMap<>(); - private final ExpiringMap> bearingCache = new ExpiringMap<>(); + private final ExpiringMap pressureCache = new ExpiringMap<>(); + private final ExpiringMap temperatureCache = new ExpiringMap<>(); + private final ExpiringMap bearingCache = new ExpiringMap<>(); - private int currentTemp = 0; + private double currentTemp = 0; + private String currentSagerCode = SagerWeatherCaster.UNDEF; public SagerCasterHandler(Thing thing, WindDirectionStateDescriptionProvider stateDescriptionProvider, SagerWeatherCaster sagerWeatherCaster) { @@ -73,15 +76,17 @@ public SagerCasterHandler(Thing thing, WindDirectionStateDescriptionProvider sta @Override public void initialize() { - String location = (String) getConfig().get(CONFIG_LOCATION); int observationPeriod = ((BigDecimal) getConfig().get(CONFIG_PERIOD)).intValue(); - String latitude = location.split(",")[0]; - sagerWeatherCaster.setLatitude(Double.parseDouble(latitude)); long period = TimeUnit.HOURS.toMillis(observationPeriod); pressureCache.setObservationPeriod(period); bearingCache.setObservationPeriod(period); temperatureCache.setObservationPeriod(period); + + String location = (String) getConfig().get(CONFIG_LOCATION); + String latitude = location.split(",")[0]; + sagerWeatherCaster.setLatitude(Double.parseDouble(latitude)); defineWindDirectionStateDescriptions(); + updateStatus(ThingStatus.ONLINE); } @@ -95,10 +100,9 @@ private void defineWindDirectionStateDescriptions() { } options.add(new StateOption("9", "Shifting / Variable winds")); - stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), GROUP_OUTPUT, CHANNEL_WINDFROM), - options); - stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), GROUP_OUTPUT, CHANNEL_WINDTO), - options); + ThingUID thingUID = getThing().getUID(); + stateDescriptionProvider.setStateOptions(new ChannelUID(thingUID, GROUP_OUTPUT, CHANNEL_WINDFROM), options); + stateDescriptionProvider.setStateOptions(new ChannelUID(thingUID, GROUP_OUTPUT, CHANNEL_WINDTO), options); } @Override @@ -109,7 +113,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { String id = channelUID.getIdWithoutGroup(); switch (id) { case CHANNEL_CLOUDINESS: - logger.debug("Octa cloud level changed, updating forecast"); + logger.debug("Cloud level changed, updating forecast"); if (command instanceof QuantityType) { QuantityType cloudiness = (QuantityType) command; scheduler.submit(() -> { @@ -127,26 +131,17 @@ public void handleCommand(ChannelUID channelUID, Command command) { postNewForecast(); }); } else { - logger.debug("Channel '{}' can only accept Switch type commands.", channelUID); + logger.debug("Channel '{}' accepts Switch commands.", channelUID); } break; case CHANNEL_RAIN_QTTY: logger.debug("Rain status updated, updating forecast"); if (command instanceof QuantityType) { - QuantityType newQtty = (QuantityType) command; - scheduler.submit(() -> { - sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0); - postNewForecast(); - }); + updateRain((QuantityType) command); } else if (command instanceof DecimalType) { - DecimalType newQtty = (DecimalType) command; - scheduler.submit(() -> { - sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0); - postNewForecast(); - }); + updateRain((DecimalType) command); } else { - logger.debug("Channel '{}' can accept Number, Number:Speed, Number:Length type commands.", - channelUID); + logger.debug("Channel '{}' accepts Number, Number:(Speed|Length) commands.", channelUID); } break; case CHANNEL_WIND_SPEED: @@ -165,12 +160,13 @@ public void handleCommand(ChannelUID channelUID, Command command) { logger.debug("Sea-level pressure updated, updating forecast"); if (command instanceof QuantityType) { @SuppressWarnings("unchecked") - QuantityType newPressure = ((QuantityType) command) + QuantityType pressQtty = ((QuantityType) command) .toUnit(HECTO(SIUnits.PASCAL)); - if (newPressure != null) { - pressureCache.put(newPressure); - pressureCache.getAgedValue().ifPresentOrElse(pressure -> scheduler.submit(() -> { - sagerWeatherCaster.setPressure(newPressure.doubleValue(), pressure.doubleValue()); + if (pressQtty != null) { + double newPressureValue = pressQtty.doubleValue(); + pressureCache.put(newPressureValue); + pressureCache.getAgedValue().ifPresentOrElse(oldPressure -> scheduler.submit(() -> { + sagerWeatherCaster.setPressure(newPressureValue, oldPressure); updateChannelString(GROUP_OUTPUT, CHANNEL_PRESSURETREND, String.valueOf(sagerWeatherCaster.getPressureEvolution())); postNewForecast(); @@ -182,14 +178,13 @@ public void handleCommand(ChannelUID channelUID, Command command) { logger.debug("Temperature updated"); if (command instanceof QuantityType) { @SuppressWarnings("unchecked") - QuantityType newTemperature = ((QuantityType) command) + QuantityType tempQtty = ((QuantityType) command) .toUnit(SIUnits.CELSIUS); - if (newTemperature != null) { - temperatureCache.put(newTemperature); - currentTemp = newTemperature.intValue(); - Optional> agedTemperature = temperatureCache.getAgedValue(); - agedTemperature.ifPresent(temperature -> { - double delta = newTemperature.doubleValue() - temperature.doubleValue(); + if (tempQtty != null) { + currentTemp = tempQtty.doubleValue(); + temperatureCache.put(currentTemp); + temperatureCache.getAgedValue().ifPresent(oldTemperature -> { + double delta = currentTemp - oldTemperature; String trend = (delta > 3) ? "1" : (delta > 0.3) ? "2" : (delta > -0.3) ? "3" : (delta > -3) ? "4" : "5"; updateChannelString(GROUP_OUTPUT, CHANNEL_TEMPERATURETREND, trend); @@ -201,12 +196,12 @@ public void handleCommand(ChannelUID channelUID, Command command) { logger.debug("Updated wind direction, updating forecast"); if (command instanceof QuantityType) { @SuppressWarnings("unchecked") - QuantityType newAngle = (QuantityType) command; - bearingCache.put(newAngle); - Optional> agedAngle = bearingCache.getAgedValue(); - agedAngle.ifPresent(angle -> { + QuantityType angleQtty = (QuantityType) command; + int newAngleValue = angleQtty.intValue(); + bearingCache.put(newAngleValue); + bearingCache.getAgedValue().ifPresent(oldAngle -> { scheduler.submit(() -> { - sagerWeatherCaster.setBearing(newAngle.intValue(), angle.intValue()); + sagerWeatherCaster.setBearing(newAngleValue, oldAngle); updateChannelString(GROUP_OUTPUT, CHANNEL_WINDEVOLUTION, String.valueOf(sagerWeatherCaster.getWindEvolution())); postNewForecast(); @@ -220,42 +215,36 @@ public void handleCommand(ChannelUID channelUID, Command command) { } } + private void updateRain(Number newQtty) { + scheduler.submit(() -> { + sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0); + postNewForecast(); + }); + } + private void postNewForecast() { - String forecast = sagerWeatherCaster.getForecast(); - // Sharpens forecast if current temp is below 2 degrees, likely to be flurries rather than shower - forecast += SHOWERS.contains(forecast) ? (currentTemp > 2) ? "1" : "2" : ""; + String newSagerCode = sagerWeatherCaster.getSagerCode(); + if (!newSagerCode.equals(currentSagerCode)) { + logger.debug("Sager prediction changed to {}", newSagerCode); + currentSagerCode = newSagerCode; + updateChannelTimeStamp(GROUP_OUTPUT, CHANNEL_TIMESTAMP, ZonedDateTime.now()); + String forecast = sagerWeatherCaster.getForecast(); + // Sharpens forecast if current temp is below 2 degrees, likely to be flurries rather than shower + forecast += SHOWERS.contains(forecast) ? (currentTemp > 2) ? "1" : "2" : ""; - updateChannelString(GROUP_OUTPUT, CHANNEL_FORECAST, forecast); - updateChannelString(GROUP_OUTPUT, CHANNEL_WINDFROM, sagerWeatherCaster.getWindDirection()); - updateChannelString(GROUP_OUTPUT, CHANNEL_WINDTO, sagerWeatherCaster.getWindDirection2()); + updateChannelString(GROUP_OUTPUT, CHANNEL_FORECAST, forecast); + updateChannelString(GROUP_OUTPUT, CHANNEL_WINDFROM, sagerWeatherCaster.getWindDirection()); + updateChannelString(GROUP_OUTPUT, CHANNEL_WINDTO, sagerWeatherCaster.getWindDirection2()); + updateChannelString(GROUP_OUTPUT, CHANNEL_VELOCITY, sagerWeatherCaster.getWindVelocity()); + updateChannelDecimal(GROUP_OUTPUT, CHANNEL_VELOCITY_BEAUFORT, sagerWeatherCaster.getPredictedBeaufort()); + } + } - String velocity = sagerWeatherCaster.getWindVelocity(); - updateChannelString(GROUP_OUTPUT, CHANNEL_VELOCITY, velocity); - int predictedBeaufort = sagerWeatherCaster.getBeaufort(); - switch (velocity) { - case "N": - predictedBeaufort += 1; - break; - case "F": - predictedBeaufort = 4; - break; - case "S": - predictedBeaufort = 6; - break; - case "G": - predictedBeaufort = 8; - break; - case "W": - predictedBeaufort = 10; - break; - case "H": - predictedBeaufort = 12; - break; - case "D": - predictedBeaufort -= 1; - break; + private void updateChannelTimeStamp(String group, String channelId, ZonedDateTime zonedDateTime) { + ChannelUID id = new ChannelUID(getThing().getUID(), group, channelId); + if (isLinked(id)) { + updateState(id, new DateTimeType(zonedDateTime)); } - updateChannelDecimal(GROUP_OUTPUT, CHANNEL_VELOCITY_BEAUFORT, predictedBeaufort); } private void updateChannelString(String group, String channelId, String value) { diff --git a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster.properties b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster.properties index a8eb7a0716a10..36d25ccac2f64 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster.properties +++ b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster.properties @@ -43,6 +43,8 @@ rainingDescription = Is it currently raining ? beaufortLabel = Beaufort beaufortDescription = Wind speed using Beaufort Scale pressureDescription = Barometric pressure at sea level. +timestampChannelLabel = Timestamp +timestampChannelDescription = Timestamp of the last weather forecast update. # channel options forecast0 = Not enough historic data to study pressure evolution, wait a bit ... @@ -52,33 +54,33 @@ forecastC = Fair and cooler forecastD = Unsettled forecastE = Unsettled and warmer forecastF = Unsettled and cooler -forecastG = Increasing cloudiness or overcast followed by Precipitation or showers/Flurries -forecastG1 = Increasing cloudiness or overcast followed by Precipitation or showers -forecastG2 = Increasing cloudiness or overcast followed by Precipitation or Flurries -forecastH = Increasing cloudiness or overcast followed by Precipitation or showers and warmer +forecastG = Increasing cloudiness or overcast followed by precipitation or showers/flurries +forecastG1 = Increasing cloudiness or overcast followed by precipitation or showers +forecastG2 = Increasing cloudiness or overcast followed by precipitation or flurries +forecastH = Increasing cloudiness or overcast followed by precipitation or showers and warmer forecastJ = Showers -forecastK = Showers/Flurries and warmer +forecastK = Showers/flurries and warmer forecastK1 = Showers and warmer forecastK2 = Flurries and warmer -forecastL = Showers/Flurries and cooler +forecastL = Showers/flurries and cooler forecastL1 = Showers and cooler forecastL2 = Flurries and cooler forecastM = Precipitation forecastN = Precipitation and warmer forecastP = Precipitation and turning cooler; then improvement likely in 24 hours -forecastR = Precipitation or showers/Flurries followed by improvement (within 12 hours) +forecastR = Precipitation or showers/flurries followed by improvement (within 12 hours) forecastR1 = Precipitation or showers followed by improvement (within 12 hours) forecastR2 = Precipitation or flurries followed by improvement (within 12 hours) -forecastS = Precipitation or showers/Flurries followed by improvement (within 12 hours) and becoming cooler +forecastS = Precipitation or showers/flurries followed by improvement (within 12 hours) and becoming cooler forecastS1 = Precipitation or showers followed by improvement (within 12 hours) and becoming cooler forecastS2 = Precipitation or flurries followed by improvement (within 12 hours) and becoming cooler -forecastT = Precipitation or showers/Flurries followed by improvement early in period (within 6 hours) +forecastT = Precipitation or showers/flurries followed by improvement early in period (within 6 hours) forecastT1 = Precipitation or showers followed by improvement early in period (within 6 hours) forecastT2 = Precipitation or flurries followed by improvement early in period (within 6 hours) -forecastU = Precipitation or showers/Flurries by improvement early in period (within 6 hours) and becoming cooler +forecastU = Precipitation or showers/flurries by improvement early in period (within 6 hours) and becoming cooler forecastU1 = Precipitation or showers by improvement early in period (within 6 hours) and becoming cooler forecastU2 = Precipitation or flurries by improvement early in period (within 6 hours) and becoming cooler -forecastW = Precipitation or showers/Flurries followed by fair early in period (within 6 hours) and becoming cooler +forecastW = Precipitation or showers/flurries followed by fair early in period (within 6 hours) and becoming cooler forecastW1 = Precipitation or showers followed by fair early in period (within 6 hours) and becoming cooler forecastW2 = Precipitation or flurries followed by fair early in period (within 6 hours) and becoming cooler forecastX = Unsettled followed by fair diff --git a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties index 6f6720285e51c..557ef119aef0b 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties +++ b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties @@ -43,6 +43,8 @@ rainingDescription = Pleut-il actuellement ? beaufortLabel = Beaufort beaufortDescription = Force du vent mesurée sur l'échelle Beaufort pressureDescription = Pression barométrique au niveau de la mer. +timestampChannelLabel = Horodatage +timestampChannelDescription = Horodatage de la dernire mise jour de la prvision mto. # channel options forecast0 = Patientez encore un peu pour une prédiction diff --git a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/thing/thing-types.xml index 60b0c1e7926eb..5b372f6988e09 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/thing/thing-types.xml @@ -72,6 +72,7 @@ @text/tempTrendDescription + @@ -163,6 +164,7 @@ String @text/trendDescription + Line @@ -174,19 +176,23 @@ - + DateTime - - @text/timestampDescription - Observation time - + + @text/timestampChannelDescription + Time + + Status + Timestamp + + Number:Dimensionless @text/cloudinessDescription - Clouds + Sun_Clouds From e4faa044a7b5bc6fbe34410920526a93e229df67 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sat, 4 Dec 2021 16:59:50 +0100 Subject: [PATCH 168/361] [chromecast] Added pattern for DateTime channel types (#11694) * Added pattern for DateTime channel types Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/thing-types.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/thing/thing-types.xml index 401cfb187ad89..5c7bbf6bf1cd0 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/thing/thing-types.xml @@ -244,7 +244,8 @@ DateTime The broadcast date of the currently playing media - + Calendar + @@ -258,7 +259,8 @@ DateTime The creation date of the currently playing media - + Calendar + @@ -300,7 +302,8 @@ DateTime The release date of the currently playing media - + Calendar + From 0134bd8cd4049a8af78dffa516969f71363dee64 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sat, 4 Dec 2021 17:05:58 +0100 Subject: [PATCH 169/361] [miio/ntp] Fix wrong "Date" channel category (#11699) Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/thing/vacuumThing.xml | 4 ++-- .../src/main/resources/OH-INF/thing/thing-types.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/vacuumThing.xml b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/vacuumThing.xml index c9e5e713eedaa..ee8887766b6e7 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/vacuumThing.xml +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/vacuumThing.xml @@ -347,14 +347,14 @@ DateTime Last Cleaning Start Time - Date + Time DateTime Last Cleaning End Time - Date + Time diff --git a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/thing/thing-types.xml index d4e6fea94c14c..e58662a3373cf 100644 --- a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/thing/thing-types.xml @@ -46,14 +46,14 @@ DateTime NTP refreshed date & time - Date + Time String NTP refreshed date & time - Date + Time From d45b087ada86fbe1d06edc0a539dcd7b4be57d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Sat, 4 Dec 2021 18:33:50 +0100 Subject: [PATCH 170/361] [SNCF] A binding to get French railways arrivals and departures (#11607) * SNCF : new binding Signed-off-by: clinique Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + bundles/org.openhab.binding.sncf/NOTICE | 13 + bundles/org.openhab.binding.sncf/README.md | 87 ++++++ bundles/org.openhab.binding.sncf/pom.xml | 17 ++ .../src/main/feature/feature.xml | 9 + .../sncf/internal/SncfBindingConstants.java | 54 ++++ .../binding/sncf/internal/SncfException.java | 38 +++ .../sncf/internal/SncfHandlerFactory.java | 78 ++++++ .../discovery/SncfDiscoveryService.java | 115 ++++++++ .../binding/sncf/internal/dto/Coord.java | 23 ++ .../sncf/internal/dto/NavitiaObject.java | 23 ++ .../binding/sncf/internal/dto/Passage.java | 24 ++ .../binding/sncf/internal/dto/Passages.java | 30 ++ .../sncf/internal/dto/PlaceNearby.java | 22 ++ .../sncf/internal/dto/PlacesNearby.java | 24 ++ .../binding/sncf/internal/dto/SncfAnswer.java | 23 ++ .../binding/sncf/internal/dto/StopArea.java | 23 ++ .../sncf/internal/dto/StopDateTime.java | 23 ++ .../binding/sncf/internal/dto/StopPoint.java | 23 ++ .../binding/sncf/internal/dto/StopPoints.java | 26 ++ .../internal/dto/VJDisplayInformation.java | 27 ++ .../internal/handler/SncfBridgeHandler.java | 171 ++++++++++++ .../sncf/internal/handler/StationHandler.java | 259 ++++++++++++++++++ .../main/resources/OH-INF/binding/binding.xml | 9 + .../main/resources/OH-INF/config/config.xml | 15 + .../resources/OH-INF/i18n/sncf.properties | 36 +++ .../main/resources/OH-INF/thing/bridge.xml | 12 + .../main/resources/OH-INF/thing/station.xml | 74 +++++ bundles/pom.xml | 1 + 30 files changed, 1285 insertions(+) create mode 100644 bundles/org.openhab.binding.sncf/NOTICE create mode 100644 bundles/org.openhab.binding.sncf/README.md create mode 100644 bundles/org.openhab.binding.sncf/pom.xml create mode 100644 bundles/org.openhab.binding.sncf/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfBindingConstants.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfException.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfHandlerFactory.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/discovery/SncfDiscoveryService.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Coord.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/NavitiaObject.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passage.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passages.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlaceNearby.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlacesNearby.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/SncfAnswer.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopArea.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopDateTime.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoint.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoints.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/VJDisplayInformation.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/SncfBridgeHandler.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/StationHandler.java create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf.properties create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/bridge.xml create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/station.xml diff --git a/CODEOWNERS b/CODEOWNERS index 8083097c0b57a..24d62cddb60bd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -280,6 +280,7 @@ /bundles/org.openhab.binding.smartmeter/ @msteigenberger /bundles/org.openhab.binding.smartthings/ @BobRak /bundles/org.openhab.binding.smhi/ @pacive +/bundles/org.openhab.binding.sncf/ @clinique /bundles/org.openhab.binding.snmp/ @openhab/add-ons-maintainers /bundles/org.openhab.binding.solaredge/ @alexf2015 /bundles/org.openhab.binding.solarlog/ @johannrichard diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 55e21c009e719..d3f73e8240e68 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1391,6 +1391,11 @@ org.openhab.binding.smhi ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.sncf + ${project.version} + org.openhab.addons.bundles org.openhab.binding.snmp diff --git a/bundles/org.openhab.binding.sncf/NOTICE b/bundles/org.openhab.binding.sncf/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/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/openhab-addons diff --git a/bundles/org.openhab.binding.sncf/README.md b/bundles/org.openhab.binding.sncf/README.md new file mode 100644 index 0000000000000..0c6ad36a733f1 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/README.md @@ -0,0 +1,87 @@ +# SNCF Binding + +The SNCF binding provides real-time data(*) for each train, bus, tramway... station in France. +This is based on live API provided by DIGITALSNCF. + +Get your API key on [DIGITALSNCF web site](https://www.digital.sncf.com/startup/api/token-developpeur) + +Note : SNCF Api is based on the open [API Navitia](https://doc.navitia.io/#getting-started). +This binding uses a very small subset of it, restricted to its primary purpose. + +(*) According to DIGITALSNCF Transilien may only be available for schedule, maybe not real-time. + +## Supported Things + +Bridge: The binding supports a bridge to connect to the [DIGITALSNCF service](https://www.digital.sncf.com/startup/api/token developpeur). +A bridge uses the thing ID "api". + +Station: Represents a given bus, train station. + +Of course, you can add as many stations as needed. + + +## Discovery + +This binding takes care of auto discovery. This method is strongly recommended as it is the only way to get proper station ID depending upon transportation type. + +To enable auto-discovery, your location system setting must be defined. +Once done, at first launch, discovery will search every station in a radius of 2000 m around the system, extending it by step of 500 m until it finds a first set of results. +Every following manual successive launch will extend this radius by 500 m, increasing the number of stations discovered. + + +## Binding Configuration + +The binding has no configuration options, all configuration is done at Thing level. + +## Bridge Configuration + +The bridge configuration only holds the api key : + +| Parameter | Description | +|-----------|----------------------------------------------------------------| +| apiID | API ID provided by the DIGITALSNCF service. Mandatory. | + +## Thing Configuration + +The 'Station' thing has only one configuration parameter: + +| Parameter | Description | +|-------------|--------------------------------------------------------------| +| stopPointId | Identifier of the station in the DIGITALSNCF network. | + +The thing will auto-update depending on the timestamp of the earliest event detected to trigger (arrival or departure). + +## Channels + +The Station thing holds two groups of channels (arrivals and departures) containing these channels: + +| Channel ID | Item Type | Description | +|-----------------------|-----------|--------------------------------------------------| +| direction | String | The direction of the route | +| lineName | String | Commercial name of the line | +| name | String | Name of the line | +| network | String | Name of the network ruling the line | +| timestamp | DateTime | Timestamp of the event (departure, arrival) | + +## Full Example + +sncf.things: + +``` +Bridge sncf:api:8901d44a68 "Bridge" [apiID="xxx-yyy-zzz"] { + station MyHouse "Krakow"[stopPointId="stop_point:SNCF:87561951:Bus"] +} +``` + +sncf.items: + +``` +String Arrival_Direction { channel="sncf:station:8901d44a68:87381475_RapidTransit:arrivals#direction" } +String Arrival_Line { channel="sncf:station:8901d44a68:87381475_RapidTransit:arrivals#lineName" } +DateTime Arrival_Time { channel="sncf:station:8901d44a68:87381475_RapidTransit:arrivals#timestamp" } +String Departure_Direction { channel="sncf:station:8901d44a68:87381475_RapidTransit:departures#direction" } +String Departure_Line { channel="sncf:station:8901d44a68:87381475_RapidTransit:departures#lineName" } +DateTime Departure_Time { channel="sncf:station:8901d44a68:87381475_RapidTransit:departures#timestamp" } + +``` + diff --git a/bundles/org.openhab.binding.sncf/pom.xml b/bundles/org.openhab.binding.sncf/pom.xml new file mode 100644 index 0000000000000..aefe5411519fe --- /dev/null +++ b/bundles/org.openhab.binding.sncf/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.sncf + + openHAB Add-ons :: Bundles :: SNCF Binding + + diff --git a/bundles/org.openhab.binding.sncf/src/main/feature/feature.xml b/bundles/org.openhab.binding.sncf/src/main/feature/feature.xml new file mode 100644 index 0000000000000..7acc033cab63f --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.sncf/${project.version} + + diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfBindingConstants.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfBindingConstants.java new file mode 100644 index 0000000000000..8f68576e8e508 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfBindingConstants.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link SncfBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class SncfBindingConstants { + + public static final String BINDING_ID = "sncf"; + + // Station properties + public static final String STOP_POINT_ID = "stopPointId"; + public static final String DISTANCE = "Distance"; + public static final String LOCATION = "Location"; + public static final String TIMEZONE = "Timezone"; + + // List of Channel groups + public static final String GROUP_ARRIVAL = "arrivals"; + public static final String GROUP_DEPARTURE = "departures"; + + // List of Channel id's + public static final String DIRECTION = "direction"; + public static final String LINE_NAME = "lineName"; + public static final String NAME = "name"; + public static final String NETWORK = "network"; + public static final String TIMESTAMP = "timestamp"; + + // List of Thing Type UIDs + public static final ThingTypeUID APIBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "api"); + public static final ThingTypeUID STATION_THING_TYPE = new ThingTypeUID(BINDING_ID, "station"); + + // List of all adressable things + public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(APIBRIDGE_THING_TYPE, STATION_THING_TYPE); +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfException.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfException.java new file mode 100644 index 0000000000000..de12a40973385 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfException.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Exception for errors when using the SNCF API + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class SncfException extends Exception { + private static final long serialVersionUID = -6215621577081394328L; + + public SncfException(String label) { + super(label); + } + + public SncfException(Throwable e) { + super(e); + } + + public SncfException(@Nullable String message, @Nullable Throwable e) { + super(message, e); + } +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfHandlerFactory.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfHandlerFactory.java new file mode 100644 index 0000000000000..131e5d942ca5a --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/SncfHandlerFactory.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal; + +import static org.openhab.binding.sncf.internal.SncfBindingConstants.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.sncf.internal.handler.SncfBridgeHandler; +import org.openhab.binding.sncf.internal.handler.StationHandler; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * The {@link SncfHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.sncf", service = ThingHandlerFactory.class) +public class SncfHandlerFactory extends BaseThingHandlerFactory { + private final Logger logger = LoggerFactory.getLogger(SncfHandlerFactory.class); + private final LocationProvider locationProvider; + private final HttpClient httpClient; + private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .create(); + + @Activate + public SncfHandlerFactory(@Reference LocationProvider locationProvider, + final @Reference HttpClientFactory httpClientFactory) { + this.locationProvider = locationProvider; + this.httpClient = httpClientFactory.getCommonHttpClient(); + } + + @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 (APIBRIDGE_THING_TYPE.equals(thingTypeUID)) { + return new SncfBridgeHandler((Bridge) thing, gson, locationProvider, httpClient); + } else if (STATION_THING_TYPE.equals(thingTypeUID)) { + return new StationHandler(thing, locationProvider); + } + logger.warn("ThingHandler not found for {}", thing.getThingTypeUID()); + return null; + } +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/discovery/SncfDiscoveryService.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/discovery/SncfDiscoveryService.java new file mode 100644 index 0000000000000..73f96c6ce70d5 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/discovery/SncfDiscoveryService.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.discovery; + +import static org.openhab.binding.sncf.internal.SncfBindingConstants.*; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.sncf.internal.SncfException; +import org.openhab.binding.sncf.internal.dto.PlaceNearby; +import org.openhab.binding.sncf.internal.handler.SncfBridgeHandler; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.library.types.PointType; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link SncfDiscoveryService} searches for available + * station discoverable through API + * + * @author Gaël L'hopital - Initial contribution + */ +@Component(service = ThingHandlerService.class) +@NonNullByDefault +public class SncfDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService { + private static final int SEARCH_TIME = 7; + + private final Logger logger = LoggerFactory.getLogger(SncfDiscoveryService.class); + + private @Nullable LocationProvider locationProvider; + private @Nullable SncfBridgeHandler bridgeHandler; + + private int searchRange = 1500; + + @Activate + public SncfDiscoveryService() { + super(SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME, false); + } + + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + public void startScan() { + SncfBridgeHandler handler = bridgeHandler; + LocationProvider provider = locationProvider; + if (provider != null && handler != null) { + PointType location = provider.getLocation(); + if (location != null) { + ThingUID bridgeUID = handler.getThing().getUID(); + searchRange += 500; + try { + List places = handler.discoverNearby(location, searchRange); + if (places != null && !places.isEmpty()) { + places.forEach(place -> { + // stop_point:SNCF:87386573:Bus + List idElts = new LinkedList(Arrays.asList(place.id.split(":"))); + idElts.remove(0); + idElts.remove(0); + thingDiscovered(DiscoveryResultBuilder + .create(new ThingUID(STATION_THING_TYPE, bridgeUID, String.join("_", idElts))) + .withLabel(String.format("%s (%s)", place.stopPoint.name, idElts.get(1)) + .replace("-", "_")) + .withBridge(bridgeUID).withRepresentationProperty(STOP_POINT_ID) + .withProperty(STOP_POINT_ID, place.id).build()); + }); + } else { + logger.info("No station found in a perimeter of {} m, extending search", searchRange); + startScan(); + } + } catch (SncfException e) { + logger.warn("Error calling SNCF Api : {}", e.getMessage()); + } + } else { + logger.info("Please set a system location to enable station discovery"); + } + } + } + + @Override + public void setThingHandler(ThingHandler handler) { + if (handler instanceof SncfBridgeHandler) { + this.bridgeHandler = (SncfBridgeHandler) handler; + this.locationProvider = ((SncfBridgeHandler) handler).getLocationProvider(); + } + } + + @Override + public @Nullable ThingHandler getThingHandler() { + return bridgeHandler; + } +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Coord.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Coord.java new file mode 100644 index 0000000000000..7441c5c7f7b6d --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Coord.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link Coord} class holds latitude and longitude of a point + * + * @author Gaël L'hopital - Initial contribution + */ +public class Coord { + public String lat; + public String lon; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/NavitiaObject.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/NavitiaObject.java new file mode 100644 index 0000000000000..56b514aaa9b16 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/NavitiaObject.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link NavitiaObject} base class for API objects + * + * @author Gaël L'hopital - Initial contribution + */ +public class NavitiaObject { + public String id; + public String name; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passage.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passage.java new file mode 100644 index 0000000000000..0a9fbe6945301 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passage.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link Passage} holds data regarding a transportation + * information passing at a given station + * + * @author Gaël L'hopital - Initial contribution + */ +public class Passage { + public VJDisplayInformation displayInformations; + public StopDateTime stopDateTime; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passages.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passages.java new file mode 100644 index 0000000000000..f4988bf3c2e9f --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/Passages.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +import java.util.List; + +import org.eclipse.jdt.annotation.Nullable; + +import com.google.gson.annotations.SerializedName; + +/** + * The {@link Passages} is responsible for storing + * list of arrivals or departures depending upon called API + * + * @author Gaël L'hopital - Initial contribution + */ +public class Passages extends SncfAnswer { + @SerializedName(value = "departures", alternate = "arrivals") + public @Nullable List passages; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlaceNearby.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlaceNearby.java new file mode 100644 index 0000000000000..a2931351a83b3 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlaceNearby.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link PlaceNearby} holds data returned by the API call + * + * @author Gaël L'hopital - Initial contribution + */ +public class PlaceNearby extends NavitiaObject { + public StopPoint stopPoint; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlacesNearby.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlacesNearby.java new file mode 100644 index 0000000000000..9141872b77d0f --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/PlacesNearby.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +import java.util.List; + +/** + * The {@link PlacesNearby} holds a list or nearby places. + * + * @author Gaël L'hopital - Initial contribution + */ +public class PlacesNearby extends SncfAnswer { + public List placesNearby; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/SncfAnswer.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/SncfAnswer.java new file mode 100644 index 0000000000000..b572f84693103 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/SncfAnswer.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link SncfAnswer} is the base class for all Sncf API requests + * + * @author Gaël L'hopital - Initial contribution + */ +public abstract class SncfAnswer { + public Error error; + public String message; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopArea.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopArea.java new file mode 100644 index 0000000000000..706874a1f8536 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopArea.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link StopArea} class holds informations for a Stop Area + * (usually a train station) + * + * @author Gaël L'hopital - Initial contribution + */ +public class StopArea extends NavitiaObject { + public String timezone; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopDateTime.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopDateTime.java new file mode 100644 index 0000000000000..0bcce5cd81bbf --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopDateTime.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link StopDateTime} class holds informations for a transportation stop + * + * @author Gaël L'hopital - Initial contribution + */ +public class StopDateTime { + public String arrivalDateTime; + public String departureDateTime; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoint.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoint.java new file mode 100644 index 0000000000000..e372dc15e5629 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoint.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link StopPoint} class holds informations for a train station + * + * @author Gaël L'hopital - Initial contribution + */ +public class StopPoint extends NavitiaObject { + public StopArea stopArea; + public Coord coord; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoints.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoints.java new file mode 100644 index 0000000000000..578d33e1fcf12 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/StopPoints.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +import java.util.List; + +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link StopPoints} holds a list of Stop Points. + * + * @author Gaël L'hopital - Initial contribution + */ +public class StopPoints extends SncfAnswer { + public @Nullable List stopPoints; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/VJDisplayInformation.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/VJDisplayInformation.java new file mode 100644 index 0000000000000..7e182f6a6dc9e --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/dto/VJDisplayInformation.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.dto; + +/** + * The {@link VJDisplayInformation} class holds informations displayed + * to traveller regarding a stop in the station + * + * @author Gaël L'hopital - Initial contribution + */ +public class VJDisplayInformation { + public String code; + public String network; + public String name; + public String commercialMode; + public String direction; +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/SncfBridgeHandler.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/SncfBridgeHandler.java new file mode 100644 index 0000000000000..0ef7fb05001a1 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/SncfBridgeHandler.java @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.handler; + +import static org.eclipse.jetty.http.HttpMethod.GET; +import static org.eclipse.jetty.http.HttpStatus.OK_200; + +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpHeader; +import org.openhab.binding.sncf.internal.SncfException; +import org.openhab.binding.sncf.internal.discovery.SncfDiscoveryService; +import org.openhab.binding.sncf.internal.dto.Passage; +import org.openhab.binding.sncf.internal.dto.Passages; +import org.openhab.binding.sncf.internal.dto.PlaceNearby; +import org.openhab.binding.sncf.internal.dto.PlacesNearby; +import org.openhab.binding.sncf.internal.dto.SncfAnswer; +import org.openhab.binding.sncf.internal.dto.StopPoint; +import org.openhab.binding.sncf.internal.dto.StopPoints; +import org.openhab.core.cache.ExpiringCacheMap; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.library.types.PointType; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; + +/** + * The {@link SncfBridgeHandler} is handles connection and communication toward + * SNCF API + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class SncfBridgeHandler extends BaseBridgeHandler { + public static final String JSON_CONTENT_TYPE = "application/json"; + + public static final String SERVICE_URL = "https://api.sncf.com/v1/coverage/sncf/"; + + private final Logger logger = LoggerFactory.getLogger(SncfBridgeHandler.class); + private final LocationProvider locationProvider; + private final ExpiringCacheMap cache = new ExpiringCacheMap<>(Duration.ofMinutes(1)); + private final HttpClient httpClient; + + private final Gson gson; + private @NonNullByDefault({}) String apiId; + + public SncfBridgeHandler(Bridge bridge, Gson gson, LocationProvider locationProvider, HttpClient httpClient) { + super(bridge); + this.locationProvider = locationProvider; + this.httpClient = httpClient; + this.gson = gson; + } + + @Override + public void initialize() { + logger.debug("Initializing SNCF API bridge handler."); + apiId = (String) getConfig().get("apiID"); + if (apiId != null && !apiId.isBlank()) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/null-or-empty-api-key"); + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.debug("SNCF API Bridge is read-only and does not handle commands"); + } + + private T getResponseFromCache(String url, Class objectClass) throws SncfException { + String answer = cache.putIfAbsentAndGet(url, () -> getResponse(url)); + try { + if (answer != null) { + @Nullable + T response = gson.fromJson(answer, objectClass); + if (response == null) { + throw new SncfException("Unable to deserialize API answer"); + } + if (response.message != null) { + throw new SncfException(response.message); + } + return response; + } else { + throw new SncfException(String.format("Unable to get api answer for url : %s", url)); + } + } catch (JsonSyntaxException e) { + throw new SncfException(e); + } + } + + private @Nullable String getResponse(String url) { + try { + logger.debug("SNCF Api request: url = '{}'", url); + ContentResponse contentResponse = httpClient.newRequest(url).method(GET).timeout(10, TimeUnit.SECONDS) + .header(HttpHeader.AUTHORIZATION, apiId).send(); + int httpStatus = contentResponse.getStatus(); + String content = contentResponse.getContentAsString(); + logger.debug("SNCF Api response: status = {}, content = '{}'", httpStatus, content); + if (httpStatus == OK_200) { + return content; + } + logger.debug("SNCF Api server responded with status code {}: {}", httpStatus, content); + } catch (TimeoutException | ExecutionException e) { + logger.debug("Execution occured : {}", e.getMessage(), e); + } catch (InterruptedException e) { + logger.debug("Execution interrupted : {}", e.getMessage(), e); + Thread.currentThread().interrupt(); + } + return null; + } + + public @Nullable List discoverNearby(PointType location, int distance) throws SncfException { + String url = String.format(Locale.US, "%scoord/%.5f;%.5f/places_nearby?distance=%d&type[]=stop_point&count=100", + SERVICE_URL, location.getLongitude().floatValue(), location.getLatitude().floatValue(), distance); + PlacesNearby places = getResponseFromCache(url, PlacesNearby.class); + return places.placesNearby; + } + + public Optional stopPointDetail(String stopPointId) throws SncfException { + String url = String.format("%sstop_points/%s", SERVICE_URL, stopPointId); + List points = getResponseFromCache(url, StopPoints.class).stopPoints; + return points != null && !points.isEmpty() ? Optional.ofNullable(points.get(0)) : Optional.empty(); + } + + public Optional getNextPassage(String stopPointId, String expected) throws SncfException { + String url = String.format("%sstop_points/%s/%s?disable_geojson=true&count=1", SERVICE_URL, stopPointId, + expected); + List passages = getResponseFromCache(url, Passages.class).passages; + return passages != null && !passages.isEmpty() ? Optional.ofNullable(passages.get(0)) : Optional.empty(); + } + + public LocationProvider getLocationProvider() { + return locationProvider; + } + + @Override + public Collection> getServices() { + return Set.of(SncfDiscoveryService.class); + } +} diff --git a/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/StationHandler.java b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/StationHandler.java new file mode 100644 index 0000000000000..855199219aad8 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/java/org/openhab/binding/sncf/internal/handler/StationHandler.java @@ -0,0 +1,259 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sncf.internal.handler; + +import static org.openhab.binding.sncf.internal.SncfBindingConstants.*; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.sncf.internal.SncfException; +import org.openhab.binding.sncf.internal.dto.Passage; +import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.PointType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingStatusInfo; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.BridgeHandler; +import org.openhab.core.thing.binding.builder.ThingBuilder; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link StationHandler} is responsible for handling commands, which are sent + * to one of the channels. + * + * @author Gaël L'hopital - Initial contribution + */ +@NonNullByDefault +public class StationHandler extends BaseThingHandler { + private static final DateTimeFormatter NAVITIA_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssZ"); + + private final Logger logger = LoggerFactory.getLogger(StationHandler.class); + private final LocationProvider locationProvider; + + private @Nullable ScheduledFuture refreshJob; + private @NonNullByDefault({}) String stationId; + private @NonNullByDefault({}) String zoneOffset; + + public StationHandler(Thing thing, LocationProvider locationProvider) { + super(thing); + this.locationProvider = locationProvider; + } + + @Override + public void initialize() { + logger.trace("Initializing the Station handler for {}", getThing().getUID()); + + stationId = (String) getConfig().get("stopPointId"); + if (stationId == null || stationId.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/null-or-empty-station-id"); + return; + } + + if (thing.getProperties().isEmpty() && !discoverAttributes(stationId)) { + return; + } + + String timezone = thing.getProperties().get(TIMEZONE); + if (timezone == null || timezone.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/null-or-empty-timezone"); + return; + } + + zoneOffset = ZoneId.of(timezone).getRules().getOffset(Instant.now()).getId().replace(":", ""); + scheduleRefresh(ZonedDateTime.now().plusSeconds(2)); + updateStatus(ThingStatus.ONLINE); + } + + @Override + public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + super.bridgeStatusChanged(bridgeStatusInfo); + if (thing.getStatus() == ThingStatus.ONLINE) { + initialize(); + } + } + + private boolean discoverAttributes(String localStation) { + SncfBridgeHandler bridgeHandler = getBridgeHandler(); + if (bridgeHandler != null) { + Map properties = new HashMap<>(); + try { + bridgeHandler.stopPointDetail(localStation).ifPresent(stopPoint -> { + String stationLoc = String.format("%s,%s", stopPoint.coord.lat, stopPoint.coord.lon); + properties.put(LOCATION, stationLoc); + properties.put(TIMEZONE, stopPoint.stopArea.timezone); + PointType serverLoc = locationProvider.getLocation(); + if (serverLoc != null) { + PointType stationLocation = new PointType(stationLoc); + double distance = serverLoc.distanceFrom(stationLocation).doubleValue(); + properties.put(DISTANCE, new QuantityType<>(distance, SIUnits.METRE).toString()); + } + }); + ThingBuilder thingBuilder = editThing(); + thingBuilder.withProperties(properties); + updateThing(thingBuilder.build()); + return true; + } catch (SncfException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + } + } + return false; + } + + private void scheduleRefresh(@Nullable ZonedDateTime when) { + // Ensure we'll try to refresh in one minute if no valid timestamp is provided + long wishedDelay = ZonedDateTime.now().until(when != null ? when : ZonedDateTime.now().plusMinutes(1), + ChronoUnit.SECONDS); + wishedDelay = wishedDelay < 0 ? 60 : wishedDelay; + logger.debug("wishedDelay is {} seconds", wishedDelay); + ScheduledFuture job = refreshJob; + if (job != null) { + long existingDelay = job.getDelay(TimeUnit.SECONDS); + logger.debug("existingDelay is {} seconds", existingDelay); + if (existingDelay < wishedDelay && existingDelay > 0) { + logger.debug("Do nothing, existingDelay earlier than wishedDelay"); + return; + } + freeRefreshJob(); + } + logger.debug("Scheduling update in {} seconds.", wishedDelay); + refreshJob = scheduler.schedule(() -> updateThing(), wishedDelay, TimeUnit.SECONDS); + } + + private void updateThing() { + SncfBridgeHandler bridgeHandler = getBridgeHandler(); + if (bridgeHandler != null) { + scheduler.submit(() -> { + updatePassage(bridgeHandler, GROUP_ARRIVAL); + updatePassage(bridgeHandler, GROUP_DEPARTURE); + }); + } + } + + private void updatePassage(SncfBridgeHandler bridgeHandler, String direction) { + try { + bridgeHandler.getNextPassage(stationId, direction).ifPresentOrElse(passage -> { + getThing().getChannels().stream().map(Channel::getUID) + .filter(channelUID -> isLinked(channelUID) && direction.equals(channelUID.getGroupId())) + .forEach(channelUID -> { + State state = getValue(channelUID.getIdWithoutGroup(), passage, direction); + updateState(channelUID, state); + }); + ZonedDateTime eventTime = getEventTimestamp(passage, direction); + if (eventTime != null) { + scheduleRefresh(eventTime.plusSeconds(10)); + } + }, () -> { + logger.debug("No {} available", direction); + scheduleRefresh(ZonedDateTime.now().plusMinutes(5)); + }); + updateStatus(ThingStatus.ONLINE); + } catch (SncfException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + freeRefreshJob(); + } + } + + private State getValue(String channelId, Passage passage, String direction) { + switch (channelId) { + case DIRECTION: + return fromNullableString(passage.displayInformations.direction); + case LINE_NAME: + return fromNullableString(String.format("%s %s", passage.displayInformations.commercialMode, + passage.displayInformations.code)); + case NAME: + return fromNullableString(passage.displayInformations.name); + case NETWORK: + return fromNullableString(passage.displayInformations.network); + case TIMESTAMP: + return fromNullableTime(passage, direction); + } + return UnDefType.NULL; + } + + private State fromNullableString(@Nullable String aValue) { + return aValue != null ? StringType.valueOf(aValue) : UnDefType.NULL; + } + + private @Nullable ZonedDateTime getEventTimestamp(Passage passage, String direction) { + String eventTime = direction.equals(GROUP_ARRIVAL) ? passage.stopDateTime.arrivalDateTime + : passage.stopDateTime.departureDateTime; + return eventTime != null ? ZonedDateTime.parse(eventTime + zoneOffset, NAVITIA_DATE_FORMAT) : null; + } + + private State fromNullableTime(Passage passage, String direction) { + ZonedDateTime timestamp = getEventTimestamp(passage, direction); + return timestamp != null ? new DateTimeType(timestamp) : UnDefType.NULL; + } + + private void freeRefreshJob() { + ScheduledFuture job = refreshJob; + if (job != null) { + job.cancel(true); + this.refreshJob = null; + } + } + + @Override + public void dispose() { + freeRefreshJob(); + super.dispose(); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (command instanceof RefreshType) { + updateThing(); + } + } + + private @Nullable SncfBridgeHandler getBridgeHandler() { + Bridge bridge = getBridge(); + if (bridge != null) { + BridgeHandler handler = bridge.getHandler(); + if (handler != null) { + if (handler.getThing().getStatus() == ThingStatus.ONLINE) { + return (SncfBridgeHandler) handler; + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + return null; + } + } + } + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED); + return null; + } +} diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..e756b395d0d29 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + SNCF Binding + Retrieves French railway informations + + diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/config/config.xml new file mode 100644 index 0000000000000..d96cf36e38e8e --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/config/config.xml @@ -0,0 +1,15 @@ + + + + + + + password + + + + diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf.properties b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf.properties new file mode 100644 index 0000000000000..1b02bcf8288c8 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf.properties @@ -0,0 +1,36 @@ + +binding.sncf.name = SNCF Binding +binding.sncf.description = Retrieves French railway informations + +config.thing-type.sncf.api.apiID.label = API ID +config.thing-type.sncf.api.apiID.description = Your SNCF API ID + +thing-type.sncf.api.label = SNCF API +thing-type.sncf.api.description = This bridge is the gateway to SNCF API. + +thing-type.sncf.station.label = Station +thing-type.sncf.station.description = Represents a station hosting some transportation mode. +thing-type.sncf.station.group.arrivals.label = Next Arrival +thing-type.sncf.station.group.arrivals.description = Informations regarding next arrival at the station. +thing-type.sncf.station.group.departures.label = Next Departure +thing-type.sncf.station.group.departures.description = Informations regarding next departure from the station. + +thing-type.config.sncf.station.stopPointId.label = Stop Point ID +thing-type.config.sncf.station.stopPointId.description = The stop point ID of the station as defined by DIGITALSNCF. + +channel-type.sncf.direction.label = Direction +channel-type.sncf.direction.description = The direction of this route. +channel-type.sncf.lineName.label = Line +channel-type.sncf.lineName.description = Name of the line (network + line number/letter) +channel-type.sncf.name.label = Name +channel-type.sncf.name.description = Name of the line. +channel-type.sncf.network.label = Network +channel-type.sncf.network.description = Name of the transportation network. +channel-type.sncf.timestamp.label = Timestamp +channel-type.sncf.timestamp.description = Timestamp of the future event. + +# Error messages +null-or-empty-api-key = Null or empty API ID +error-invalid-apikey = Invalid API ID +null-or-empty-station-id = Null or empty Station ID +null-or-empty-timezone = Timezone is empty. It should have been set at first initialization. diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/bridge.xml b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/bridge.xml new file mode 100644 index 0000000000000..ab99f53c25924 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/bridge.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/station.xml b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/station.xml new file mode 100644 index 0000000000000..495b8c1bf6192 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/thing/station.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + stopPointId + + + + + + + + + + + + + + + + + + + + + String + + + + + + String + + + + + + String + + + + + + String + + + + + + DateTime + + time + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 2932a8d104698..25f301f453e4f 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -312,6 +312,7 @@ org.openhab.binding.smartmeter org.openhab.binding.smhi org.openhab.binding.smartthings + org.openhab.binding.sncf org.openhab.binding.snmp org.openhab.binding.solaredge org.openhab.binding.solarlog From 637ad1dc1c6a0054be5e3bd844a0bca10250f2aa Mon Sep 17 00:00:00 2001 From: bruestel Date: Sun, 5 Dec 2021 09:30:35 +0100 Subject: [PATCH 171/361] [homeconnect] Add oven control (#11706) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jonas Brüstel Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.homeconnect/README.md | 5 ----- .../homeconnect/internal/HomeConnectBindingConstants.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.homeconnect/README.md b/bundles/org.openhab.binding.homeconnect/README.md index 6612b0545426d..a03c8a9dcba64 100644 --- a/bundles/org.openhab.binding.homeconnect/README.md +++ b/bundles/org.openhab.binding.homeconnect/README.md @@ -285,11 +285,6 @@ Otherwise, all you need to do is re-authorize your bridge. ## FAQ -### I can't start my oven via openHAB. - -Some operations are not possible at the moment. You need to sign an "Additional Partner Agreement". Please have a look at: -https://developer.home-connect.com/docs/authorization/scope - ### I can't switch remote start to on. The channel of type `remote_start_allowance_state` is read only. You can only enable it directly on the physical appliance. diff --git a/bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/HomeConnectBindingConstants.java b/bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/HomeConnectBindingConstants.java index 6718f41ac0834..364e591e2460d 100644 --- a/bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/HomeConnectBindingConstants.java +++ b/bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/HomeConnectBindingConstants.java @@ -241,7 +241,7 @@ public class HomeConnectBindingConstants { public static final String API_SIMULATOR_BASE_URL = "https://simulator.home-connect.com"; public static final String OAUTH_TOKEN_PATH = "/security/oauth/token"; public static final String OAUTH_AUTHORIZE_PATH = "/security/oauth/authorize"; - public static final String OAUTH_SCOPE = "IdentifyAppliance Monitor Settings Dishwasher-Control Washer-Control Dryer-Control WasherDryer-Control CoffeeMaker-Control Hood-Control CleaningRobot-Control"; + public static final String OAUTH_SCOPE = "IdentifyAppliance Monitor Settings Dishwasher-Control Washer-Control Dryer-Control WasherDryer-Control CoffeeMaker-Control Hood-Control Oven-Control CleaningRobot-Control"; // Operation states public static final String OPERATION_STATE_INACTIVE = "BSH.Common.EnumType.OperationState.Inactive"; From 4858f95138498eeee7cc51e3b1993b7eb57383d8 Mon Sep 17 00:00:00 2001 From: Doug Culnane <32482395+dougculnane@users.noreply.github.com> Date: Sun, 5 Dec 2021 09:33:32 +0100 Subject: [PATCH 172/361] [renault] Initial Contribution (#11467) * #11465 Initial renault-api binding Signed-off-by: Doug Culnane Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + bundles/org.openhab.binding.renault/NOTICE | 13 + bundles/org.openhab.binding.renault/README.md | 43 +++ bundles/org.openhab.binding.renault/pom.xml | 17 ++ .../src/main/feature/feature.xml | 9 + .../internal/RenaultBindingConstants.java | 38 +++ .../internal/RenaultConfiguration.java | 30 ++ .../internal/RenaultHandlerFactory.java | 67 +++++ .../binding/renault/internal/api/Car.java | 214 ++++++++++++++ .../renault/internal/api/Constants.java | 238 ++++++++++++++++ .../internal/api/MyRenaultHttpSession.java | 264 ++++++++++++++++++ .../api/exceptions/RenaultException.java | 30 ++ .../exceptions/RenaultForbiddenException.java | 31 ++ .../RenaultNotImplementedException.java | 31 ++ .../exceptions/RenaultUpdateException.java | 30 ++ .../internal/handler/RenaultHandler.java | 207 ++++++++++++++ .../main/resources/OH-INF/binding/binding.xml | 9 + .../resources/OH-INF/thing/thing-types.xml | 94 +++++++ bundles/pom.xml | 1 + 20 files changed, 1372 insertions(+) create mode 100644 bundles/org.openhab.binding.renault/NOTICE create mode 100644 bundles/org.openhab.binding.renault/README.md create mode 100644 bundles/org.openhab.binding.renault/pom.xml create mode 100644 bundles/org.openhab.binding.renault/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultBindingConstants.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultConfiguration.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultHandlerFactory.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Car.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Constants.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/MyRenaultHttpSession.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultException.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultForbiddenException.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultNotImplementedException.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultUpdateException.java create mode 100644 bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/handler/RenaultHandler.java create mode 100644 bundles/org.openhab.binding.renault/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.renault/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/CODEOWNERS b/CODEOWNERS index 24d62cddb60bd..aefb2968aea4b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -254,6 +254,7 @@ /bundles/org.openhab.binding.regoheatpump/ @crnjan /bundles/org.openhab.binding.revogi/ @andibraeu /bundles/org.openhab.binding.remoteopenhab/ @lolodomo +/bundles/org.openhab.binding.renault/ @dougculnane /bundles/org.openhab.binding.resol/ @ramack /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 d3f73e8240e68..79751a4f01223 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1256,6 +1256,11 @@ org.openhab.binding.remoteopenhab ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.renault + ${project.version} + org.openhab.addons.bundles org.openhab.binding.resol diff --git a/bundles/org.openhab.binding.renault/NOTICE b/bundles/org.openhab.binding.renault/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.renault/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/openhab-addons diff --git a/bundles/org.openhab.binding.renault/README.md b/bundles/org.openhab.binding.renault/README.md new file mode 100644 index 0000000000000..d6533bf7f11fc --- /dev/null +++ b/bundles/org.openhab.binding.renault/README.md @@ -0,0 +1,43 @@ +# Renault Binding + +This binding allow MyRenault App. users to get battery status and other data from their cars. + +A binding that translates the [python based renault-api](https://renault-api.readthedocs.io/en/latest/) in an easy to use binding. + + +## Supported Things + +Supports MyRenault registered cars with an active Connected-Services account. + +This binding can only retrieve information that is available in the the MyRenault App. + + +## Discovery + +No discovery + +## Thing Configuration + +You require your MyRenault credential, locale and VIN for your MyRenault registered car. + +| Parameter | Description | Required | +|-------------------|----------------------------------------|----------| +| myRenaultUsername | MyRenault Username. | yes | +| myRenaultPassword | MyRenault Password. | yes | +| locale | MyRenault Location (language_country). | yes | +| vin | Vehicle Identification Number. | yes | +| refreshInterval | Interval the car is polled in minutes. | no | + +## Channels + +Currently all available channels are read only: + +| Channel ID | Type | Description | +|--------------|---------------|---------------------------------| +| batterylevel | Number | State of the battery in % | +| hvacstatus | Switch | HVAC status switch | +| image | String | Image URL of MyRenault | +| location | Location | The GPS position of the vehicle | +| odometer | Number:Length | Total distance travelled | + + diff --git a/bundles/org.openhab.binding.renault/pom.xml b/bundles/org.openhab.binding.renault/pom.xml new file mode 100644 index 0000000000000..bbd7abe02f806 --- /dev/null +++ b/bundles/org.openhab.binding.renault/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + + org.openhab.binding.renault + + openHAB Add-ons :: Bundles :: Renault Binding + + diff --git a/bundles/org.openhab.binding.renault/src/main/feature/feature.xml b/bundles/org.openhab.binding.renault/src/main/feature/feature.xml new file mode 100644 index 0000000000000..e443ed5c5c6cb --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.renault/${project.version} + + diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultBindingConstants.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultBindingConstants.java new file mode 100644 index 0000000000000..fd22c3f88abe1 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultBindingConstants.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link RenaultBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultBindingConstants { + + private static final String BINDING_ID = "renault"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_CAR = new ThingTypeUID(BINDING_ID, "car"); + + // List of all Channel ids + public static final String CHANNEL_BATTERY_LEVEL = "batterylevel"; + public static final String CHANNEL_HVAC_STATUS = "hvacstatus"; + public static final String CHANNEL_IMAGE = "image"; + public static final String CHANNEL_LOCATION = "location"; + public static final String CHANNEL_ODOMETER = "odometer"; +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultConfiguration.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultConfiguration.java new file mode 100644 index 0000000000000..8040c4241658d --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultConfiguration.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link RenaultConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultConfiguration { + + public String myRenaultUsername = ""; + public String myRenaultPassword = ""; + public String locale = ""; + public String vin = ""; + public int refreshInterval = 10; +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultHandlerFactory.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultHandlerFactory.java new file mode 100644 index 0000000000000..7561d811cb6e3 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/RenaultHandlerFactory.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal; + +import static org.openhab.binding.renault.internal.RenaultBindingConstants.*; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.renault.internal.handler.RenaultHandler; +import org.openhab.core.io.net.http.HttpClientFactory; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link RenaultHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.renault", service = ThingHandlerFactory.class) +public class RenaultHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_CAR); + + private final HttpClient httpClient; + + @Activate + public RenaultHandlerFactory(final @Reference HttpClientFactory httpClientFactory) { + this.httpClient = httpClientFactory.getCommonHttpClient(); + } + + @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_CAR.equals(thingTypeUID)) { + return new RenaultHandler(thing, httpClient); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Car.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Car.java new file mode 100644 index 0000000000000..fec7c182f0ae7 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Car.java @@ -0,0 +1,214 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * MyRenault registered car for parsing HTTP responses and collecting data and + * information. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class Car { + + private final Logger logger = LoggerFactory.getLogger(Car.class); + + private boolean disableLocation = false; + private boolean disableBattery = false; + private boolean disableCockpit = false; + private boolean disableHvac = false; + + private @Nullable Double batteryLevel; + private @Nullable Boolean hvacstatus; + private @Nullable Double odometer; + private @Nullable String imageURL; + private @Nullable Double gpsLatitude; + private @Nullable Double gpsLongitude; + + public void setBatteryStatus(JsonObject responseJson) { + try { + JsonObject attributes = getAttributes(responseJson); + if (attributes != null && attributes.get("batteryLevel") != null) { + batteryLevel = attributes.get("batteryLevel").getAsDouble(); + } + } catch (IllegalStateException | ClassCastException e) { + logger.warn("Error {} parsing Battery Status: {}", e.getMessage(), responseJson); + } + } + + public void setHVACStatus(JsonObject responseJson) { + try { + JsonObject attributes = getAttributes(responseJson); + if (attributes != null && attributes.get("hvacStatus") != null) { + hvacstatus = attributes.get("hvacStatus").getAsString().equals("on"); + } + } catch (IllegalStateException | ClassCastException e) { + logger.warn("Error {} parsing HVAC Status: {}", e.getMessage(), responseJson); + } + } + + public void setCockpit(JsonObject responseJson) { + try { + JsonObject attributes = getAttributes(responseJson); + if (attributes != null && attributes.get("totalMileage") != null) { + odometer = attributes.get("totalMileage").getAsDouble(); + } + } catch (IllegalStateException | ClassCastException e) { + logger.warn("Error {} parsing Cockpit: {}", e.getMessage(), responseJson); + } + } + + public void setLocation(JsonObject responseJson) { + try { + JsonObject attributes = getAttributes(responseJson); + if (attributes != null) { + if (attributes.get("gpsLatitude") != null) { + gpsLatitude = attributes.get("gpsLatitude").getAsDouble(); + } + if (attributes.get("gpsLongitude") != null) { + gpsLongitude = attributes.get("gpsLongitude").getAsDouble(); + } + } + } catch (IllegalStateException | ClassCastException e) { + logger.warn("Error {} parsing Location: {}", e.getMessage(), responseJson); + } + } + + public void setDetails(JsonObject responseJson) { + try { + if (responseJson.get("assets") != null) { + JsonArray assetsJson = responseJson.get("assets").getAsJsonArray(); + String url = null; + for (JsonElement asset : assetsJson) { + if (asset.getAsJsonObject().get("assetType") != null + && asset.getAsJsonObject().get("assetType").getAsString().equals("PICTURE")) { + if (asset.getAsJsonObject().get("renditions") != null) { + JsonArray renditions = asset.getAsJsonObject().get("renditions").getAsJsonArray(); + for (JsonElement rendition : renditions) { + if (rendition.getAsJsonObject().get("resolutionType") != null + && rendition.getAsJsonObject().get("resolutionType").getAsString() + .equals("ONE_MYRENAULT_SMALL")) { + url = rendition.getAsJsonObject().get("url").getAsString(); + break; + } + } + } + } + if (url != null && !url.isEmpty()) { + imageURL = url; + break; + } + } + } + } catch (IllegalStateException | ClassCastException e) { + logger.warn("Error {} parsing Details: {}", e.getMessage(), responseJson); + } + } + + public boolean isDisableLocation() { + return disableLocation; + } + + public void setDisableLocation(boolean disableLocation) { + this.disableLocation = disableLocation; + } + + public boolean isDisableBattery() { + return disableBattery; + } + + public void setDisableBattery(boolean disableBattery) { + this.disableBattery = disableBattery; + } + + public boolean isDisableCockpit() { + return disableCockpit; + } + + public void setDisableCockpit(boolean disableCockpit) { + this.disableCockpit = disableCockpit; + } + + public boolean isDisableHvac() { + return disableHvac; + } + + public void setDisableHvac(boolean disableHvac) { + this.disableHvac = disableHvac; + } + + public @Nullable Double getBatteryLevel() { + return batteryLevel; + } + + public void setBatteryLevel(Double batteryLevel) { + this.batteryLevel = batteryLevel; + } + + public @Nullable Boolean getHvacstatus() { + return hvacstatus; + } + + public void setHvacstatus(Boolean hvacstatus) { + this.hvacstatus = hvacstatus; + } + + public @Nullable Double getOdometer() { + return odometer; + } + + public void setOdometer(Double odometer) { + this.odometer = odometer; + } + + public @Nullable String getImageURL() { + return imageURL; + } + + public void setImageURL(String imageURL) { + this.imageURL = imageURL; + } + + public @Nullable Double getGpsLatitude() { + return gpsLatitude; + } + + public void setGpsLatitude(Double gpsLatitude) { + this.gpsLatitude = gpsLatitude; + } + + public @Nullable Double getGpsLongitude() { + return gpsLongitude; + } + + public void setGpsLongitude(Double gpsLongitude) { + this.gpsLongitude = gpsLongitude; + } + + private @Nullable JsonObject getAttributes(JsonObject responseJson) + throws IllegalStateException, ClassCastException { + if (responseJson.get("data") != null && responseJson.get("data").getAsJsonObject().get("attributes") != null) { + return responseJson.get("data").getAsJsonObject().get("attributes").getAsJsonObject(); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Constants.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Constants.java new file mode 100644 index 0000000000000..45170ba9522a3 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/Constants.java @@ -0,0 +1,238 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Constants for Renault API. + * + * https://github.com/hacf-fr/renault-api/blob/main/src/renault_api/const.py + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class Constants { + + private static final String GIGYA_URL_EU = "https://accounts.eu1.gigya.com"; + private static final String GIGYA_URL_US = "https://accounts.us1.gigya.com"; + private static final String KAMEREON_APIKEY = "Ae9FDWugRxZQAGm3Sxgk7uJn6Q4CGEA2"; + private static final String KAMEREON_URL_EU = "https://api-wired-prod-1-euw1.wrd-aws.com"; + private static final String KAMEREON_URL_US = "https://api-wired-prod-1-usw2.wrd-aws.com"; + + private String gigyaApiKey = "gigya-api-key"; + private String gigyaRootUrl = "gigya-root-url"; + private String kamereonApiKey = "kamereon-api-key"; + private String kamereonRootUrl = "kamereon-root-url"; + + public Constants(final String locale) { + switch (locale) { + case "bg_BG": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3__3ER_6lFvXEXHTP_faLtq6eEdbKDXd9F5GoKwzRyZq37ZQ-db7mXcLzR1Jtls5sn"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "cs_CZ": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_oRlKr5PCVL_sPWUZdJ8c5NOl5Ej8nIZw7VKG7S9Rg36UkDszFzfHfxCaUAUU5or2"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "da_DK": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_5x-2C8b1R4MJPQXkwTPdIqgBpcw653Dakw_ZaEneQRkTBdg9UW9Qg_5G-tMNrTMc"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "de_DE": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_7PLksOyBRkHv126x5WhHb-5pqC1qFR8pQjxSeLB6nhAnPERTUlwnYoznHSxwX668"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "de_AT": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3__B4KghyeUb0GlpU62ZXKrjSfb7CPzwBS368wioftJUL5qXE0Z_sSy0rX69klXuHy"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "de_CH": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_UyiWZs_1UXYCUqK_1n7l7l44UiI_9N9hqwtREV0-UYA_5X7tOV-VKvnGxPBww4q2"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "en_GB": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "en_IE": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_Xn7tuOnT9raLEXuwSI1_sFFZNEJhSD0lv3gxkwFtGI-RY4AgiePBiJ9EODh8d9yo"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "es_ES": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_DyMiOwEaxLcPdBTu63Gv3hlhvLaLbW3ufvjHLeuU8U5bx3zx19t5rEKq7KMwk9f1"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "es_MX": + gigyaRootUrl = GIGYA_URL_US; + gigyaApiKey = "3_BFzR-2wfhMhUs5OCy3R8U8IiQcHS-81vF8bteSe8eFrboMTjEWzbf4pY1aHQ7cW0"; + kamereonRootUrl = KAMEREON_URL_US; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "fi_FI": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_xSRCLDYhk1SwSeYQLI3DmA8t-etfAfu5un51fws125ANOBZHgh8Lcc4ReWSwaqNY"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "fr_FR": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_4LKbCcMMcvjDm3X89LU4z4mNKYKdl_W0oD9w-Jvih21WqgJKtFZAnb9YdUgWT9_a"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "fr_BE": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_ZK9x38N8pzEvdiG7ojWHeOAAej43APkeJ5Av6VbTkeoOWR4sdkRc-wyF72HzUB8X"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "fr_CH": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_h3LOcrKZ9mTXxMI9clb2R1VGAWPke6jMNqMw4yYLz4N7PGjYyD0hqRgIFAIHusSn"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "fr_LU": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_zt44Wl_wT9mnqn-BHrR19PvXj3wYRPQKLcPbGWawlatFR837KdxSZZStbBTDaqnb"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "hr_HR": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_HcDC5GGZ89NMP1jORLhYNNCcXt7M3thhZ85eGrcQaM2pRwrgrzcIRWEYi_36cFj9"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "hu_HU": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_nGDWrkSGZovhnVFv5hdIxyuuCuJGZfNmlRGp7-5kEn9yb0bfIfJqoDa2opHOd3Mu"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "it_IT": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_js8th3jdmCWV86fKR3SXQWvXGKbHoWFv8NAgRbH7FnIBsi_XvCpN_rtLcI07uNuq"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "it_CH": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_gHkmHaGACxSLKXqD_uDDx415zdTw7w8HXAFyvh0qIP0WxnHPMF2B9K_nREJVSkGq"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "nl_NL": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_ZIOtjqmP0zaHdEnPK7h1xPuBYgtcOyUxbsTY8Gw31Fzy7i7Ltjfm-hhPh23fpHT5"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "nl_BE": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_yachztWczt6i1pIMhLIH9UA6DXK6vXXuCDmcsoA4PYR0g35RvLPDbp49YribFdpC"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "no_NO": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_QrPkEJr69l7rHkdCVls0owC80BB4CGz5xw_b0gBSNdn3pL04wzMBkcwtbeKdl1g9"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "pl_PL": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_2YBjydYRd1shr6bsZdrvA9z7owvSg3W5RHDYDp6AlatXw9hqx7nVoanRn8YGsBN8"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "pt_PT": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3__afxovspi2-Ip1E5kNsAgc4_35lpLAKCF6bq4_xXj2I2bFPjIWxAOAQJlIkreKTD"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "ro_RO": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_WlBp06vVHuHZhiDLIehF8gchqbfegDJADPQ2MtEsrc8dWVuESf2JCITRo5I2CIxs"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "ru_RU": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_N_ecy4iDyoRtX8v5xOxewwZLKXBjRgrEIv85XxI0KJk8AAdYhJIi17LWb086tGXR"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "sk_SK": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_e8d4g4SE_Fo8ahyHwwP7ohLGZ79HKNN2T8NjQqoNnk6Epj6ilyYwKdHUyCw3wuxz"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "sl_SI": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_QKt0ADYxIhgcje4F3fj9oVidHsx3JIIk-GThhdyMMQi8AJR0QoHdA62YArVjbZCt"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + case "sv_SE": + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3_EN5Hcnwanu9_Dqot1v1Aky1YelT5QqG4TxveO0EgKFWZYu03WkeB9FKuKKIWUXIS"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + default: + gigyaRootUrl = GIGYA_URL_EU; + gigyaApiKey = "3__B4KghyeUb0GlpU62ZXKrjSfb7CPzwBS368wioftJUL5qXE0Z_sSy0rX69klXuHy"; + kamereonRootUrl = KAMEREON_URL_EU; + kamereonApiKey = KAMEREON_APIKEY; + break; + } + } + + public String getGigyaApiKey() { + return gigyaApiKey; + } + + public String getGigyaRootUrl() { + return gigyaRootUrl; + } + + public String getKamereonApiKey() { + return kamereonApiKey; + } + + public String getKamereonRootUrl() { + return kamereonRootUrl; + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/MyRenaultHttpSession.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/MyRenaultHttpSession.java new file mode 100644 index 0000000000000..b7ca956e2fefb --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/MyRenaultHttpSession.java @@ -0,0 +1,264 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.util.Fields; +import org.openhab.binding.renault.internal.RenaultConfiguration; +import org.openhab.binding.renault.internal.api.exceptions.RenaultException; +import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException; +import org.openhab.binding.renault.internal.api.exceptions.RenaultNotImplementedException; +import org.openhab.binding.renault.internal.api.exceptions.RenaultUpdateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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; + +/** + * This is a Java version of the python renault-api project developed here: + * https://github.com/hacf-fr/renault-api + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class MyRenaultHttpSession { + + private RenaultConfiguration config; + private HttpClient httpClient; + private Constants constants; + private @Nullable String kamereonToken; + private @Nullable String kamereonaccountId; + private @Nullable String cookieValue; + private @Nullable String personId; + private @Nullable String gigyaDataCenter; + private @Nullable String jwt; + + private final Logger logger = LoggerFactory.getLogger(MyRenaultHttpSession.class); + + public MyRenaultHttpSession(RenaultConfiguration config, HttpClient httpClient) { + this.config = config; + this.httpClient = httpClient; + this.constants = new Constants(config.locale); + } + + public void initSesssion(Car car) throws RenaultException, RenaultForbiddenException, RenaultUpdateException, + RenaultNotImplementedException, InterruptedException, ExecutionException, TimeoutException { + login(); + getAccountInfo(); + getJWT(); + getAccountID(); + + final String imageURL = car.getImageURL(); + if (imageURL == null) { + getVehicle(car); + } + } + + private void login() throws RenaultException, InterruptedException, ExecutionException, TimeoutException { + Fields fields = new Fields(); + fields.add("ApiKey", this.constants.getGigyaApiKey()); + fields.add("loginID", config.myRenaultUsername); + fields.add("password", config.myRenaultPassword); + logger.debug("URL: {}/accounts.login", this.constants.getGigyaRootUrl()); + ContentResponse response = httpClient.FORM(this.constants.getGigyaRootUrl() + "/accounts.login", fields); + if (HttpStatus.OK_200 == response.getStatus()) { + try { + JsonObject responseJson = JsonParser.parseString(response.getContentAsString()).getAsJsonObject(); + JsonObject sessionInfoJson = responseJson.getAsJsonObject("sessionInfo"); + if (sessionInfoJson != null) { + JsonElement element = sessionInfoJson.get("cookieValue"); + if (element != null) { + cookieValue = element.getAsString(); + logger.debug("Cookie: {}", cookieValue); + } + } + } catch (JsonParseException | ClassCastException | IllegalStateException e) { + throw new RenaultException("Login Error: cookie value not found in JSON response"); + } + } else { + logger.warn("Response: [{}] {}\n{}", response.getStatus(), response.getReason(), + response.getContentAsString()); + throw new RenaultException("Login Error: " + response.getReason()); + } + } + + private void getAccountInfo() throws RenaultException, InterruptedException, ExecutionException, TimeoutException { + Fields fields = new Fields(); + fields.add("ApiKey", this.constants.getGigyaApiKey()); + fields.add("login_token", cookieValue); + ContentResponse response = httpClient.FORM(this.constants.getGigyaRootUrl() + "/accounts.getAccountInfo", + fields); + if (HttpStatus.OK_200 == response.getStatus()) { + try { + JsonObject responseJson = JsonParser.parseString(response.getContentAsString()).getAsJsonObject(); + JsonObject dataJson = responseJson.getAsJsonObject("data"); + if (dataJson != null) { + JsonElement element1 = dataJson.get("personId"); + JsonElement element2 = dataJson.get("gigyaDataCenter"); + if (element1 != null && element2 != null) { + personId = element1.getAsString(); + gigyaDataCenter = element2.getAsString(); + logger.debug("personId ID: {} gigyaDataCenter: {}", personId, gigyaDataCenter); + } + } + } catch (JsonParseException | ClassCastException | IllegalStateException e) { + throw new RenaultException( + "Get Account Info Error: personId or gigyaDataCenter value not found in JSON response"); + } + } else { + logger.warn("Response: [{}] {}\n{}", response.getStatus(), response.getReason(), + response.getContentAsString()); + throw new RenaultException("Get Account Info Error: " + response.getReason()); + } + } + + private void getJWT() throws RenaultException, InterruptedException, ExecutionException, TimeoutException { + Fields fields = new Fields(); + fields.add("ApiKey", this.constants.getGigyaApiKey()); + fields.add("login_token", cookieValue); + fields.add("fields", "data.personId,data.gigyaDataCenter"); + fields.add("personId", personId); + fields.add("gigyaDataCenter", gigyaDataCenter); + ContentResponse response = this.httpClient.FORM(this.constants.getGigyaRootUrl() + "/accounts.getJWT", fields); + if (HttpStatus.OK_200 == response.getStatus()) { + try { + JsonObject responseJson = JsonParser.parseString(response.getContentAsString()).getAsJsonObject(); + JsonElement element = responseJson.get("id_token"); + if (element != null) { + jwt = element.getAsString(); + logger.debug("jwt: {} ", jwt); + } + } catch (JsonParseException | ClassCastException | IllegalStateException e) { + throw new RenaultException("Get JWT Error: jwt value not found in JSON response"); + } + } else { + logger.warn("Response: [{}] {}\n{}", response.getStatus(), response.getReason(), + response.getContentAsString()); + throw new RenaultException("Get JWT Error: " + response.getReason()); + } + } + + private void getAccountID() + throws RenaultException, RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse( + "/commerce/v1/persons/" + personId + "?country=" + getCountry(config)); + if (responseJson != null) { + JsonArray accounts = responseJson.getAsJsonArray("accounts"); + for (int i = 0; i < accounts.size(); i++) { + if (accounts.get(i).getAsJsonObject().get("accountType").getAsString().equals("MYRENAULT")) { + kamereonaccountId = accounts.get(i).getAsJsonObject().get("accountId").getAsString(); + break; + } + } + } + if (kamereonaccountId == null) { + throw new RenaultException("Can not get Kamereon MyRenault Account ID!"); + } + } + + public void getVehicle(Car car) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + "/vehicles/" + + config.vin + "/details?country=" + getCountry(config)); + if (responseJson != null) { + car.setDetails(responseJson); + } + } + + public void getBatteryStatus(Car car) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + + "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/battery-status?country=" + getCountry(config)); + if (responseJson != null) { + car.setBatteryStatus(responseJson); + } + } + + public void getHvacStatus(Car car) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + + "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/hvac-status?country=" + getCountry(config)); + if (responseJson != null) { + car.setHVACStatus(responseJson); + } + } + + public void getCockpit(Car car) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + + "/kamereon/kca/car-adapter/v2/cars/" + config.vin + "/cockpit?country=" + getCountry(config)); + if (responseJson != null) { + car.setCockpit(responseJson); + } + } + + public void getLocation(Car car) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + JsonObject responseJson = getKamereonResponse("/commerce/v1/accounts/" + kamereonaccountId + + "/kamereon/kca/car-adapter/v1/cars/" + config.vin + "/location?country=" + getCountry(config)); + if (responseJson != null) { + car.setLocation(responseJson); + } + } + + private @Nullable JsonObject getKamereonResponse(String path) + throws RenaultForbiddenException, RenaultUpdateException, RenaultNotImplementedException { + Request request = httpClient.newRequest(this.constants.getKamereonRootUrl() + path).method(HttpMethod.GET) + .header("Content-type", "application/vnd.api+json").header("apikey", this.constants.getKamereonApiKey()) + .header("x-kamereon-authorization", "Bearer " + kamereonToken).header("x-gigya-id_token", jwt); + try { + ContentResponse response = request.send(); + if (HttpStatus.OK_200 == response.getStatus()) { + logger.debug("Kamereon Response: {}", response.getContentAsString()); + return JsonParser.parseString(response.getContentAsString()).getAsJsonObject(); + } else { + logger.warn("Kamereon Response: [{}] {} {}", response.getStatus(), response.getReason(), + response.getContentAsString()); + if (HttpStatus.FORBIDDEN_403 == response.getStatus()) { + throw new RenaultForbiddenException( + "Kamereon Response Forbidden! Ensure the car is paired in your MyRenault App."); + } else if (HttpStatus.NOT_IMPLEMENTED_501 == response.getStatus()) { + throw new RenaultNotImplementedException( + "Kamereon Service Not Implemented: [" + response.getStatus() + "] " + response.getReason()); + } else { + throw new RenaultUpdateException( + "Kamereon Response Failed! Error: [" + response.getStatus() + "] " + response.getReason()); + } + } + } catch (JsonParseException | InterruptedException | TimeoutException | ExecutionException e) { + logger.warn("Kamereon Request: {} threw exception: {} ", request.getURI().toString(), e.getMessage()); + } + return null; + } + + private String getCountry(RenaultConfiguration config) { + String country = "XX"; + if (config.locale.length() == 5) { + country = config.locale.substring(3); + } + return country; + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultException.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultException.java new file mode 100644 index 0000000000000..bb8385a483313 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultException.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api.exceptions; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception thrown while trying to access the My Renault web services. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultException extends Exception { + + private static final long serialVersionUID = 1L; + + public RenaultException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultForbiddenException.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultForbiddenException.java new file mode 100644 index 0000000000000..f469daf6aec80 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultForbiddenException.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api.exceptions; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception thrown while trying to access the My Renault web services when HTTP + * 403 is returned. Normally means the car is not paired to the account. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultForbiddenException extends Exception { + + private static final long serialVersionUID = 1L; + + public RenaultForbiddenException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultNotImplementedException.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultNotImplementedException.java new file mode 100644 index 0000000000000..d948cbc7a44a1 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultNotImplementedException.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api.exceptions; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception thrown while trying to access the My Renault service for information + * that is not implemented. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultNotImplementedException extends Exception { + + private static final long serialVersionUID = 1L; + + public RenaultNotImplementedException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultUpdateException.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultUpdateException.java new file mode 100644 index 0000000000000..a7266f7304275 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/api/exceptions/RenaultUpdateException.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.api.exceptions; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception thrown while trying to update the My Renault car information. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultUpdateException extends Exception { + + private static final long serialVersionUID = 1L; + + public RenaultUpdateException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/handler/RenaultHandler.java b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/handler/RenaultHandler.java new file mode 100644 index 0000000000000..fedfab292baeb --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/java/org/openhab/binding/renault/internal/handler/RenaultHandler.java @@ -0,0 +1,207 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.renault.internal.handler; + +import static org.openhab.binding.renault.internal.RenaultBindingConstants.*; +import static org.openhab.core.library.unit.MetricPrefix.KILO; +import static org.openhab.core.library.unit.SIUnits.METRE; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.measure.quantity.Length; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.renault.internal.RenaultConfiguration; +import org.openhab.binding.renault.internal.api.Car; +import org.openhab.binding.renault.internal.api.MyRenaultHttpSession; +import org.openhab.binding.renault.internal.api.exceptions.RenaultForbiddenException; +import org.openhab.binding.renault.internal.api.exceptions.RenaultNotImplementedException; +import org.openhab.binding.renault.internal.api.exceptions.RenaultUpdateException; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PointType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link RenaultHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Doug Culnane - Initial contribution + */ +@NonNullByDefault +public class RenaultHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(RenaultHandler.class); + + private RenaultConfiguration config = new RenaultConfiguration(); + + private @Nullable ScheduledFuture pollingJob; + + private HttpClient httpClient; + + private Car car; + + public RenaultHandler(Thing thing, HttpClient httpClient) { + super(thing); + this.car = new Car(); + this.httpClient = httpClient; + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // This binding only polls status data automatically. + } + + @Override + public void initialize() { + // reset the car on initialize + this.car = new Car(); + this.config = getConfigAs(RenaultConfiguration.class); + + // Validate configuration + if (this.config.myRenaultUsername.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "MyRenault Username is empty!"); + return; + } + if (this.config.myRenaultPassword.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "MyRenault Password is empty!"); + return; + } + if (this.config.locale.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Location is empty!"); + return; + } + if (this.config.vin.isBlank()) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "VIN is empty!"); + return; + } + if (this.config.refreshInterval < 1) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "The refresh interval mush to be larger than 1"); + return; + } + updateStatus(ThingStatus.UNKNOWN); + + // Background initialization: + ScheduledFuture job = pollingJob; + if (job == null || job.isCancelled()) { + pollingJob = scheduler.scheduleWithFixedDelay(this::getStatus, 0, config.refreshInterval, TimeUnit.MINUTES); + } + } + + @Override + public void dispose() { + ScheduledFuture job = pollingJob; + if (job != null) { + job.cancel(true); + pollingJob = null; + } + super.dispose(); + } + + private void getStatus() { + MyRenaultHttpSession httpSession = new MyRenaultHttpSession(this.config, httpClient); + try { + httpSession.initSesssion(car); + updateStatus(ThingStatus.ONLINE); + } catch (Exception e) { + httpSession = null; + logger.warn("Error My Renault Http Session.", e); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + } + if (httpSession != null) { + String imageURL = car.getImageURL(); + if (imageURL != null && !imageURL.isEmpty()) { + updateState(CHANNEL_IMAGE, new StringType(imageURL)); + } + updateHvacStatus(httpSession); + updateCockpit(httpSession); + updateLocation(httpSession); + updateBattery(httpSession); + } + } + + private void updateHvacStatus(MyRenaultHttpSession httpSession) { + if (!car.isDisableHvac()) { + try { + httpSession.getHvacStatus(car); + Boolean hvacstatus = car.getHvacstatus(); + if (hvacstatus != null) { + updateState(CHANNEL_HVAC_STATUS, OnOffType.from(hvacstatus.booleanValue())); + } + } catch (RenaultNotImplementedException e) { + car.setDisableHvac(true); + } catch (RenaultForbiddenException | RenaultUpdateException e) { + } + } + } + + private void updateLocation(MyRenaultHttpSession httpSession) { + if (!car.isDisableLocation()) { + try { + httpSession.getLocation(car); + Double latitude = car.getGpsLatitude(); + Double longitude = car.getGpsLongitude(); + if (latitude != null && longitude != null) { + updateState(CHANNEL_LOCATION, new PointType(new DecimalType(latitude.doubleValue()), + new DecimalType(longitude.doubleValue()))); + } + } catch (RenaultNotImplementedException e) { + car.setDisableLocation(true); + } catch (RenaultForbiddenException | RenaultUpdateException e) { + } + } + } + + private void updateCockpit(MyRenaultHttpSession httpSession) { + if (!car.isDisableCockpit()) { + try { + httpSession.getCockpit(car); + Double odometer = car.getOdometer(); + if (odometer != null) { + updateState(CHANNEL_ODOMETER, new QuantityType(odometer.doubleValue(), KILO(METRE))); + } + } catch (RenaultNotImplementedException e) { + car.setDisableCockpit(true); + } catch (RenaultForbiddenException | RenaultUpdateException e) { + } + } + } + + private void updateBattery(MyRenaultHttpSession httpSession) { + if (!car.isDisableBattery()) { + try { + httpSession.getBatteryStatus(car); + Double batteryLevel = car.getBatteryLevel(); + if (batteryLevel != null) { + updateState(CHANNEL_BATTERY_LEVEL, new DecimalType(batteryLevel.doubleValue())); + } + } catch (RenaultNotImplementedException e) { + car.setDisableBattery(true); + } catch (RenaultForbiddenException | RenaultUpdateException e) { + } + } + } +} diff --git a/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..6f8634020eda3 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + Renault Binding + This is the binding for Renault electric cars. + + diff --git a/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..ee21b82bbcd7a --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,94 @@ + + + + + + + A MyRenault registered car. + + + + + + + + + + + + + + + password + + + + + The country (and language combination) that best fits with your MyRenault registered car. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vehicle Identification Number + + + + Interval the car is polled in minutes. + 10 + + + + + + + Switch + + + + + String + + Image URL of MyRenault + + + + Number:Length + + Total distance travelled + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index 25f301f453e4f..c09a0a2c50950 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -286,6 +286,7 @@ org.openhab.binding.regoheatpump org.openhab.binding.revogi org.openhab.binding.remoteopenhab + org.openhab.binding.renault org.openhab.binding.resol org.openhab.binding.rfxcom org.openhab.binding.rme From ce403e7602062251cfbba463057a67605e8595f7 Mon Sep 17 00:00:00 2001 From: lolodomo Date: Sun, 5 Dec 2021 09:39:51 +0100 Subject: [PATCH 173/361] [openuv] Fix internationalization of discovery result (#11500) * [openuv] Fix internationalization of discovery result Signed-off-by: Laurent Garnier Signed-off-by: Michael Schmidt --- .../openuv/internal/OpenUVHandlerFactory.java | 11 +++++++++-- .../discovery/OpenUVDiscoveryService.java | 5 ++++- .../internal/handler/OpenUVBridgeHandler.java | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/OpenUVHandlerFactory.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/OpenUVHandlerFactory.java index fe483a09ea1d2..1d7bb529c33cf 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/OpenUVHandlerFactory.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/OpenUVHandlerFactory.java @@ -20,8 +20,10 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.openuv.internal.handler.OpenUVBridgeHandler; import org.openhab.binding.openuv.internal.handler.OpenUVReportHandler; +import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.LocationProvider; import org.openhab.core.i18n.TimeZoneProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; @@ -48,12 +50,17 @@ public class OpenUVHandlerFactory extends BaseThingHandlerFactory { private final LocationProvider locationProvider; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; private final Gson gson; @Activate public OpenUVHandlerFactory(@Reference TimeZoneProvider timeZoneProvider, - @Reference LocationProvider locationProvider) { + @Reference LocationProvider locationProvider, @Reference TranslationProvider i18nProvider, + @Reference LocaleProvider localeProvider) { this.locationProvider = locationProvider; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; this.gson = new GsonBuilder() .registerTypeAdapter(ZonedDateTime.class, (JsonDeserializer) (json, type, jsonDeserializationContext) -> ZonedDateTime @@ -72,7 +79,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); return APIBRIDGE_THING_TYPE.equals(thingTypeUID) - ? new OpenUVBridgeHandler((Bridge) thing, locationProvider, gson) + ? new OpenUVBridgeHandler((Bridge) thing, locationProvider, i18nProvider, localeProvider, gson) : LOCATION_REPORT_THING_TYPE.equals(thingTypeUID) ? new OpenUVReportHandler(thing) : null; } } diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/discovery/OpenUVDiscoveryService.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/discovery/OpenUVDiscoveryService.java index b192db432729a..374f31fa64210 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/discovery/OpenUVDiscoveryService.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/discovery/OpenUVDiscoveryService.java @@ -50,7 +50,10 @@ public OpenUVDiscoveryService() { @Override public void setThingHandler(ThingHandler handler) { if (handler instanceof OpenUVBridgeHandler) { - this.bridgeHandler = (OpenUVBridgeHandler) handler; + OpenUVBridgeHandler localHandler = (OpenUVBridgeHandler) handler; + this.bridgeHandler = localHandler; + this.i18nProvider = localHandler.getI18nProvider(); + this.localeProvider = localHandler.getLocaleProvider(); } } diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java index f39e85b9c395b..6388e0a287729 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java @@ -29,7 +29,9 @@ import org.openhab.binding.openuv.internal.discovery.OpenUVDiscoveryService; import org.openhab.binding.openuv.internal.json.OpenUVResponse; import org.openhab.binding.openuv.internal.json.OpenUVResult; +import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.LocationProvider; +import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.io.net.http.HttpUtil; import org.openhab.core.library.types.PointType; import org.openhab.core.thing.Bridge; @@ -61,13 +63,18 @@ public class OpenUVBridgeHandler extends BaseBridgeHandler { private final Properties header = new Properties(); private final Gson gson; private final LocationProvider locationProvider; + private final TranslationProvider i18nProvider; + private final LocaleProvider localeProvider; private @Nullable ScheduledFuture reconnectJob; - public OpenUVBridgeHandler(Bridge bridge, LocationProvider locationProvider, Gson gson) { + public OpenUVBridgeHandler(Bridge bridge, LocationProvider locationProvider, TranslationProvider i18nProvider, + LocaleProvider localeProvider, Gson gson) { super(bridge); this.gson = gson; this.locationProvider = locationProvider; + this.i18nProvider = i18nProvider; + this.localeProvider = localeProvider; } @Override @@ -149,4 +156,12 @@ public Collection> getServices() { public @Nullable PointType getLocation() { return locationProvider.getLocation(); } + + public TranslationProvider getI18nProvider() { + return i18nProvider; + } + + public LocaleProvider getLocaleProvider() { + return localeProvider; + } } From b457d4d418341547221f453d50ff0f9a002b9943 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Sun, 5 Dec 2021 11:16:17 +0100 Subject: [PATCH 174/361] New Crowdin updates (#11663) * New translations astro.properties (Hungarian) * New translations chromecast.properties (German) * New translations chromecast.properties (Hungarian) * New translations lgwebos.properties (French) * New translations linky.properties (French) * New translations logreader.properties (German) * New translations mail.properties (French) * New translations mail.properties (Hungarian) * New translations max.properties (German) * New translations ntp.properties (Hungarian) * New translations openhabcloud.properties (Hungarian) * New translations pushover.properties (German) * New translations pushsafer.properties (German) * New translations remoteopenhab.properties (Hungarian) * New translations transform.properties (French) * New translations transform.properties (German) * New translations vigicrues.properties (French) * New translations voicerss.properties (German) * New translations volvooncall.properties (French) * New translations xmltv.properties (French) * Fix encoding issue Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/astro_hu.properties | 215 ++++++++++ .../OH-INF/i18n/chromecast_de.properties | 90 ++++- .../OH-INF/i18n/chromecast_hu.properties | 95 +++++ .../OH-INF/i18n/lgwebos_fr.properties | 2 +- .../resources/OH-INF/i18n/linky_fr.properties | 20 +- .../OH-INF/i18n/logreader_de.properties | 51 +++ .../resources/OH-INF/i18n/mail_fr.properties | 2 +- .../resources/OH-INF/i18n/mail_hu.properties | 61 +++ .../resources/OH-INF/i18n/max_de.properties | 375 +++++++----------- .../resources/OH-INF/i18n/ntp_hu.properties | 30 ++ .../OH-INF/i18n/pushover_de.properties | 4 +- .../OH-INF/i18n/pushsafer_de.properties | 6 +- .../OH-INF/i18n/remoteopenhab_hu.properties | 87 ++++ .../OH-INF/i18n/sagercaster_fr.properties | 2 +- .../OH-INF/i18n/vigicrues_fr.properties | 10 +- .../OH-INF/i18n/volvooncall_fr.properties | 98 ++--- .../resources/OH-INF/i18n/xmltv_fr.properties | 64 +++ .../OH-INF/i18n/openhabcloud_hu.properties | 14 + .../OH-INF/i18n/transform_de.properties | 9 +- .../OH-INF/i18n/transform_fr.properties | 9 +- .../OH-INF/i18n/voicerss_de.properties | 8 + 21 files changed, 928 insertions(+), 324 deletions(-) create mode 100644 bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_hu.properties create mode 100644 bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_hu.properties create mode 100644 bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties create mode 100644 bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_hu.properties create mode 100644 bundles/org.openhab.binding.remoteopenhab/src/main/resources/OH-INF/i18n/remoteopenhab_hu.properties create mode 100644 bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties create mode 100644 bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties create mode 100644 bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_de.properties diff --git a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_hu.properties b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_hu.properties new file mode 100644 index 0000000000000..a3b71783edd73 --- /dev/null +++ b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_hu.properties @@ -0,0 +1,215 @@ +# binding +binding.astro.name = Astro kötés +binding.astro.description = Az Astro kötés csillagászati adatokat számol a hold és nap állásából. + +# thing types +thing-type.astro.sun.label = Astro Nap adatok +thing-type.astro.sun.description = Csillagászati adatok a nap állásából +thing-type.astro.sun.group.rise.label = Napkelte +thing-type.astro.sun.group.rise.description = A napkelte esemény időtartama +thing-type.astro.sun.group.set.label = Napnyugta +thing-type.astro.sun.group.set.description = A napnyugta esemény időtartama +thing-type.astro.sun.group.noon.label = Dél +thing-type.astro.sun.group.noon.description = A dél esemény időtartama +thing-type.astro.sun.group.night.label = Éjszaka +thing-type.astro.sun.group.night.description = A éjszaka esemény időtartama +thing-type.astro.sun.group.morningNight.label = Reggeli éjszaka +thing-type.astro.sun.group.morningNight.description = A reggeli éjszaka esemény időtartama +thing-type.astro.sun.group.astroDawn.label = Astro hajnal +thing-type.astro.sun.group.astroDawn.description = Az Astro hajnal esemény időtartama +thing-type.astro.sun.group.nauticDawn.label = Tengerészeti hajnal +thing-type.astro.sun.group.nauticDawn.description = Az tengerészeti hajnal esemény időtartama +thing-type.astro.sun.group.civilDawn.label = Civil hajnal +thing-type.astro.sun.group.civilDawn.description = Az civil hajnal esemény időtartama +thing-type.astro.sun.group.astroDusk.label = Astro szürkület +thing-type.astro.sun.group.astroDusk.description = Az Astro szürkület esemény időtartama +thing-type.astro.sun.group.nauticDusk.label = Tengerészeti szürkület +thing-type.astro.sun.group.nauticDusk.description = Az tengerészeti szürkület esemény időtartama +thing-type.astro.sun.group.civilDusk.label = Civil szürkület +thing-type.astro.sun.group.civilDusk.description = Az civil szürkület esemény időtartama +thing-type.astro.sun.group.eveningNight.label = Esti éjszaka +thing-type.astro.sun.group.eveningNight.description = A esti éjszaka esemény időtartama +thing-type.astro.sun.group.daylight.label = Nappal +thing-type.astro.sun.group.daylight.description = A nappal esemény időtartama +thing-type.astro.sun.group.position.description = A nap pozíciója + +thing-type.astro.moon.label = Astro hold adatok +thing-type.astro.moon.description = Csillagászati adatok a hold állásából +thing-type.astro.moon.group.rise.label = Holdfelkelte +thing-type.astro.moon.group.rise.description = A holdfelkelte esemény időtartama +thing-type.astro.moon.group.set.label = Holdnyugta +thing-type.astro.moon.group.set.description = A holdnyugta esemény időtartama +thing-type.astro.moon.group.distance.description = A hold távolsága +thing-type.astro.moon.group.perigee.label = Földközel +thing-type.astro.moon.group.perigee.description = A hold földközeli helyzetben +thing-type.astro.moon.group.apogee.label = Földtávol +thing-type.astro.moon.group.apogee.description = A hold a legtávolabbi helyzetben van +thing-type.astro.moon.group.position.description = A hold pozíciója + +# thing types config +thing-type.config.astro.sunconfig.geolocation.label = Hely +thing-type.config.astro.sunconfig.geolocation.description = Hosszúság, szélesség, magasság adatok vesszővel elválasztva (hossz, szél, [mag]). + +thing-type.config.astro.sunconfig.useMeteorologicalSeason.label = Meteorológiai évszak +thing-type.config.astro.sunconfig.useMeteorologicalSeason.description = Meteorológiai évszak számítás használata a csillagászati helyett. + +thing-type.config.astro.sunconfig.interval.label = Időköz +thing-type.config.astro.sunconfig.interval.description = A pozíció adatok számításának időköze másodpercben. + +thing-type.config.astro.moonconfig.geolocation.label = Helyszín +thing-type.config.astro.moonconfig.geolocation.description = Hosszúság, szélesség, magasság adatok vesszővel elválasztva (hossz, szél, [mag]). + +thing-type.config.astro.moonconfig.interval.label = Időköz +thing-type.config.astro.moonconfig.interval.description = A pozíció adatok számításának időköze másodpercben. + +# channel group types +channel-group-type.astro.position.label = Pozíció +channel-group-type.astro.position.description = A bolygó pozíciója +channel-group-type.astro.radiation.label = Sugárzás +channel-group-type.astro.radiation.description = A napsugárzás szintje +channel-group-type.astro.sunRange.label = Tartomány +channel-group-type.astro.sunRange.description = A nap eseményének időtartama +channel-group-type.astro.moonRange.label = Tartomány +channel-group-type.astro.moonRange.description = A hold eseményének időtartama +channel-group-type.astro.sunZodiac.label = Állatöv +channel-group-type.astro.sunZodiac.description = A nap állatövi pozíciója +channel-group-type.astro.season.label = Évszak +channel-group-type.astro.season.description = Az év évszakjai +channel-group-type.astro.sunEclipse.label = Napfogyatkozások +channel-group-type.astro.sunEclipse.description = A következő napfogyatkozások időpontja +channel-group-type.astro.sunPhase.label = Nap fázis +channel-group-type.astro.sunPhase.description = Az aktuális napfázis részletei +channel-group-type.astro.moonPhase.label = Holdfázis +channel-group-type.astro.moonPhase.description = Az aktuális és következő holdfázis részletei +channel-group-type.astro.moonEclipse.label = Napfogyatkozások +channel-group-type.astro.moonEclipse.description = A következő holdfogyatkozások időpontjai +channel-group-type.astro.distance.label = Távolság +channel-group-type.astro.distance.description = Távolság adat +channel-group-type.astro.moonZodiac.label = Állatöv +channel-group-type.astro.moonZodiac.description = A hold állatövi pozíciója + +channel-group-type.astro.moonEclipse.channel.total.label = Teljes holdfogyatkozás +channel-group-type.astro.moonEclipse.channel.total.description = A következő teljes holdfogyatkozás időpontja +channel-group-type.astro.moonEclipse.channel.partial.label = Részleges holdfogyatkozás +channel-group-type.astro.moonEclipse.channel.partial.description = A következő részleges holdfogyatkozás időpontja + +# channel types +channel-type.astro.azimuth.label = Irányszög +channel-type.astro.azimuth.description = A bolygó irányszöge +channel-type.astro.elevation.label = Emelkedés +channel-type.astro.elevation.description = A bolygó emelkedési szöge +channel-type.astro.shadeLength.label = Árnyék hossz arány +channel-type.astro.shadeLength.description = A vetett árnyék és a tárgyhossz aránya (az emelkedési szögből számítva) +channel-type.astro.directRadiation.label = Direkt sugárzás +channel-type.astro.directRadiation.description = A légköri rétegeken áthatoló direkt sugárzás mértéke +channel-type.astro.diffuseRadiation.label = Szórt sugárzás +channel-type.astro.diffuseRadiation.description = A légkör és a felhők által szétszórt sugárzás mértéke +channel-type.astro.totalRadiation.label = Teljes sugárzás +channel-type.astro.totalRadiation.description = A talajra érkező teljes besugárzás mértéke +channel-type.astro.start.label = Kezdés ideje +channel-type.astro.start.description = Az esemény kezdeti időpontja +channel-type.astro.end.label = Befejezés +channel-type.astro.end.description = Az esemény befejező időpontja +channel-type.astro.duration.label = Időtartam +channel-type.astro.duration.description = Az esemény időtartama +channel-type.astro.sign.label = Jel +channel-type.astro.sign.description = Az állatöv jele +channel-type.astro.sign.state.option.ARIES = Nyilas +channel-type.astro.sign.state.option.TAURUS = Bika +channel-type.astro.sign.state.option.GEMINI = Szűz +channel-type.astro.sign.state.option.CANCER = Rák +channel-type.astro.sign.state.option.LEO = Oroszlán +channel-type.astro.sign.state.option.VIRGO = Szűz +channel-type.astro.sign.state.option.LIBRA = Mérleg +channel-type.astro.sign.state.option.SCORPIO = Skorpió +channel-type.astro.sign.state.option.SAGITTARIUS = Nyilas +channel-type.astro.sign.state.option.CAPRICORN = Bak +channel-type.astro.sign.state.option.AQUARIUS = Vízöntő +channel-type.astro.sign.state.option.PISCES = Halak +channel-type.astro.seasonName.label = Évszak neve +channel-type.astro.seasonName.description = Az aktuális évszak neve +channel-type.astro.seasonName.state.option.SPRING = Tavasz +channel-type.astro.seasonName.state.option.SUMMER = Nyár +channel-type.astro.seasonName.state.option.AUTUMN = Ősz +channel-type.astro.seasonName.state.option.WINTER = Tél +channel-type.astro.spring.label = Tavasz +channel-type.astro.spring.description = Tavasz kezdete +channel-type.astro.summer.label = Nyár +channel-type.astro.summer.description = Nyár kezdete +channel-type.astro.autumn.label = Ősz +channel-type.astro.autumn.description = Ősz kezdete +channel-type.astro.winter.label = Tél +channel-type.astro.winter.description = Tél kezdete +channel-type.astro.total.label = Teljes napfogyatkozás +channel-type.astro.total.description = A következő teljes napfogyatkozás időpontja +channel-type.astro.partial.label = Részleges napfogyatkozás +channel-type.astro.partial.description = A következő részleges napfogyatkozás időpontja +channel-type.astro.ring.label = Gyűrűfogyatkozás +channel-type.astro.ring.description = A következő gyűrűfogyatkozás időpontja +channel-type.astro.sunPhaseName.label = Nap fázis neve +channel-type.astro.sunPhaseName.description = Az aktuális napfázis neve +channel-type.astro.sunPhaseName.state.option.SUN_RISE = Napkelte +channel-type.astro.sunPhaseName.state.option.ASTRO_DAWN = Astro hajnal +channel-type.astro.sunPhaseName.state.option.NAUTIC_DAWN = Tengerészeti hajnal +channel-type.astro.sunPhaseName.state.option.CIVIL_DAWN = Civil hajnal +channel-type.astro.sunPhaseName.state.option.CIVIL_DUSK = Civil szürkület +channel-type.astro.sunPhaseName.state.option.NAUTIC_DUSK = Tengerészeti szürkület +channel-type.astro.sunPhaseName.state.option.ASTRO_DUSK = Astro szürkület +channel-type.astro.sunPhaseName.state.option.SUN_SET = Napnyugta +channel-type.astro.sunPhaseName.state.option.DAYLIGHT = Nappal +channel-type.astro.sunPhaseName.state.option.NOON = Dél +channel-type.astro.sunPhaseName.state.option.NIGHT = Éjszaka +channel-type.astro.firstQuarter.label = Első negyed +channel-type.astro.firstQuarter.description = A hold első negyedének időpontja +channel-type.astro.thirdQuarter.label = Harmadik negyed +channel-type.astro.thirdQuarter.description = A hold harmadik negyedének időpontja +channel-type.astro.fullMoon.label = Telihold +channel-type.astro.fullMoon.description = A telihold időpontja +channel-type.astro.newMoon.label = Újhold +channel-type.astro.newMoon.description = A újhold időpontja +channel-type.astro.age.label = A hold kora +channel-type.astro.age.description = A hold kora napokban +channel-type.astro.ageDegree.label = A hold kora +channel-type.astro.ageDegree.description = A hold kora +channel-type.astro.agePercent.label = A hold kora +channel-type.astro.agePercent.description = A hold kora +channel-type.astro.illumination.label = A hold fényereje +channel-type.astro.illumination.description = A hold visszavert sugárzásának fényessége +channel-type.astro.phaseName.label = A holdfázis neve +channel-type.astro.phaseName.description = Az aktuális holdfázis neve +channel-type.astro.phaseName.state.option.NEW = Újhold +channel-type.astro.phaseName.state.option.WAXING_CRESCENT = Növekvő sarló +channel-type.astro.phaseName.state.option.FIRST_QUARTER = Első negyed +channel-type.astro.phaseName.state.option.WAXING_GIBBOUS = Növekvő félhold +channel-type.astro.phaseName.state.option.FULL = Telihold +channel-type.astro.phaseName.state.option.WANING_GIBBOUS = Fogyó félhold +channel-type.astro.phaseName.state.option.THIRD_QUARTER = Harmadik negyed +channel-type.astro.phaseName.state.option.WANING_CRESCENT = Fogyó sarló +channel-type.astro.distanceDate.label = Dátum +channel-type.astro.distanceDate.description = A távolság elérésének időpontja +channel-type.astro.distance.label = Távolság +channel-type.astro.distance.description = Az objektum távolsága +channel-type.astro.rangeEvent.label = Időtartam esemény +channel-type.astro.rangeEvent.description = Időtartam esemény +channel-type.astro.sunEclipseEvent.label = Napfogyatkozás esemény +channel-type.astro.sunEclipseEvent.description = Napfogyatkozás esemény +channel-type.astro.phaseEvent.label = Holdfázis esemény +channel-type.astro.phaseEvent.description = Holdfázis esemény +channel-type.astro.moonEclipseEvent.label = Holdfogyatkozás esemény +channel-type.astro.moonEclipseEvent.description = Holdfogyatkozás esemény +channel-type.astro.distanceEvent.label = Hold távolság esemény +channel-type.astro.distanceEvent.description = Hold távolság esemény + +# channel types config +channel-type.config.astro.config.offset.label = Eltolás +channel-type.config.astro.config.offset.description = Egy esemény vagy időpont előre vagy vissza tolása (percekben). + +channel-type.config.astro.config.earliest.label = Legkorábbi +channel-type.config.astro.config.earliest.description = Az esemény legkorábbi időpontja a napon belül vagy annak dátuma (óó\:pp). + +channel-type.config.astro.config.latest.label = Legújabb +channel-type.config.astro.config.latest.description = Az esemény legújabb időpontja a napon belül vagy annak dátuma (óó\:pp). + +# Discovery result +discovery.astro.sun.local.label = Helyi Nap +discovery.astro.moon.local.label = Helyi Hold diff --git a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties index 857b64ccb239e..961def6432163 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties +++ b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties @@ -1,39 +1,95 @@ # binding + binding.chromecast.name = Chromecast Binding binding.chromecast.description = Dieses Binding integriert Chromecast Geräte (z.B. Chromecast, Chromecast Audio oder Chromecast Ultra). +# binding config + +binding.config.chromecast.callbackUrl.label = Callback URL +binding.config.chromecast.callbackUrl.description = URL zum Abspielen von Benachrichtigungen (z.B. http\://192.168.0.2\:8080). + # thing types -thing-type.chromecast.audiogroup.label = Chromecast Audiogruppe -thing-type.chromecast.audiogroup.description = Audiogruppe aus mehreren Chromecast Audio oder Media Playern. thing-type.chromecast.audio.label = Chromecast Audio thing-type.chromecast.audio.description = Chromecast Audio Player - +thing-type.chromecast.audiogroup.label = Chromecast Audiogruppe +thing-type.chromecast.audiogroup.description = Audiogruppe aus mehreren Chromecast Audio oder Media Playern. thing-type.chromecast.chromecast.label = Chromecast thing-type.chromecast.chromecast.description = Chromecast Media Player # thing types config + thing-type.config.chromecast.device.ipAddress.label = IP-Adresse -thing-type.config.chromecast.device.ipAddress.description = Lokale IP-Adresse oder Hostname des Chromecast Gerätes. +thing-type.config.chromecast.device.ipAddress.description = IP-Adresse oder Hostname des Chromecast Gerätes. thing-type.config.chromecast.device.port.label = Port thing-type.config.chromecast.device.port.description = Port des Chromecast Gerätes. thing-type.config.chromecast.device.refreshRate.label = Aktualisierungsintervall thing-type.config.chromecast.device.refreshRate.description = Intervall zur Aktualisierung des Chromecast Gerätes. # channel types -channel-type.chromecast.stop.label = Stop -channel-type.chromecast.stop.description = Ermöglicht das Stoppen der Wiedergabe. -channel-type.chromecast.playuri.label = URI abspielen -channel-type.chromecast.playuri.description = Ermöglicht das Abspielen einer URI. -channel-type.chromecast.metadataType.label = Medientyp -channel-type.chromecast.metadataType.description = Zeigt den Medientyp des aktuellen Stücks oder Films (z. B. MOVIE, AUDIO_TRACK) an. + +channel-type.chromecast.albumArtist.label = Künstler +channel-type.chromecast.albumArtist.description = Zeigt den Künstler des (aktuell abgespielten) Albums an. channel-type.chromecast.albumName.label = Album -channel-type.chromecast.albumName.description = Zeigt das Album des aktuellen Stücks an. -channel-type.chromecast.metadataType.label = Medientyp -channel-type.chromecast.metadataType.description = Zeigt den Medientyp des aktuellen Stücks oder Films (z. B. movie, song) an. -channel-type.chromecast.image.label = Thumbnail -channel-type.chromecast.image.description = Zeigt das Thumbnail des aktuellen Stücks oder Films an. +channel-type.chromecast.albumName.description = Zeigt das Album der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.appId.label = Anwendungs-ID +channel-type.chromecast.appId.description = Zeigt die ID der aktuellen Anwendung an. +channel-type.chromecast.appName.label = Anwendung +channel-type.chromecast.appName.description = Zeigt den Namen der aktuellen Anwendung an. +channel-type.chromecast.broadcastDate.label = Ausstrahlungsdatum +channel-type.chromecast.broadcastDate.description = Zeigt das Ausstrahlungssdatum der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.composer.label = Verfasser +channel-type.chromecast.composer.description = Zeigt den Verfasser der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.creationDate.label = Erstellungsdatum +channel-type.chromecast.creationDate.description = Zeigt das Erstellungsdatum der (aktuell abgespielten) Video- oder Audiodatei an. channel-type.chromecast.currentTime.label = Laufzeit -channel-type.chromecast.currentTime.description = Zeigt die Laufzeit des aktuellen Stücks oder Films an. +channel-type.chromecast.currentTime.description = Zeigt das Laufzeit der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.discNumber.label = Disk-Nummer +channel-type.chromecast.discNumber.description = Zeigt die Disk-Nummer der (aktuell abgespielten) Video- oder Audiodatei an. channel-type.chromecast.duration.label = Dauer -channel-type.chromecast.duration.description = Zeigt die Dauer des aktuellen Stücks oder Films an. +channel-type.chromecast.duration.description = Zeigt die Dauer der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.episodeNumber.label = Episodennummer +channel-type.chromecast.episodeNumber.description = Zeigt die Episodennummer der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.idling.label = Leerlauf +channel-type.chromecast.idling.description = Zeit an, ob sich das Gerät im Leerlauf befindet. +channel-type.chromecast.image.label = Thumbnail +channel-type.chromecast.image.description = Zeigt das Thumbnail der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.imageSrc.label = Thumbnail URL +channel-type.chromecast.imageSrc.description = Zeigt die Thumbnail URL der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.locationName.label = Aufnahmeort +channel-type.chromecast.locationName.description = Zeigt den Aufnahmeort der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.metadataType.label = Medientyp +channel-type.chromecast.metadataType.description = Zeigt den Medientyp des aktuellen Stücks oder Films (z. B. movie, song) an. +channel-type.chromecast.playuri.label = URI abspielen +channel-type.chromecast.playuri.description = Ermöglicht das Abspielen einer URI. +channel-type.chromecast.releaseDate.label = Veröffentlichungsdatum +channel-type.chromecast.releaseDate.description = Zeigt das Veröffentlichungsdatum der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.seasonNumber.label = Staffelnummer +channel-type.chromecast.seasonNumber.description = Zeigt die Staffelnummer der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.seriesTitle.label = Serientitel +channel-type.chromecast.seriesTitle.description = Zeigt den Serientitel der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.statustext.label = Anwendungsstatus +channel-type.chromecast.statustext.description = Zeigt den Status der aktuellen Anwendung an. +channel-type.chromecast.stop.label = Stop +channel-type.chromecast.stop.description = Ermöglicht das Stoppen der Wiedergabe. +channel-type.chromecast.studio.label = Aufnahmestudio +channel-type.chromecast.studio.description = Zeigt das Aufnahmestudio der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.subtitle.label = Untertitel +channel-type.chromecast.subtitle.description = Zeigt den Untertitel der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.trackNumber.label = Titelnummer +channel-type.chromecast.trackNumber.description = Zeigt die Titelnummer der (aktuell abgespielten) Video- oder Audiodatei an. + +# channel types + +channel-type.chromecast.metadataType.state.option.GENERIC = Allgemein +channel-type.chromecast.metadataType.state.option.MOVIE = Film +channel-type.chromecast.metadataType.state.option.TV_SHOW = TV-Sendung +channel-type.chromecast.metadataType.state.option.AUDIO_TRACK = Audio +channel-type.chromecast.metadataType.state.option.PHOTO = Foto + +# actions + +playURLActionLabel = von URL abspielen +playURLActionDescription = Spielt von einer URL ab. +playURLTypeActionLabel = von einer URL mit benutzerdefiniertem Medientyp abspielen +playURLTypeActionDescription = Spielt von einer URL mit benutzerdefiniertem Medientyp ab. diff --git a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_hu.properties b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_hu.properties new file mode 100644 index 0000000000000..10b554769393b --- /dev/null +++ b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_hu.properties @@ -0,0 +1,95 @@ +# binding + +binding.chromecast.name = Chromecast kötés +binding.chromecast.description = Ez a kötés a Google Chromecast eszközöket kezeli. + +# binding config + +binding.config.chromecast.callbackUrl.label = Visszacsatolási URL +binding.config.chromecast.callbackUrl.description = url a lejátszott értesítési hangokhoz, pl.\: http\://192.168.0.2\:8080 + +# thing types + +thing-type.chromecast.audio.label = Chromecast hang +thing-type.chromecast.audio.description = Google Chromecast hang eszköz +thing-type.chromecast.audiogroup.label = Chromecast hangfal csoport +thing-type.chromecast.audiogroup.description = Google Chromecast hangfal csoport eszköze +thing-type.chromecast.chromecast.label = Chromecast +thing-type.chromecast.chromecast.description = Google Chromecast hangfolyam lejátszó eszköze + +# thing types config + +thing-type.config.chromecast.device.ipAddress.label = Hálózati cím +thing-type.config.chromecast.device.ipAddress.description = A Chromecast eszköz hálózati címe. +thing-type.config.chromecast.device.port.label = Hálózati port +thing-type.config.chromecast.device.port.description = A Chromecast eszköz hálózati port száma. +thing-type.config.chromecast.device.refreshRate.label = Frissítés gyakorisága +thing-type.config.chromecast.device.refreshRate.description = Milyen gyakran frissüljenek a chromecast adatai. A chromecastnak értesíteni kellene a kötést, ha valami változik, de ha követni akarod a lejátszási időt, gyakrabb frissítést kell beütemezned. + +# channel types + +channel-type.chromecast.albumArtist.label = Album előadó +channel-type.chromecast.albumArtist.description = Az album előadójának a neve +channel-type.chromecast.albumName.label = Album neve +channel-type.chromecast.albumName.description = Az album neve +channel-type.chromecast.appId.label = Alkalmazás azonosító +channel-type.chromecast.appId.description = Az aktuálisan futó alkalmazás azonosítója +channel-type.chromecast.appName.label = Alkalmazás +channel-type.chromecast.appName.description = Az aktuálisan futó alkalmazás neve +channel-type.chromecast.broadcastDate.label = Adás időpontja +channel-type.chromecast.broadcastDate.description = Az aktuálisan játszott média leadásának időpontja +channel-type.chromecast.composer.label = Szerző +channel-type.chromecast.composer.description = Az aktuális sáv szerzője +channel-type.chromecast.creationDate.label = Létrehozás dátuma +channel-type.chromecast.creationDate.description = Az aktuálisan játszott média létrehozásának időpontja +channel-type.chromecast.currentTime.label = Aktuális idő +channel-type.chromecast.currentTime.description = A lejátszott média pozíciójának időpontja +channel-type.chromecast.discNumber.label = Lemez sorszám +channel-type.chromecast.discNumber.description = Az aktuálisan játszott média lemezének száma +channel-type.chromecast.duration.label = Időtartam +channel-type.chromecast.duration.description = A lejátszott média hossza +channel-type.chromecast.episodeNumber.label = Epizódszám +channel-type.chromecast.episodeNumber.description = Az aktuálisan játszott média epizódjának száma +channel-type.chromecast.idling.label = Üresjárat +channel-type.chromecast.idling.description = A chromecast aktív vagy üresjáratban van +channel-type.chromecast.image.label = Kép +channel-type.chromecast.image.description = A kép, ami az aktuális médiát jellemzi. Általában egy borítókép vagy jelenet a filmből +channel-type.chromecast.imageSrc.label = Kép URL +channel-type.chromecast.imageSrc.description = A kép URL, ami az aktuális médiát jellemzi. Általában egy borítókép vagy jelenet a filmből +channel-type.chromecast.locationName.label = Helyszín neve +channel-type.chromecast.locationName.description = A helyszín, ahol a lejátszott médiát felvették +channel-type.chromecast.metadataType.label = Médiatípus +channel-type.chromecast.metadataType.description = A lejátszott média típusa. (GENERIC, MOVIE, TV_SHOW, AUDIO_TRACK, PHOTO) +channel-type.chromecast.playuri.label = URL lejátszása +channel-type.chromecast.playuri.description = Lejátssza a megadott URI-t +channel-type.chromecast.releaseDate.label = Megjelenési dátum +channel-type.chromecast.releaseDate.description = Az aktuálisan játszott média kiadásának időpontja +channel-type.chromecast.seasonNumber.label = Évadszám +channel-type.chromecast.seasonNumber.description = Az aktuálisan játszott média évadjának száma +channel-type.chromecast.seriesTitle.label = Sorozat címe +channel-type.chromecast.seriesTitle.description = Az aktuálisan játszott média sorozatcíme +channel-type.chromecast.statustext.label = Alkalmazás állapota +channel-type.chromecast.statustext.description = Az aktuális alkalmazás állapotjelentése +channel-type.chromecast.stop.label = Megállít +channel-type.chromecast.stop.description = Megállítja a lejátszást. ON állapotú, ha a lejátszó áll. +channel-type.chromecast.studio.label = Stúdió +channel-type.chromecast.studio.description = Az aktuálisan játszott média stúdiója +channel-type.chromecast.subtitle.label = Alcím +channel-type.chromecast.subtitle.description = Az aktuálisan játszott média alcíme +channel-type.chromecast.trackNumber.label = Sáv száma +channel-type.chromecast.trackNumber.description = Az aktuálisan játszott média sávjának a száma + +# channel types + +channel-type.chromecast.metadataType.state.option.GENERIC = Általános +channel-type.chromecast.metadataType.state.option.MOVIE = Film +channel-type.chromecast.metadataType.state.option.TV_SHOW = Sorozat +channel-type.chromecast.metadataType.state.option.AUDIO_TRACK = Hangsáv +channel-type.chromecast.metadataType.state.option.PHOTO = Fénykép + +# actions + +playURLActionLabel = URL lejátszása +playURLActionDescription = URL lejátszása. +playURLTypeActionLabel = URL lejátszása média típus szerint +playURLTypeActionDescription = Az URL lejátszása a megadott médiatípus szerint. diff --git a/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties b/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties index a23a56ff9214d..ff61c4a572f65 100644 --- a/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties +++ b/bundles/org.openhab.binding.lgwebos/src/main/resources/OH-INF/i18n/lgwebos_fr.properties @@ -5,7 +5,7 @@ binding.lgwebos.description = Cette extension permet de contrôler les télévis # thing types -thing-type.lgwebos.WebOSTV.label = TV webOS +thing-type.lgwebos.WebOSTV.label = TV WebOS thing-type.lgwebos.WebOSTV.description = Smart TV reposant sur le système d'exploitation LG webOS # thing types config diff --git a/bundles/org.openhab.binding.linky/src/main/resources/OH-INF/i18n/linky_fr.properties b/bundles/org.openhab.binding.linky/src/main/resources/OH-INF/i18n/linky_fr.properties index d1e0f891dfbfc..2c81df4c63cfa 100644 --- a/bundles/org.openhab.binding.linky/src/main/resources/OH-INF/i18n/linky_fr.properties +++ b/bundles/org.openhab.binding.linky/src/main/resources/OH-INF/i18n/linky_fr.properties @@ -20,24 +20,24 @@ thing-type.config.linky.linky.username.description = Votre nom d'utilisateur Ene # channel group types channel-group-type.linky.daily.label = Consommation quotidienne -channel-group-type.linky.daily.channel.timestamp.label = Horodatage du pic +channel-group-type.linky.daily.channel.timestamp.label = Horodatage Pic channel-group-type.linky.daily.channel.timestamp.description = Horodatage du pic maximum de consommation d'énergie -channel-group-type.linky.daily.channel.yesterday.label = Consommation d'hier +channel-group-type.linky.daily.channel.yesterday.label = Consommation Hier channel-group-type.linky.monthly.label = Consommation mensuelle -channel-group-type.linky.monthly.channel.lastMonth.label = Consommation du mois dernier -channel-group-type.linky.monthly.channel.thisMonth.label = Consommation de ce mois-ci +channel-group-type.linky.monthly.channel.lastMonth.label = Consommation Mois Dernier +channel-group-type.linky.monthly.channel.thisMonth.label = Consommation Mois Actuel channel-group-type.linky.weekly.label = Consommation hebdomadaire -channel-group-type.linky.weekly.channel.lastWeek.label = Consommation de la semaine dernière -channel-group-type.linky.weekly.channel.thisWeek.label = Consommation de cette semaine +channel-group-type.linky.weekly.channel.lastWeek.label = Consommation Semaine Dernière +channel-group-type.linky.weekly.channel.thisWeek.label = Consommation Semaine Actuelle channel-group-type.linky.yearly.label = Consommation annuelle -channel-group-type.linky.yearly.channel.lastYear.label = Consommation de l'année dernière -channel-group-type.linky.yearly.channel.thisYear.label = Consommation de cette année +channel-group-type.linky.yearly.channel.lastYear.label = Consommation Année Dernière +channel-group-type.linky.yearly.channel.thisYear.label = Consommation Année Actuelle # channel types -channel-type.linky.consumption.label = Consommation totale +channel-type.linky.consumption.label = Consommation Totale channel-type.linky.consumption.description = Consommation pour un intervalle de temps donné -channel-type.linky.power.label = Pic de consommation d'hier +channel-type.linky.power.label = Pic Consommation Hier channel-type.linky.power.description = Pic maximum de consommation d'énergie hier channel-type.linky.timestamp.label = Horodatage diff --git a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties new file mode 100644 index 0000000000000..23096a95bb31d --- /dev/null +++ b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties @@ -0,0 +1,51 @@ +# binding + +binding.logreader.name = LogReader Binding +binding.logreader.description = Das LogReader Binding ermöglicht es Logdateien zu überwachen und auf Fehler, Warnungen oder benutzerdefinierte Einträge zu durchsuchen. + +# thing types + +thing-type.logreader.reader.label = Logdatei +thing-type.logreader.reader.description = Logdatei, die überwacht werden soll. + +# thing types config + +thing-type.config.logreader.reader.customBlacklistingPatterns.label = Benutzerdefinierte Muster-Blacklist +thing-type.config.logreader.reader.customBlacklistingPatterns.description = Benutzerdefinierte Muster-Blacklist, die ignoriert werden sollen, getrennt durch |. +thing-type.config.logreader.reader.customPatterns.label = Benutzerdefinierte Muster +thing-type.config.logreader.reader.customPatterns.description = Benutzerdefinierte Muster getrennt durch |. +thing-type.config.logreader.reader.errorBlacklistingPatterns.label = Muster-Blacklist für Fehler +thing-type.config.logreader.reader.errorBlacklistingPatterns.description = Muster-Blacklist für Fehler, die ignoriert werden sollen, getrennt durch |. +thing-type.config.logreader.reader.errorPatterns.label = Muster für Fehler +thing-type.config.logreader.reader.errorPatterns.description = Muster für Fehler getrennt durch |. Standard ist "ERROR+". +thing-type.config.logreader.reader.filePath.label = Dateipfad +thing-type.config.logreader.reader.filePath.description = Pfad zur Logdatei. +thing-type.config.logreader.reader.refreshRate.label = Aktualisierungsintervall +thing-type.config.logreader.reader.refreshRate.description = Intervall zur Aktualisierung der Logdatei (in Millisekunden). +thing-type.config.logreader.reader.warningBlacklistingPatterns.label = Muster-Blacklist für Warnungen +thing-type.config.logreader.reader.warningBlacklistingPatterns.description = Muster-Blacklist für Warnungen, die ignoriert werden sollen, getrennt durch |. +thing-type.config.logreader.reader.warningPatterns.label = Muster für Warnungen +thing-type.config.logreader.reader.warningPatterns.description = Muster für Warnungen getrennt durch |. Standard ist "WARN+". + +# channel types + +channel-type.logreader.customEvents.label = Anzahl der Benutzerdefinierten Einträge +channel-type.logreader.customEvents.description = Zeigt die Anzahl der Einträge an, die mit dem benutzerdefiniertem Muster übereinstimmen. +channel-type.logreader.errorEvents.label = Anzahl der Fehler +channel-type.logreader.errorEvents.description = Zeigt die Anzahl der Einträge an, die mit dem Muster für Fehler übereinstimmen. +channel-type.logreader.lastCustomEvent.label = Neuester Benutzerdefinierter Eintrag +channel-type.logreader.lastCustomEvent.description = Zeigt den neuesten Eintrag an, der mit dem benutzerdefinierten Muster übereinstimmt. +channel-type.logreader.lastErrorEvent.label = Neuester Fehler +channel-type.logreader.lastErrorEvent.description = Zeigt den neuesten Eintrag an, der mit dem Muster für Fehler übereinstimmt. +channel-type.logreader.lastWarningEvent.label = Neueste Warnung +channel-type.logreader.lastWarningEvent.description = Zeigt den neuesten Eintrag an, der mit dem Muster für Warnungen übereinstimmt. +channel-type.logreader.logRotated.label = Letzte Rotation +channel-type.logreader.logRotated.description = Zeigt die Zeit an, zu der die Logdatei zuletzt rotiert wurde. +channel-type.logreader.newCustomEvent.label = Neuer Benutzerdefinierter Eintrag +channel-type.logreader.newCustomEvent.description = Dieser Channel wird bei einem neuen Eintrag ausgelöst, der mit dem benutzerdefinierten Muster übereinstimmt. +channel-type.logreader.newErrorEvent.label = Neuer Fehler +channel-type.logreader.newErrorEvent.description = Dieser Channel wird bei einem neuen Eintrag ausgelöst, der mit dem Muster für Fehler übereinstimmt. +channel-type.logreader.newWarningEvent.label = Neue Warnung +channel-type.logreader.newWarningEvent.description = Dieser Channel wird bei einem neuen Eintrag ausgelöst, der mit dem Muster für Warnungen übereinstimmt. +channel-type.logreader.warningEvents.label = Anzahl der Warnungen +channel-type.logreader.warningEvents.description = Zeigt die Anzahl der Einträge an, die mit dem Muster für Warnungen übereinstimmen. diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties index 60032404647ec..807b6aee5777c 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_fr.properties @@ -33,7 +33,7 @@ config.username.label = Nom d'utilisateur du serveur SMTP # channel types -channel-type.mail.mailcount.label = Nombre d'e-mails +channel-type.mail.mailcount.label = Nombre Courriers channel-type.mail.mailcount.description = Nombre d'e-mails dans le dossier # channel types config diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_hu.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_hu.properties new file mode 100644 index 0000000000000..78b1b8bcd8709 --- /dev/null +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail_hu.properties @@ -0,0 +1,61 @@ +# binding + +binding.mail.name = Levelezés kötés +binding.mail.description = Ez a kötés lehetővé teszi a POP3, IMAP és SMTP kiszolgáló kapcsolódását. + +# thing types + +thing-type.mail.imap.label = IMAP kiszolgáló +thing-type.mail.imap.description = Levelek fogadására használható +thing-type.mail.pop3.label = POP3 kiszolgáló +thing-type.mail.pop3.description = Levelek fogadására használható +thing-type.mail.smtp.label = SMTP kiszolgáló +thing-type.mail.smtp.description = Szabályok végrehajtásakor levelek küldésére használható + +# thing types config + +thing-type.config.mail.imap.port.description = Alapértelmezetten 143 (alap/STARTTLS) és 993 (SSL/TLS) +thing-type.config.mail.pop3.port.description = Alapértelmezetten 110 (alap/STARTTLS) és 995 (SSL/TLS) +thing-type.config.mail.smtp.port.description = Alapértelmezetten 25 (alap/STARTTLS) és 465 (SSL/TLS) +thing-type.config.mail.smtp.sender.label = Küldő +thing-type.config.mail.smtp.sender.description = A levelek alapértelmezett küldője + +config.hostname.label = Kiszolgáló gépneve +config.password.label = SMTP kiszolgáló jelszava +config.port.label = Kiszolgáló port +config.refresh.label = Frissítési idő +config.refresh.description = Az azonosítóhoz tartozó frissítési időköz másodpercben +config.security.label = SMTP kiszolgáló protokollja +config.security.option.PLAIN = normál +config.security.option.STARTTLS = STARTTLS +config.security.option.SSL = SSL/TLS +config.username.label = SMTP kiszolgáló azonosító + +# channel types + +channel-type.mail.mailcount.label = Levelek száma +channel-type.mail.mailcount.description = A mappában található levelek száma + +# channel types config + +channel-type.config.mail.mailcount.folder.label = Mappa neve +channel-type.config.mail.mailcount.type.label = Számláló típusa +channel-type.config.mail.mailcount.type.option.UNREAD = Olvasatlan +channel-type.config.mail.mailcount.type.option.TOTAL = Összes + +# actions + +addHeaderActionLabel = fejléc hozzáadása +addHeaderActionDescription = A leveléhez fejlécet ad hozzá. +sendAttachmentMessageActionLabel = levél küldése csatolmánnyal +sendAttachmentMessageActionDescription = Levél küldése webcímes csatolmánnyal. +sendAttachmentsMessageActionLabel = levél küldése több csatolmánnyal +sendAttachmentsMessageActionDescription = Levél küldése több webcímes csatolmánnyal. +sendHTMLAttachmentMessageActionLabel = HTML üzenet küldése csatolmánnyal +sendHTMLAttachmentMessageActionDescription = HTML üzenet küldése webcímes csatolmánnyal. +sendHTMLAttachmentsMessageActionLabel = HTML üzenet küldése több csatolmánnyal +sendHTMLAttachmentsMessageActionDescription = HTML üzenet küldése több webcímes csatolmánnyal. +sendHTMLMessageActionLabel = HTML üzenet küldése +sendHTMLMessageActionDescription = HTML (formázott) üzenet küldése. +sendMessageActionLabel = szöveges levél küldése +sendMessageActionDescription = Szöveges levél küldése. diff --git a/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max_de.properties b/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max_de.properties index 8774bf116a8b7..6ffecc27fabca 100644 --- a/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max_de.properties +++ b/bundles/org.openhab.binding.max/src/main/resources/OH-INF/i18n/max_de.properties @@ -1,278 +1,199 @@ # binding -binding.max.name = MAX! Heizungssteuerung Binding -binding.max.description = Dieses Binding integriert die MAX! Heizungssteuerung (z.B. Heizkörperthermostat, Heizkörperthermostat+, Wandthermostat+, Eco Taster, Fensterkontakt). -# bridge types -thing-type.max.bridge.description = MAX! Cube LAN Gateway. +binding.max.name = MAX\! Heizungssteuerung Binding +binding.max.description = Dieses Binding integriert die MAX\! Heizungssteuerung (z.B. Heizkörperthermostat, Heizkörperthermostat+, Wandthermostat+, Eco Taster, Fensterkontakt). -# bridge types config groups -thing-type.config.max.bridge.group.identification.label = Identifizierung -thing-type.config.max.bridge.group.identification.description = Einstellungen für die Identifizierung des Gerätes. +# thing types -thing-type.config.max.bridge.group.network.label = Netzwerk -thing-type.config.max.bridge.group.network.description = Einstellungen für das Netzwerk. +thing-type.max.bridge.label = MAX\! Cube LAN Gateway +thing-type.max.bridge.description = MAX\! Cube LAN Gateway. +thing-type.max.ecoswitch.label = MAX\! Eco Taster +thing-type.max.ecoswitch.description = MAX\! Eco Taster. Dient zur Steuerung von Heizkörperthermostaten. +thing-type.max.shuttercontact.label = MAX\! Fensterkontakt +thing-type.max.shuttercontact.description = MAX\! Fensterkontakt. Liefert Daten wie z.B. Fenster-Zustand. +thing-type.max.thermostat.label = MAX\! Heizkörperthermostat +thing-type.max.thermostat.description = MAX\! Heizkörperthermostat und MAX\! Heizkörperthermostat basic. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur. +thing-type.max.thermostatplus.label = MAX\! Heizkörperthermostat+ +thing-type.max.thermostatplus.description = MAX\! Heizkörperthermostat+. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur. +thing-type.max.wallthermostat.label = MAX\! Wandthermostat+ +thing-type.max.wallthermostat.description = MAX\! Wandthermostat+. Dient zur Steuerung von Heizkörperthermostaten und liefert Daten wie z.B. Temperatur. -thing-type.config.max.bridge.group.device.label = Gerät -thing-type.config.max.bridge.group.device.description = Einstellungen für das Gerät. +# thing types config +thing-type.config.max.bridge.action-cubeReboot.label = Neustart +thing-type.config.max.bridge.action-cubeReboot.description = Ermöglicht das MAX Cube LAN Gateway neu zu starten. +thing-type.config.max.bridge.action-cubeReboot.option.1234 = Neustarten +thing-type.config.max.bridge.action-cubeReboot.option.-1 = Keine Aktion +thing-type.config.max.bridge.action-cubeReset.label = Werkszustand +thing-type.config.max.bridge.action-cubeReset.description = Ermöglicht das MAX Cube LAN Gateway in den Werkszustand zurück zu versetzen. +thing-type.config.max.bridge.action-cubeReset.option.1234 = Zurücksetzen +thing-type.config.max.bridge.action-cubeReset.option.-1 = Keine Aktion +thing-type.config.max.bridge.exclusive.label = Exklusivmodus +thing-type.config.max.bridge.exclusive.description = Setzt den Exklusivmodus zur Nutzung des MAX\! Cube LAN Gateways. thing-type.config.max.bridge.group.actions.label = Aktionen thing-type.config.max.bridge.group.actions.description = Einstellungen für Aktionen. - -# bridge types config +thing-type.config.max.bridge.group.device.label = Gerät +thing-type.config.max.bridge.group.device.description = Einstellungen für das Gerät. +thing-type.config.max.bridge.group.identification.label = Identifizierung +thing-type.config.max.bridge.group.identification.description = Einstellungen für die Identifizierung des Gerätes. +thing-type.config.max.bridge.group.network.label = Netzwerk +thing-type.config.max.bridge.group.network.description = Einstellungen für das Netzwerk. thing-type.config.max.bridge.ipAddress.label = IP-Adresse -thing-type.config.max.bridge.ipAddress.description = Lokale IP-Adresse oder Hostname des MAX! Cube LAN Gateway. - -thing-type.config.max.bridge.port.label = Port -thing-type.config.max.bridge.port.description = Port des MAX! Cube LAN Gateway. - -thing-type.config.max.bridge.refreshInterval.label = Abfrageintervall -thing-type.config.max.bridge.refreshInterval.description = Intervall zur Abfrage des MAX! Cube LAN Gateway (in Sekunden). - -thing-type.config.max.bridge.serialNumber.label = Seriennummer -thing-type.config.max.bridge.serialNumber.description = Seriennummer des MAX! Cube LAN Gateway. - -thing-type.config.max.bridge.rfAddress.label = RF-Addresse -thing-type.config.max.bridge.rfAddress.description = RF-Addresse des MAX! Cube LAN Gateway. - -thing-type.config.max.bridge.exclusive.label = Exklusivmodus -thing-type.config.max.bridge.exclusive.description = Setzt den Exklusivmodus zur Nutzung des MAX! Cube LAN Gateways. - +thing-type.config.max.bridge.ipAddress.description = IP-Adresse oder Hostname des MAX\! Cube LAN Gateway. thing-type.config.max.bridge.maxRequestsPerConnection.label = Verbindingsanzahl -thing-type.config.max.bridge.maxRequestsPerConnection.description = Maximale Anzahl an Verbindungen zum MAX! Cube LAN Gateways. - +thing-type.config.max.bridge.maxRequestsPerConnection.description = Maximale Anzahl an Verbindungen zum MAX\! Cube LAN Gateways. thing-type.config.max.bridge.ntpServer1.label = 1. NTP-Server thing-type.config.max.bridge.ntpServer1.description = Erster NTP-Server zur Abfrage des Datums und der Zeit. - thing-type.config.max.bridge.ntpServer2.label = 2. NTP-Server thing-type.config.max.bridge.ntpServer2.description = Zweiter NTP-Server zur Abfrage des Datums und der Zeit. - -thing-type.config.max.bridge.action-cubeReset.label = Werkszustand -thing-type.config.max.bridge.action-cubeReset.description = Ermöglicht das MAX Cube LAN Gateway in den Werkszustand zurück zu versetzen. -thing-type.config.max.bridge.action-cubeReset.option.1234 = Zurücksetzen -thing-type.config.max.bridge.action-cubeReset.option.-1 = Keine Aktion - -thing-type.config.max.bridge.action-cubeReboot.label = Neustart -thing-type.config.max.bridge.action-cubeReboot.description = Ermöglicht das MAX Cube LAN Gateway neu zu starten. -thing-type.config.max.bridge.action-cubeReboot.option.1234 = Neustarten -thing-type.config.max.bridge.action-cubeReboot.option.-1 = Keine Aktion - -# thing types -thing-type.max.thermostat.label = MAX! Heizkörperthermostat -thing-type.max.thermostat.description = MAX! Heizkörperthermostat und MAX! Heizkörperthermostat basic. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur. - -thing-type.max.thermostatplus.label = MAX! Heizkörperthermostat+ -thing-type.max.thermostatplus.description = MAX! Heizkörperthermostat+. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur. - -thing-type.max.wallthermostat.label = MAX! Wandthermostat+ -thing-type.max.wallthermostat.description = MAX! Wandthermostat+. Dient zur Steuerung von Heizkörperthermostaten und liefert Daten wie z.B. Temperatur. - -thing-type.max.ecoswitch.label = MAX! Eco Taster -thing-type.max.ecoswitch.description = MAX! Eco Taster. Dient zur Steuerung von Heizkörperthermostaten. - -thing-type.max.shuttercontact.label = MAX! Fensterkontakt -thing-type.max.shuttercontact.description = MAX! Fensterkontakt. Liefert Daten wie z.B. Fenster-Zustand. - -# thing types config groups -thing-type.config.max.thermostat.group.identification.label = Identifizierung -thing-type.config.max.thermostat.group.identification.description = Einstellungen für die Identifizierung des Gerätes. - -thing-type.config.max.thermostat.group.device.label = Gerät -thing-type.config.max.thermostat.group.device.description = Einstellungen für das Gerät. - -thing-type.config.max.thermostat.group.binding.label = Binding -thing-type.config.max.thermostat.group.binding.description = Einstellungen für das Binding. - -thing-type.config.max.thermostat.group.actions.label = Aktionen -thing-type.config.max.thermostat.group.actions.description = Einstellungen für Aktionen. - -thing-type.config.max.thermostatplus.group.identification.label = Identifizierung -thing-type.config.max.thermostatplus.group.identification.description = Einstellungen für die Identifizierung des Gerätes. - -thing-type.config.max.thermostatplus.group.device.label = Gerät -thing-type.config.max.thermostatplus.group.device.description = Einstellungen für das Gerät. - -thing-type.config.max.thermostatplus.group.actions.label = Aktionen -thing-type.config.max.thermostatplus.group.actions.description = Einstellungen für Aktionen. - -thing-type.config.max.thermostatplus.group.binding.label = Binding -thing-type.config.max.thermostatplus.group.binding.description = Einstellungen für das Binding. - -thing-type.config.max.wallthermostat.group.identification.label = Identifizierung -thing-type.config.max.wallthermostat.group.identification.description = Einstellungen für die Identifizierung des Gerätes. - -thing-type.config.max.wallthermostat.group.device.label = Gerät -thing-type.config.max.wallthermostat.group.device.description = Einstellungen für das Gerät. - -thing-type.config.max.wallthermostat.group.actions.label = Aktionen -thing-type.config.max.wallthermostat.group.actions.description = Einstellungen für Aktionen. - -thing-type.config.max.ecoswitch.group.identification.label = Identifizierung -thing-type.config.max.ecoswitch.group.identification.description = Einstellungen für die Identifizierung des Gerätes. - +thing-type.config.max.bridge.port.label = Port +thing-type.config.max.bridge.port.description = Port des MAX\! Cube LAN Gateway. +thing-type.config.max.bridge.refreshInterval.label = Abfrageintervall +thing-type.config.max.bridge.refreshInterval.description = Intervall zur Abfrage des MAX\! Cube LAN Gateway (in Sekunden). +thing-type.config.max.bridge.rfAddress.label = RF-Addresse +thing-type.config.max.bridge.rfAddress.description = RF-Addresse des MAX\! Cube LAN Gateway. +thing-type.config.max.bridge.serialNumber.label = Seriennummer +thing-type.config.max.bridge.serialNumber.description = Seriennummer des MAX\! Cube LAN Gateway. thing-type.config.max.ecoswitch.group.device.label = Gerät thing-type.config.max.ecoswitch.group.device.description = Einstellungen für das Gerät. - -thing-type.config.max.shuttercontact.group.identification.label = Identifizierung -thing-type.config.max.shuttercontact.group.identification.description = Einstellungen für die Identifizierung des Gerätes. - -thing-type.config.max.shuttercontact.group.device.label = Gerät -thing-type.config.max.shuttercontact.group.device.description = Einstellungen für das Gerät. - +thing-type.config.max.ecoswitch.group.identification.label = Identifizierung +thing-type.config.max.ecoswitch.group.identification.description = Einstellungen für die Identifizierung des Gerätes. +thing-type.config.max.ecoswitch.name.label = Name +thing-type.config.max.ecoswitch.name.description = Benutzerspezifischer Namen des Gerätes. +thing-type.config.max.ecoswitch.rfAddress.label = RF-Addresse +thing-type.config.max.ecoswitch.rfAddress.description = RF-Addresse des Gerätes. +thing-type.config.max.ecoswitch.room.label = Raum +thing-type.config.max.ecoswitch.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. +thing-type.config.max.ecoswitch.serialNumber.label = Seriennummer +thing-type.config.max.ecoswitch.serialNumber.description = Seriennummer des Gerätes. +thing-type.config.max.shuttercontact.action-deviceDelete.label = Gerät trennen +thing-type.config.max.shuttercontact.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX\! Cube LAN Gateway. +thing-type.config.max.shuttercontact.action-deviceDelete.option.1234 = Löschen +thing-type.config.max.shuttercontact.action-deviceDelete.option.-1 = Keine Aktion thing-type.config.max.shuttercontact.group.actions.label = Aktionen thing-type.config.max.shuttercontact.group.actions.description = Einstellungen für Aktionen. - -# thing types config -thing-type.config.max.thermostat.room.label = Raum -thing-type.config.max.thermostat.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. - -thing-type.config.max.thermostat.name.label = Name -thing-type.config.max.thermostat.name.description = Benutzerspezifischer Namen des Gerätes. - +thing-type.config.max.shuttercontact.group.device.label = Gerät +thing-type.config.max.shuttercontact.group.device.description = Einstellungen für das Gerät. +thing-type.config.max.shuttercontact.group.identification.label = Identifizierung +thing-type.config.max.shuttercontact.group.identification.description = Einstellungen für die Identifizierung des Gerätes. +thing-type.config.max.shuttercontact.name.label = Name +thing-type.config.max.shuttercontact.name.description = Benutzerspezifischer Namen des Gerätes. +thing-type.config.max.shuttercontact.rfAddress.label = RF-Addresse +thing-type.config.max.shuttercontact.rfAddress.description = RF-Addresse des Gerätes. +thing-type.config.max.shuttercontact.room.label = Raum +thing-type.config.max.shuttercontact.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. +thing-type.config.max.shuttercontact.serialNumber.label = Seriennummer +thing-type.config.max.shuttercontact.serialNumber.description = Seriennummer des Gerätes. +thing-type.config.max.thermostat.action-deviceDelete.label = Gerät trennen +thing-type.config.max.thermostat.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX\! Cube LAN Gateway. +thing-type.config.max.thermostat.action-deviceDelete.option.1234 = Löschen +thing-type.config.max.thermostat.action-deviceDelete.option.-1 = Keine Aktion thing-type.config.max.thermostat.comfortTemp.label = Komforttemperatur thing-type.config.max.thermostat.comfortTemp.description = Gibt die Komforttemperatur (in °C) des Heizkörperthermostats an. - thing-type.config.max.thermostat.ecoTemp.label = Absenktemperatur thing-type.config.max.thermostat.ecoTemp.description = Gibt die Absenktemperatur (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostat.offsetTemp.label = Temperatur-Offset -thing-type.config.max.thermostat.offsetTemp.description = Gibt den Temperatur-Offset (in °C) des Heizkörperthermostats an. - +thing-type.config.max.thermostat.group.actions.label = Aktionen +thing-type.config.max.thermostat.group.actions.description = Einstellungen für Aktionen. +thing-type.config.max.thermostat.group.binding.label = Binding +thing-type.config.max.thermostat.group.binding.description = Einstellungen für das Binding. +thing-type.config.max.thermostat.group.device.label = Gerät +thing-type.config.max.thermostat.group.device.description = Einstellungen für das Gerät. +thing-type.config.max.thermostat.group.identification.label = Identifizierung +thing-type.config.max.thermostat.group.identification.description = Einstellungen für die Identifizierung des Gerätes. thing-type.config.max.thermostat.maxTempSetpoint.label = Max. Solltemperatur thing-type.config.max.thermostat.maxTempSetpoint.description = Gibt die maximal einstellbare Solltemperatur (in °C) des Heizkörperthermostats an. - thing-type.config.max.thermostat.minTempSetpoint.label = Min. Solltemperatur thing-type.config.max.thermostat.minTempSetpoint.description = Gibt die minimal einstellbare Solltemperatur (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostat.windowOpenTemp.label = Fenster-Auf-Temperatur -thing-type.config.max.thermostat.windowOpenTemp.description = Gibt die Temperatur bei geöffnetem Fenster-Zustand (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostat.windowOpenDuration.label = Dauer Fenster-Auf-Temperatur -thing-type.config.max.thermostat.windowOpenDuration.description = Gibt die Dauer der Absenkung auf die Fenster-Auf-Temperatur (in Minuten) des Heizkörperthermostats an. - -thing-type.config.max.thermostat.serialNumber.label = Seriennummer -thing-type.config.max.thermostat.serialNumber.description = Seriennummer des Gerätes. - +thing-type.config.max.thermostat.name.label = Name +thing-type.config.max.thermostat.name.description = Benutzerspezifischer Namen des Gerätes. +thing-type.config.max.thermostat.offsetTemp.label = Temperatur-Offset +thing-type.config.max.thermostat.offsetTemp.description = Gibt den Temperatur-Offset (in °C) des Heizkörperthermostats an. +thing-type.config.max.thermostat.refreshActualRate.label = Aktualisierungsrate +thing-type.config.max.thermostat.refreshActualRate.description = Experimentelles Feature\! Intervall zur Aktualisierung (in Minuten). 0-9\=deaktiviert, minimales Aktualisierungsintervall 10min, empfohlen 60min. Die Einstellungen der Heizkörperthermostat werden so geändert, dass eine Aktualisierung der Temperatur ausgelöst wird, da die tatsächliche Temperatur nur bei Änderung der Ventilposition aktualisiert wird. thing-type.config.max.thermostat.rfAddress.label = RF-Addresse thing-type.config.max.thermostat.rfAddress.description = RF-Addresse des Gerätes. - -thing-type.config.max.thermostat.refreshActualRate.label = Aktualisierungsrate - -thing-type.config.max.thermostat.action-deviceDelete.label = Gerät trennen -thing-type.config.max.thermostat.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX! Cube LAN Gateway. -thing-type.config.max.thermostat.action-deviceDelete.option.1234 = Löschen -thing-type.config.max.thermostat.action-deviceDelete.option.-1 = Keine Aktion - -thing-type.config.max.thermostatplus.room.label = Raum -thing-type.config.max.thermostatplus.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. - -thing-type.config.max.thermostatplus.name.label = Name -thing-type.config.max.thermostatplus.name.description = Benutzerspezifischer Namen des Gerätes. - +thing-type.config.max.thermostat.room.label = Raum +thing-type.config.max.thermostat.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. +thing-type.config.max.thermostat.serialNumber.label = Seriennummer +thing-type.config.max.thermostat.serialNumber.description = Seriennummer des Gerätes. +thing-type.config.max.thermostat.windowOpenDuration.label = Dauer Fenster-Auf-Temperatur +thing-type.config.max.thermostat.windowOpenDuration.description = Gibt die Dauer der Absenkung auf die Fenster-Auf-Temperatur (in Minuten) des Heizkörperthermostats an. +thing-type.config.max.thermostat.windowOpenTemp.label = Fenster-Auf-Temperatur +thing-type.config.max.thermostat.windowOpenTemp.description = Gibt die Temperatur bei geöffnetem Fenster-Zustand (in °C) des Heizkörperthermostats an. +thing-type.config.max.thermostatplus.action-deviceDelete.label = Gerät trennen +thing-type.config.max.thermostatplus.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX\! Cube LAN Gateway. +thing-type.config.max.thermostatplus.action-deviceDelete.option.1234 = Löschen +thing-type.config.max.thermostatplus.action-deviceDelete.option.-1 = Keine Aktion thing-type.config.max.thermostatplus.comfortTemp.label = Komforttemperatur thing-type.config.max.thermostatplus.comfortTemp.description = Gibt die Komforttemperatur (in °C) des Heizkörperthermostats an. - thing-type.config.max.thermostatplus.ecoTemp.label = Absenktemperatur thing-type.config.max.thermostatplus.ecoTemp.description = Gibt die Absenktemperatur (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostatplus.offsetTemp.label = Temperatur-Offset -thing-type.config.max.thermostatplus.offsetTemp.description = Gibt den Temperatur-Offset (in °C) des Heizkörperthermostats an. - +thing-type.config.max.thermostatplus.group.actions.label = Aktionen +thing-type.config.max.thermostatplus.group.actions.description = Einstellungen für Aktionen. +thing-type.config.max.thermostatplus.group.binding.label = Binding +thing-type.config.max.thermostatplus.group.binding.description = Einstellungen für das Binding. +thing-type.config.max.thermostatplus.group.device.label = Gerät +thing-type.config.max.thermostatplus.group.device.description = Einstellungen für das Gerät. +thing-type.config.max.thermostatplus.group.identification.label = Identifizierung +thing-type.config.max.thermostatplus.group.identification.description = Einstellungen für die Identifizierung des Gerätes. thing-type.config.max.thermostatplus.maxTempSetpoint.label = Max. Solltemperatur thing-type.config.max.thermostatplus.maxTempSetpoint.description = Gibt die maximal einstellbare Solltemperatur (in °C) des Heizkörperthermostats an. - thing-type.config.max.thermostatplus.minTempSetpoint.label = Min. Solltemperatur thing-type.config.max.thermostatplus.minTempSetpoint.description = Gibt die minimal einstellbare Solltemperatur (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostatplus.windowOpenTemp.label = Fenster-Auf-Temperatur -thing-type.config.max.thermostatplus.windowOpenTemp.description = Gibt die Temperatur bei geöffnetem Fenster-Zustand (in °C) des Heizkörperthermostats an. - -thing-type.config.max.thermostatplus.windowOpenDuration.label = Dauer Fenster-Auf-Temperatur -thing-type.config.max.thermostatplus.windowOpenDuration.description = Gibt die Dauer der Absenkung auf die Fenster-Auf-Temperatur (in Minuten) des Heizkörperthermostats an. - -thing-type.config.max.thermostatplus.serialNumber.label = Seriennummer -thing-type.config.max.thermostatplus.serialNumber.description = Seriennummer des Gerätes. - +thing-type.config.max.thermostatplus.name.label = Name +thing-type.config.max.thermostatplus.name.description = Benutzerspezifischer Namen des Gerätes. +thing-type.config.max.thermostatplus.offsetTemp.label = Temperatur-Offset +thing-type.config.max.thermostatplus.offsetTemp.description = Gibt den Temperatur-Offset (in °C) des Heizkörperthermostats an. +thing-type.config.max.thermostatplus.refreshActualRate.label = Aktualisierungsrate +thing-type.config.max.thermostatplus.refreshActualRate.description = Experimentelles Feature\! Intervall zur Aktualisierung (in Minuten). 0-9\=deaktiviert, minimales Aktualisierungsintervall 10min, empfohlen 60min. Die Einstellungen der Heizkörperthermostat werden so geändert, dass eine Aktualisierung der Temperatur ausgelöst wird, da die tatsächliche Temperatur nur bei Änderung der Ventilposition aktualisiert wird. thing-type.config.max.thermostatplus.rfAddress.label = RF-Addresse thing-type.config.max.thermostatplus.rfAddress.description = RF-Addresse des Gerätes. - -thing-type.config.max.thermostatplus.refreshActualRate.label = Aktualisierungsrate - -thing-type.config.max.thermostatplus.action-deviceDelete.label = Gerät trennen -thing-type.config.max.thermostatplus.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX! Cube LAN Gateway. -thing-type.config.max.thermostatplus.action-deviceDelete.option.1234 = Löschen -thing-type.config.max.thermostatplus.action-deviceDelete.option.-1 = Keine Aktion - -thing-type.config.max.wallthermostat.room.label = Raum -thing-type.config.max.wallthermostat.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. - +thing-type.config.max.thermostatplus.room.label = Raum +thing-type.config.max.thermostatplus.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. +thing-type.config.max.thermostatplus.serialNumber.label = Seriennummer +thing-type.config.max.thermostatplus.serialNumber.description = Seriennummer des Gerätes. +thing-type.config.max.thermostatplus.windowOpenDuration.label = Dauer Fenster-Auf-Temperatur +thing-type.config.max.thermostatplus.windowOpenDuration.description = Gibt die Dauer der Absenkung auf die Fenster-Auf-Temperatur (in Minuten) des Heizkörperthermostats an. +thing-type.config.max.thermostatplus.windowOpenTemp.label = Fenster-Auf-Temperatur +thing-type.config.max.thermostatplus.windowOpenTemp.description = Gibt die Temperatur bei geöffnetem Fenster-Zustand (in °C) des Heizkörperthermostats an. +thing-type.config.max.wallthermostat.action-deviceDelete.label = Gerät trennen +thing-type.config.max.wallthermostat.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX\! Cube LAN Gateway. +thing-type.config.max.wallthermostat.action-deviceDelete.option.1234 = Löschen +thing-type.config.max.wallthermostat.action-deviceDelete.option.-1 = Keine Aktion +thing-type.config.max.wallthermostat.group.actions.label = Aktionen +thing-type.config.max.wallthermostat.group.actions.description = Einstellungen für Aktionen. +thing-type.config.max.wallthermostat.group.device.label = Gerät +thing-type.config.max.wallthermostat.group.device.description = Einstellungen für das Gerät. +thing-type.config.max.wallthermostat.group.identification.label = Identifizierung +thing-type.config.max.wallthermostat.group.identification.description = Einstellungen für die Identifizierung des Gerätes. thing-type.config.max.wallthermostat.name.label = Name thing-type.config.max.wallthermostat.name.description = Benutzerspezifischer Namen des Gerätes. - -thing-type.config.max.wallthermostat.serialNumber.label = Seriennummer -thing-type.config.max.wallthermostat.serialNumber.description = Seriennummer des Gerätes. - thing-type.config.max.wallthermostat.rfAddress.label = RF-Addresse thing-type.config.max.wallthermostat.rfAddress.description = RF-Addresse des Gerätes. - -thing-type.config.max.wallthermostat.action-deviceDelete.label = Gerät trennen -thing-type.config.max.wallthermostat.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX! Cube LAN Gateway. -thing-type.config.max.wallthermostat.action-deviceDelete.option.1234 = Löschen -thing-type.config.max.wallthermostat.action-deviceDelete.option.-1 = Keine Aktion - -thing-type.config.max.ecoswitch.room.label = Raum -thing-type.config.max.ecoswitch.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. - -thing-type.config.max.ecoswitch.name.label = Name -thing-type.config.max.ecoswitch.name.description = Benutzerspezifischer Namen des Gerätes. - -thing-type.config.max.ecoswitch.serialNumber.label = Seriennummer -thing-type.config.max.ecoswitch.serialNumber.description = Seriennummer des Gerätes. - -thing-type.config.max.ecoswitch.rfAddress.label = RF-Addresse -thing-type.config.max.ecoswitch.rfAddress.description = RF-Addresse des Gerätes. - -thing-type.config.max.shuttercontact.room.label = Raum -thing-type.config.max.shuttercontact.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. - -thing-type.config.max.shuttercontact.name.label = Name -thing-type.config.max.shuttercontact.name.description = Benutzerspezifischer Namen des Gerätes. - -thing-type.config.max.shuttercontact.serialNumber.label = Seriennummer -thing-type.config.max.shuttercontact.serialNumber.description = Seriennummer des Gerätes. - -thing-type.config.max.shuttercontact.rfAddress.label = RF-Addresse -thing-type.config.max.shuttercontact.rfAddress.description = RF-Addresse des Gerätes. - -thing-type.config.max.shuttercontact.action-deviceDelete.label = Gerät trennen -thing-type.config.max.shuttercontact.action-deviceDelete.description = Ermöglicht das Trennen des Gerätes vom MAX! Cube LAN Gateway. -thing-type.config.max.shuttercontact.action-deviceDelete.option.1234 = Löschen -thing-type.config.max.shuttercontact.action-deviceDelete.option.-1 = Keine Aktion +thing-type.config.max.wallthermostat.room.label = Raum +thing-type.config.max.wallthermostat.room.description = Benutzerspezifischer Namen des Raumes, dem das Gerät zugeordnet ist. +thing-type.config.max.wallthermostat.serialNumber.label = Seriennummer +thing-type.config.max.wallthermostat.serialNumber.description = Seriennummer des Gerätes. # channel types -channel-type.max.free_mem.label = Freie Speicherplätze -channel-type.max.free_mem.description = Gibt an, wie viele freie Speicherplätze im MAX! Cube LAN Gateway für Befehle zur Verfügung stehen. +channel-type.max.actual_temp.label = Temperatur +channel-type.max.actual_temp.description = Zeigt die aktuell gemessene Temperatur des Heizkörperthermostat an. +channel-type.max.contact_state.label = Tür-/Fenster-Zustand +channel-type.max.contact_state.description = Zeigt an, ob die Tür oder das Fester offen oder geschlossen ist (OPEN oder CLOSED). channel-type.max.duty_cycle.label = Auslastungsgrad -channel-type.max.duty_cycle.description = Gibt den Auslastungsgrad für Befehle (in %) an. - -channel-type.max.valve.label = Ventil -channel-type.max.valve.description = Gibt die Ventilöffnung des Heizkörperreglers (in %) an. - -channel-type.max.mode.label = Modus des Gerätes -channel-type.max.mode.description = Gibt den aktuellen Modus des Gerätes an (MANUAL/AUTOMATIC/BOOST/VACATION). +channel-type.max.duty_cycle.description = Zeigt den Auslastungsgrad für Befehle (in %) an. +channel-type.max.free_mem.label = Freie Speicherplätze +channel-type.max.free_mem.description = Zeigt an, wie viele freie Speicherplätze im MAX\! Cube LAN Gateway für Befehle zur Verfügung stehen. +channel-type.max.locked.label = Tastensperre +channel-type.max.locked.description = Zeigt an, ob das Schalten per Taste am Gerät aktiviert ist. +channel-type.max.mode.label = Modus +channel-type.max.mode.description = Zeigt den aktuellen Modus des Heizkörperthermostat an (MANUAL, AUTOMATIC, \nBOOST, VACATION). channel-type.max.mode.state.option.AUTOMATIC = Automatisch channel-type.max.mode.state.option.MANUAL = Manuell channel-type.max.mode.state.option.BOOST = Boost channel-type.max.mode.state.option.VACATION = Urlaubsmodus - -channel-type.max.actual_temp.label = Temperatur -channel-type.max.actual_temp.description = Gibt die aktuell gemessene Temperatur des Thermostats an. - channel-type.max.set_temp.label = Solltemperatur -channel-type.max.set_temp.description = Gibt die aktuell eingestellte Solltemperatur des Thermostats an. - -channel-type.max.locked.label = Tastensperre -channel-type.max.locked.description = Gibt an, ob die Tastensperre am Gerät aktiviert ist. - -channel-type.max.contact_state.label = Fenster-Zustand -channel-type.max.contact_state.description = Gibt an, ob ein Fenster offen oder geschlossen ist. +channel-type.max.set_temp.description = Steuert die Solltemperatur des Heizkörperthermostat. +channel-type.max.valve.label = Ventilposition +channel-type.max.valve.description = Zeigt die aktuelle Ventilposition des Heizkörperthermostat an. diff --git a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_hu.properties b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_hu.properties index 389f27149bdb8..95bb92e571c24 100644 --- a/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_hu.properties +++ b/bundles/org.openhab.binding.ntp/src/main/resources/OH-INF/i18n/ntp_hu.properties @@ -1,3 +1,33 @@ +# binding +binding.ntp.name = NTP kötés +binding.ntp.description = Az NTP kötés a beállított időkiszolgálót kérdezi le és az aktuális dátumot és időt teszi közzé. + +# thing types +thing-type.ntp.ntp.label = NTP kiszolgáló +thing-type.ntp.ntp.description = Az NTP kiszolgáló mely a pontos időt adja meg + +# thing type configuration +thing-type.config.ntp.ntp.hostname.label = Gépnév +thing-type.config.ntp.ntp.hostname.description = Az NTP kiszolgáló gépneve. +thing-type.config.ntp.ntp.refreshInterval.label = Frissítés időköz +thing-type.config.ntp.ntp.refreshInterval.description = A másodpercekben megadott időköz, mely után a friss időpont továbbításra kerül az esemény buszon. +thing-type.config.ntp.ntp.refreshNtp.label = NTP frissítési időköz +thing-type.config.ntp.ntp.refreshNtp.description = A frissítések száma, mely után az NTP kiszolgáló lekérdezésre kerül. +thing-type.config.ntp.ntp.serverPort.label = Kiszolgáló port +thing-type.config.ntp.ntp.serverPort.description = A port, melyet az NTP kiszolgáló használ. +thing-type.config.ntp.ntp.timeZone.label = Időzóna +thing-type.config.ntp.ntp.timeZone.description = Az aktuális időzóna. + +# channel types +channel-type.ntp.dateTime-channel.label = Dátum +channel-type.ntp.dateTime-channel.description = A legutolsó NTP frissítés időpontja. +channel-type.ntp.string-channel.label = Dátum +channel-type.ntp.string-channel.description = A legutolsó NTP frissítés időpontja. + +# channel type configuration +channel-type.config.ntp.string-channel.DateTimeFormat.label = Dátum/idő formátum +channel-type.config.ntp.string-channel.DateTimeFormat.description = A dátum és idő szöveg formátuma. + # Thing status descriptions offline.comm-error-unknown-host = Az időkiszolgáló gazdaneve {0} ismeretlen -> helyette az aktuális rendszeridő kerül használatra. offline.comm-error-connection = A hálózati kapcsolat az időkiszolgálóval {0} nem hozható létre -> helyette az aktuális rendszer idő kerül használatra. diff --git a/bundles/org.openhab.binding.pushover/src/main/resources/OH-INF/i18n/pushover_de.properties b/bundles/org.openhab.binding.pushover/src/main/resources/OH-INF/i18n/pushover_de.properties index 0964286177f8e..3e3743d16b610 100644 --- a/bundles/org.openhab.binding.pushover/src/main/resources/OH-INF/i18n/pushover_de.properties +++ b/bundles/org.openhab.binding.pushover/src/main/resources/OH-INF/i18n/pushover_de.properties @@ -49,7 +49,7 @@ sendAttachmentMessageActionDescription = Action zum Versenden einer Textnachrich sendMessageActionInputAttachmentLabel = Anhang sendMessageActionInputAttachmentDescription = Lokaler Pfad oder URL zum Anhang. sendMessageActionInputContentTypeLabel = Content-Type -sendMessageActionInputContentTypeDescription = Der Content-Type für den Anhang. Default\: "image/jpeg". +sendMessageActionInputContentTypeDescription = Der Content-Type für den Anhang. Standard ist "image/jpeg". sendHTMLMessageActionLabel = eine HTML-Nachricht senden sendHTMLMessageActionDescription = Action zum Versenden einer HTML-Nachricht. sendMessageActionInputSoundLabel = Benachrichtigungston @@ -73,7 +73,7 @@ sendPriorityMessageActionDescription = Action zum Versenden einer Prioritätsnac sendPriorityMessageActionOutputLabel = Receipt sendPriorityMessageActionOutputDescription = ID der Prioritätsnachricht, wenn diese erfolgreich versendet wurde. sendMessageActionInputPriorityLabel = Priorität -sendMessageActionInputPriorityDescription = Die Priorität. Default\: 2. +sendMessageActionInputPriorityDescription = Die Priorität. Standard ist 2. sendURLMessageActionLabel = eine Textnachricht mit URL senden sendURLMessageActionDescription = Action zum Versenden einer Textnachricht mit einer URL. sendMessageActionInputURLLabel = URL diff --git a/bundles/org.openhab.binding.pushsafer/src/main/resources/OH-INF/i18n/pushsafer_de.properties b/bundles/org.openhab.binding.pushsafer/src/main/resources/OH-INF/i18n/pushsafer_de.properties index 1fc5961a3bb3f..39c1b35bbea4c 100644 --- a/bundles/org.openhab.binding.pushsafer/src/main/resources/OH-INF/i18n/pushsafer_de.properties +++ b/bundles/org.openhab.binding.pushsafer/src/main/resources/OH-INF/i18n/pushsafer_de.properties @@ -68,9 +68,9 @@ sendPushsaferAttachmentMessageActionDescription = Action zum Versenden einer Tex sendPushsaferMessageActionInputAttachmentLabel = Bild-Anhang sendPushsaferMessageActionInputAttachmentDescription = Lokaler Pfad oder URL zum Anhang. sendPushsaferMessageActionInputContentTypeLabel = Bild-Typ -sendPushsaferMessageActionInputContentTypeDescription = Der Bild-Typ für den Anhang. Default\: "jpeg", mögliche Werte "jpeg", "png" oder "gif". +sendPushsaferMessageActionInputContentTypeDescription = Der Bild-Typ für den Anhang. Standard ist "jpeg", mögliche Werte "jpeg", "png" oder "gif". sendPushsaferMessageActionInputAuthenticationLabel = Authentifizierung -sendPushsaferMessageActionInputAuthenticationDescription = Basisauthentifizierung für HTTP(S) Aufrufe. Default\: "", Beispiel\: "user\:passwort". +sendPushsaferMessageActionInputAuthenticationDescription = Basisauthentifizierung für HTTP(S) Aufrufe (z.B. "user\:passwort"). sendPushsaferMessageActionLabel = eine Textnachricht senden sendPushsaferMessageActionDescription = Action zum Versenden einer Textnachricht. sendPushsaferMessageActionOutputLabel = Gesendet @@ -90,7 +90,7 @@ sendPushsaferPriorityMessageActionDescription = Action zum Versenden einer Prior sendPushsaferPriorityMessageActionOutputLabel = Receipt sendPushsaferPriorityMessageActionOutputDescription = ID der Prioritätsnachricht, wenn diese erfolgreich versendet wurde. sendPushsaferMessageActionInputPriorityLabel = Priorität -sendPushsaferMessageActionInputPriorityDescription = Die Priorität. Default\: 2. +sendPushsaferMessageActionInputPriorityDescription = Die Priorität. Standard ist 2. sendPushsaferURLMessageActionLabel = eine Textnachricht mit URL senden sendPushsaferURLMessageActionDescription = Action zum Versenden einer Textnachricht mit einer URL. sendPushsaferMessageActionInputURLLabel = URL diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/resources/OH-INF/i18n/remoteopenhab_hu.properties b/bundles/org.openhab.binding.remoteopenhab/src/main/resources/OH-INF/i18n/remoteopenhab_hu.properties new file mode 100644 index 0000000000000..5f917b93104db --- /dev/null +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/resources/OH-INF/i18n/remoteopenhab_hu.properties @@ -0,0 +1,87 @@ +# binding + +binding.remoteopenhab.name = Távoli openHAB kötés +binding.remoteopenhab.description = A távoli openHAB kötés egyéb openHAB kiszolgálókkal való kommunikációt tesz lehetővé. + +# thing types + +thing-type.remoteopenhab.server.label = Távoli openHAB kiszolgáló +thing-type.remoteopenhab.server.description = A távoli openHAB kiszolgáló. Minden távoli tétel (item) egy helyi csatornának felel meg. +thing-type.remoteopenhab.thing.label = Távoli dolog +thing-type.remoteopenhab.thing.description = Egy dolog a távoli openHAB szerverről. Minden távoli trigger csatorna egy helyi csatornának felel meg (az állapot csatornák figyelmen kívül lesznek hagyva). + +# thing type configuration + +thing-type.config.remoteopenhab.server.accessibilityInterval.label = Hozzáférhetőség időzítő +thing-type.config.remoteopenhab.server.accessibilityInterval.description = A távoli szerver elérhetőségét ellenőrzi ennyi percenként. 0 kikapcsol. Alapértelmezetten 3. +thing-type.config.remoteopenhab.server.aliveInterval.label = Élő kapcsolat időtartam +thing-type.config.remoteopenhab.server.aliveInterval.description = A távoli szerver eseményeinek érkezése után eltelt idő percekben. Ha az esemény ezen időn belül érkezik, a távoli kiszolgáló kapcsolat élőnek minősül, így az elérhetőség nem lesz ellenőrizve. 0 kikapcsol. Alapértelmezetten 5. +thing-type.config.remoteopenhab.server.authenticateAnyway.label = Mindenképpen hitelesít +thing-type.config.remoteopenhab.server.authenticateAnyway.description = Bekapcsolt állapotban akkor is elküldi a hitelesítő információkat, ha a kapcsolat a távoli openHAB kiszolgálóval nem biztonságos (csak HTTP). Ez természetesen nem javasolt, leginkább interneten keresztül felépített kapcsolat esetén nem. Alapértelmezetten kikapcsolva. +thing-type.config.remoteopenhab.server.host.label = Kiszolgáló címe +thing-type.config.remoteopenhab.server.host.description = A távoli openHAB kiszolgáló neve vagy címe. +thing-type.config.remoteopenhab.server.password.label = Jelszó +thing-type.config.remoteopenhab.server.password.description = A távoli openHAB kiszolgáló kapcsolat jelszava, mely a REST API hozzáférést biztosítja. +thing-type.config.remoteopenhab.server.port.label = Kiszolgáló HTTP portja +thing-type.config.remoteopenhab.server.port.description = A HTTP port, melyen a távoli openHAB kiszolgáló elérhető. +thing-type.config.remoteopenhab.server.restartIfNoActivity.label = Újraindít, ha nincs aktivitás +thing-type.config.remoteopenhab.server.restartIfNoActivity.description = Kapcsold be, ha újra akarod indítani a kapcsolódást (SSE) a távoli kiszolgálóhoz, amennyiben nem érkezik esemény a megadott időtartamon belül. Nincs erre szükség, ha rövidebb hálózati kimaradásokat kell áthidalni (néhány másodperc). Hosszabb kimaradás esetén lehet hasznos. Ne kapcsold be, ha normál esetben a nem küld a távoli fél adatot a megadott időtartam alatt mert a gyakori újrakapcsolódás esemény kimaradásához vezet. Alapértelmezetten kikapcsolva. +thing-type.config.remoteopenhab.server.restPath.label = REST API útvonal +thing-type.config.remoteopenhab.server.restPath.description = A távoli openHAB kiszolgáló REST API elérési útvonala. +thing-type.config.remoteopenhab.server.token.label = Token +thing-type.config.remoteopenhab.server.token.description = A távoli openHAB kiszolgáló kapcsolat tokenje, mely a REST API hozzáférést biztosítja. +thing-type.config.remoteopenhab.server.trustedCertificate.label = Megbízható SSL tanúsítványok +thing-type.config.remoteopenhab.server.trustedCertificate.description = Ha a távoli kiszolgáló HTTPS kapcsolatot használ nem megbízható tanúsítvánnyal, ez az opció segíthet. +thing-type.config.remoteopenhab.server.useHttps.label = HTTPS használata +thing-type.config.remoteopenhab.server.useHttps.description = Kapcsold be, ha a távoli openHAB kiszolgálóhoz HTTPS-n keresztül akarsz kapcsolódni. Alapértelmezetten kikapcsolva. +thing-type.config.remoteopenhab.server.username.label = Felhasználónév +thing-type.config.remoteopenhab.server.username.description = A távoli openHAB kiszolgáló kapcsolat felhasználói neve, mely a REST API hozzáférést biztosítja. +thing-type.config.remoteopenhab.thing.buildTriggerChannels.label = Automatikus trigger csatornák felépítése +thing-type.config.remoteopenhab.thing.buildTriggerChannels.description = Bekapcsolt állapotban minden távoli trigger csatorna helyileg is létrejön és kapcsolódik a távoli csatornához. +thing-type.config.remoteopenhab.thing.thingUID.label = Távoli dolog azonosító +thing-type.config.remoteopenhab.thing.thingUID.description = A dolog azonosító a távoli openHAB kiszolgálón. + +# channel types + +channel-type.remoteopenhab.trigger.label = Trigger csatorna + +# channel type configuration + +channel-type.config.remoteopenhab.trigger.channelUID.label = Távoli csatorna azonosító +channel-type.config.remoteopenhab.trigger.channelUID.description = A csatorna azonosító a távoli openHAB kiszolgálón. + +# Thing status descriptions + +offline.config-error-undefined-host = Hiányzó kiszolgáló cím a dolog beállításokban +offline.config-error-invalid-rest-path = Érvénytelen REST API útvonal a dolog beállításokban +offline.config-error-invalid-rest-url = Érvénytelen REST URL jött létre a dolog beállításban megadottak alapján +offline.config-error-unsupported-server = Az 1.x verziójú OH kiszolgálók nem támogatottak a kötés által +offline.config-error-undefined-thing-uid = Hiányzó dolog azonosító a dolog beállításokban +offline.error-channels-creation = A távoli kiszolgáló elemei alapján a dinamikus csatornák létrehozása meghiúsult +offline.comm-error-disconnected = A távoli kiszolgálóval a kapcsolat megszakadt +offline.comm-error-receiving-events = Hiba az események fogadása alatt + +# Discovery result + +discovery.server.label = openHAB kiszolgáló + +# Exceptions + +exception.rest-client-not-setup = Helytelen a REST ügyfél beállítása +exception.json-response-empty = A JSON válasz üres +exception.root-rest-api-failed = A gyökér REST API hívás hibás +exception.get-list-items-api-failed = A távoli elemek lekérdezése a REST API hívás során meghiúsult +exception.get-item-state-api-failed = A távoli elem {0} állapotának lekérdezése a REST API hívás során meghiúsult +exception.send-item-command-api-failed = Parancs küldése a távoli elemhez {0} a REST API hívás során meghiúsult +exception.get-list-things-api-failed = A távoli dolgok listájának lekérdezése a REST API hívás során meghiúsult +exception.get-thing-api-failed = A távoli dolog {0} lekérdezése a REST API hívás során meghiúsult +exception.invalid-event-topic = Érvénytelen esemény téma {0} az esemény {1} típusához +exception.http-call-failed = HTTP hívás meghiúsult {0} + +# Other texts + +channel-type.label = Távoli elem {0} +channel-type.description = Egy távoli elem típusa {0}. + +channel.label = Elem {0} +channel.description = Távoli elem {0}. diff --git a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties index 557ef119aef0b..465768e799435 100644 --- a/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties +++ b/bundles/org.openhab.binding.sagercaster/src/main/resources/OH-INF/i18n/sagercaster_fr.properties @@ -44,7 +44,7 @@ beaufortLabel = Beaufort beaufortDescription = Force du vent mesurée sur l'échelle Beaufort pressureDescription = Pression barométrique au niveau de la mer. timestampChannelLabel = Horodatage -timestampChannelDescription = Horodatage de la dernire mise jour de la prvision mto. +timestampChannelDescription = Horodatage de la dernière mise à jour de la prévision météo. # channel options forecast0 = Patientez encore un peu pour une prédiction diff --git a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties index 673be0b2c2bec..9fbd0fd148892 100644 --- a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties +++ b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties @@ -19,7 +19,7 @@ thing-type.config.vigicrues.station.refresh.description = Fréquence de rafraich channel-type.vigicrues.alert-icon.label = Pictogramme channel-type.vigicrues.alert-icon.description = Pictogramme officiel associé au niveau d'alerte. -channel-type.vigicrues.alert-level.label = Niveau d'alerte +channel-type.vigicrues.alert-level.label = Alerte channel-type.vigicrues.alert-level.state.option.0 = Vert channel-type.vigicrues.alert-level.state.option.1 = Jaune channel-type.vigicrues.alert-level.state.option.2 = Orange @@ -28,17 +28,17 @@ channel-type.vigicrues.comment.label = Commentaire channel-type.vigicrues.comment.description = Commentaire détaillé. channel-type.vigicrues.flow.label = Débit channel-type.vigicrues.flow.description = Débit du cours d'eau. -channel-type.vigicrues.gauge.label = Mesure relative +channel-type.vigicrues.gauge.label = Mesure Relative channel-type.vigicrues.height.label = Hauteur channel-type.vigicrues.height.description = Niveau d'eau de la rivière -channel-type.vigicrues.observation-time.label = Heure d'observation +channel-type.vigicrues.observation-time.label = Heure Observation channel-type.vigicrues.observation-time.description = Date et heure de l’observation # channels -thing-type.vigicrues.station.channel.relative-flow.label = Débit relatif +thing-type.vigicrues.station.channel.relative-flow.label = Débit Relatif thing-type.vigicrues.station.channel.relative-flow.description = Débit relatif par rapport aux crues historiques. -thing-type.vigicrues.station.channel.relative-height.label = Hauteur relative +thing-type.vigicrues.station.channel.relative-height.label = Hauteur Relative thing-type.vigicrues.station.channel.relative-height.description = Hauteur relative par rapport aux crues historiques. thing-type.vigicrues.station.channel.short-comment.label = Description Courte thing-type.vigicrues.station.channel.short-comment.description = Brève description de la situation. diff --git a/bundles/org.openhab.binding.volvooncall/src/main/resources/OH-INF/i18n/volvooncall_fr.properties b/bundles/org.openhab.binding.volvooncall/src/main/resources/OH-INF/i18n/volvooncall_fr.properties index f8787f581a7e7..d3a0c0c054161 100644 --- a/bundles/org.openhab.binding.volvooncall/src/main/resources/OH-INF/i18n/volvooncall_fr.properties +++ b/bundles/org.openhab.binding.volvooncall/src/main/resources/OH-INF/i18n/volvooncall_fr.properties @@ -24,117 +24,117 @@ thing-type.config.volvooncall.vocapi.username.description = Votre nom d'utilisat # channel group types channel-group-type.volvooncall.battery.label = Informations sur le plugin Hybride / Twin Engine -channel-group-type.volvooncall.battery.channel.batteryDistanceToEmpty.label = Distance restante (Batterie) -channel-group-type.volvooncall.battery.channel.chargingEnd.label = Fin de charge +channel-group-type.volvooncall.battery.channel.batteryDistanceToEmpty.label = Distance Restante (Batterie) +channel-group-type.volvooncall.battery.channel.chargingEnd.label = Fin Charge channel-group-type.volvooncall.doors.label = État d'ouverture des portes -channel-group-type.volvooncall.doors.channel.frontLeft.label = Portière avant gauche -channel-group-type.volvooncall.doors.channel.frontRight.label = Portière avant droite +channel-group-type.volvooncall.doors.channel.frontLeft.label = Portière Avant Gauche +channel-group-type.volvooncall.doors.channel.frontRight.label = Portière Avant Droite channel-group-type.volvooncall.doors.channel.hood.label = Capot -channel-group-type.volvooncall.doors.channel.rearLeft.label = Portière arrière gauche -channel-group-type.volvooncall.doors.channel.rearRight.label = Portière arrière droite +channel-group-type.volvooncall.doors.channel.rearLeft.label = Portière Arrière Gauche +channel-group-type.volvooncall.doors.channel.rearRight.label = Portière Arrière Droite channel-group-type.volvooncall.doors.channel.tailgate.label = Hayon channel-group-type.volvooncall.lasttrip.label = Dernier trajet -channel-group-type.volvooncall.lasttrip.channel.endPosition.label = Allant vers +channel-group-type.volvooncall.lasttrip.channel.endPosition.label = Allant Vers channel-group-type.volvooncall.lasttrip.channel.endPosition.description = Emplacement d'arrivée de la voiture -channel-group-type.volvooncall.lasttrip.channel.startPosition.label = Venant de +channel-group-type.volvooncall.lasttrip.channel.startPosition.label = Venant De channel-group-type.volvooncall.lasttrip.channel.startPosition.description = Emplacement initial de la voiture -channel-group-type.volvooncall.lasttrip.channel.tripConsumption.label = Consommation du trajet +channel-group-type.volvooncall.lasttrip.channel.tripConsumption.label = Consommation Trajet channel-group-type.volvooncall.lasttrip.channel.tripConsumption.description = Indique la quantité de carburant consommée lors du trajet -channel-group-type.volvooncall.lasttrip.channel.tripDistance.label = Distance parcourue +channel-group-type.volvooncall.lasttrip.channel.tripDistance.label = Distance Parcourue channel-group-type.volvooncall.lasttrip.channel.tripDistance.description = Distance parcourue lors du trajet -channel-group-type.volvooncall.lasttrip.channel.tripEndTime.label = Heure d'arrivée +channel-group-type.volvooncall.lasttrip.channel.tripEndTime.label = Heure Arrivée channel-group-type.volvooncall.lasttrip.channel.tripEndTime.description = Heure de fin du trajet -channel-group-type.volvooncall.lasttrip.channel.tripStartOdometer.label = Kilométrage de départ -channel-group-type.volvooncall.lasttrip.channel.tripStartTime.label = Heure de départ +channel-group-type.volvooncall.lasttrip.channel.tripStartOdometer.label = Kilométrage Départ +channel-group-type.volvooncall.lasttrip.channel.tripStartTime.label = Heure Départ channel-group-type.volvooncall.lasttrip.channel.tripStartTime.description = Heure de début du trajet -channel-group-type.volvooncall.lasttrip.channel.tripStopOdometer.label = Kilométrage à l''''arrivée +channel-group-type.volvooncall.lasttrip.channel.tripStopOdometer.label = Kilométrage Arrivée channel-group-type.volvooncall.odometer.label = Compteurs kilométriques channel-group-type.volvooncall.odometer.channel.tripmeter1.label = Compteur 1 channel-group-type.volvooncall.odometer.channel.tripmeter2.label = Compteur 2 channel-group-type.volvooncall.other.label = Autres -channel-group-type.volvooncall.other.channel.brakeFluidLevel.label = Niveau de liquide de frein +channel-group-type.volvooncall.other.channel.brakeFluidLevel.label = Niveau Liquide Frein channel-group-type.volvooncall.other.channel.brakeFluidLevel.description = Quantité de liquide de frein disponible. -channel-group-type.volvooncall.other.channel.washerFluidLevel.label = Niveau de liquide lave-glace +channel-group-type.volvooncall.other.channel.washerFluidLevel.label = Niveau Liquide Lave-glace channel-group-type.volvooncall.other.channel.washerFluidLevel.description = Quantité de liquide lave-glace disponible. channel-group-type.volvooncall.position.label = Info de géolocalisation -channel-group-type.volvooncall.position.channel.location.label = Emplacement actuel +channel-group-type.volvooncall.position.channel.location.label = Emplacement Actuel channel-group-type.volvooncall.position.channel.location.description = Position du véhicule -channel-group-type.volvooncall.position.channel.locationTimestamp.label = Horodatage de l'emplacement +channel-group-type.volvooncall.position.channel.locationTimestamp.label = Horodatage Emplacement channel-group-type.volvooncall.position.channel.locationTimestamp.description = Horodatage de l'actualisation de l'emplacement channel-group-type.volvooncall.tank.label = Informations sur le réservoir -channel-group-type.volvooncall.tank.channel.distanceToEmpty.label = Distance restante +channel-group-type.volvooncall.tank.channel.distanceToEmpty.label = Distance Restante channel-group-type.volvooncall.tank.channel.distanceToEmpty.description = Distance restante avec la quantité de carburant disponible -channel-group-type.volvooncall.tank.channel.fuelAmount.label = Quantité de Carburant +channel-group-type.volvooncall.tank.channel.fuelAmount.label = Quantité Carburant channel-group-type.volvooncall.tank.channel.fuelAmount.description = Fournit la quantité de carburant disponible dans le réservoir channel-group-type.volvooncall.tyrePressure.label = Pression des pneus -channel-group-type.volvooncall.tyrePressure.channel.frontLeftTyre.label = Pneu avant gauche -channel-group-type.volvooncall.tyrePressure.channel.frontRightTyre.label = Pneu avant droit -channel-group-type.volvooncall.tyrePressure.channel.rearLeftTyre.label = Pneu arrière gauche -channel-group-type.volvooncall.tyrePressure.channel.rearRightTyre.label = Pneu arrière droit +channel-group-type.volvooncall.tyrePressure.channel.frontLeftTyre.label = Pneu Avant Gauche +channel-group-type.volvooncall.tyrePressure.channel.frontRightTyre.label = Pneu Avant Droit +channel-group-type.volvooncall.tyrePressure.channel.rearLeftTyre.label = Pneu Arrière Gauche +channel-group-type.volvooncall.tyrePressure.channel.rearRightTyre.label = Pneu Arrière Droit channel-group-type.volvooncall.windows.label = État d'ouverture des vitres -channel-group-type.volvooncall.windows.channel.frontLeftWnd.label = Vitre avant gauche -channel-group-type.volvooncall.windows.channel.frontRightWnd.label = Vitre avant droite -channel-group-type.volvooncall.windows.channel.rearLeftWnd.label = Vitre arrière gauche -channel-group-type.volvooncall.windows.channel.rearRightWnd.label = Vitre arrière droite +channel-group-type.volvooncall.windows.channel.frontLeftWnd.label = Vitre Avant Gauche +channel-group-type.volvooncall.windows.channel.frontRightWnd.label = Vitre Avant Droite +channel-group-type.volvooncall.windows.channel.rearLeftWnd.label = Vitre Arrière Gauche +channel-group-type.volvooncall.windows.channel.rearRightWnd.label = Vitre Arrière Droite # channel types -channel-type.volvooncall.averageSpeed.label = Vitesse moyenne +channel-type.volvooncall.averageSpeed.label = Vitesse Moyenne channel-type.volvooncall.averageSpeed.description = Vitesse moyenne du véhicule -channel-type.volvooncall.batteryLevel.label = Niveau de la batterie +channel-type.volvooncall.batteryLevel.label = Niveau Batterie channel-type.volvooncall.batteryLevel.description = Indique le niveau de puissance de la batterie, peut-être inconnu dans les cas où l'API est trompeuse (dans le cas de PHEV / Twin Engine) -channel-type.volvooncall.batteryLevelRaw.label = Niveau de la batterie (brut) +channel-type.volvooncall.batteryLevelRaw.label = Niveau Batterie (Brut) channel-type.volvooncall.batteryLevelRaw.description = Indique le niveau de puissance de la batterie fourni directement par l'API, peut être trompeuse (dans le cas de PHEV / Twin Engine) -channel-type.volvooncall.bulbFailure.label = Panne d'ampoule +channel-type.volvooncall.bulbFailure.label = Panne Ampoule channel-type.volvooncall.bulbFailure.description = Au moins une ampoule est morte -channel-type.volvooncall.calculatedLocation.label = Emplacement calculé +channel-type.volvooncall.calculatedLocation.label = Emplacement Calculé channel-type.volvooncall.calculatedLocation.description = Indique si l'emplacement est réel ou calculé -channel-type.volvooncall.carEvent.label = Événement voiture +channel-type.volvooncall.carEvent.label = Événement Voiture channel-type.volvooncall.carLocked.label = Verrouillé channel-type.volvooncall.carLocked.description = État du verrouillage -channel-type.volvooncall.chargeStatus.label = État de la charge +channel-type.volvooncall.chargeStatus.label = État Charge channel-type.volvooncall.chargeStatus.description = État de charge (en cas de PHEV / Twin Engine) channel-type.volvooncall.chargeStatusCable.label = Branché channel-type.volvooncall.chargeStatusCable.description = Indique si le câble de recharge est connecté -channel-type.volvooncall.chargeStatusCharging.label = En charge +channel-type.volvooncall.chargeStatusCharging.label = En Charge channel-type.volvooncall.chargeStatusCharging.description = Indique si la voiture est actuellement en charge -channel-type.volvooncall.chargeStatusFullyCharged.label = Charge complète +channel-type.volvooncall.chargeStatusFullyCharged.label = Charge Complète channel-type.volvooncall.chargeStatusFullyCharged.description = Indique si la voiture est entièrement chargée channel-type.volvooncall.door.label = Porte channel-type.volvooncall.door.description = Indique si la porte est ouverte -channel-type.volvooncall.engineRunning.label = Moteur démarré +channel-type.volvooncall.engineRunning.label = Moteur Démarré channel-type.volvooncall.engineRunning.description = État du moteur (actif ou non) -channel-type.volvooncall.engineStart.label = Démarrer le moteur +channel-type.volvooncall.engineStart.label = Démarrer Moteur channel-type.volvooncall.engineStart.description = Démarre le moteur du véhicule -channel-type.volvooncall.fluidLevel.label = Niveau de liquide +channel-type.volvooncall.fluidLevel.label = Niveau Liquide channel-type.volvooncall.fluidLevel.description = Quantité de liquide disponible. channel-type.volvooncall.fluidLevel.state.option.0 = Normal channel-type.volvooncall.fluidLevel.state.option.1 = Bas channel-type.volvooncall.fluidLevel.state.option.2 = Très bas -channel-type.volvooncall.fuelAlert.label = Alarme de carburant +channel-type.volvooncall.fuelAlert.label = Alarme Carburant channel-type.volvooncall.fuelAlert.description = Placé sur 'ON' lorsque le niveau du réservoir est faible -channel-type.volvooncall.fuelConsumption.label = Consommation moyenne +channel-type.volvooncall.fuelConsumption.label = Consommation Moyenne channel-type.volvooncall.fuelConsumption.description = Indique la consommation moyenne de carburant en l/100km -channel-type.volvooncall.fuelLevel.label = Niveau de carburant +channel-type.volvooncall.fuelLevel.label = Niveau Carburant channel-type.volvooncall.fuelLevel.description = Indique le niveau de carburant dans le réservoir -channel-type.volvooncall.fuelQuantity.label = Quantité de Carburant +channel-type.volvooncall.fuelQuantity.label = Quantité Carburant channel-type.volvooncall.heading.label = Direction channel-type.volvooncall.location.label = Emplacement -channel-type.volvooncall.odometer.label = Compteur kilométrique +channel-type.volvooncall.odometer.label = Compteur Kilométrique channel-type.volvooncall.odometer.description = Compteur kilométrique du véhicule channel-type.volvooncall.preclimatization.label = Préclimatisation channel-type.volvooncall.preclimatization.description = Démarre la pré-climatisation -channel-type.volvooncall.remoteHeater.label = Chauffage à distance +channel-type.volvooncall.remoteHeater.label = Chauffage à Distance channel-type.volvooncall.remoteHeater.description = (Dés)Active le chauffage à distance -channel-type.volvooncall.serviceWarningStatus.label = Avertissement de service +channel-type.volvooncall.serviceWarningStatus.label = Avertissement Service channel-type.volvooncall.serviceWarningStatus.description = Un entretien est-il nécessaire ? -channel-type.volvooncall.timeToHVBatteryFullyCharged.label = Temps de recharge restant +channel-type.volvooncall.timeToHVBatteryFullyCharged.label = Temps Recharge Restant channel-type.volvooncall.timeToHVBatteryFullyCharged.description = Temps en secondes jusqu'à ce que la batterie soit complètement chargée (en cas de PHEV / Twin Engine) channel-type.volvooncall.timestamp.label = Horodatage channel-type.volvooncall.timestamp.description = Horodatage des données channel-type.volvooncall.tripDuration.label = Durée channel-type.volvooncall.tripDuration.description = Durée du trajet -channel-type.volvooncall.tyrePressure.label = Pression des pneus +channel-type.volvooncall.tyrePressure.label = Pression Pneus channel-type.volvooncall.tyrePressure.state.option.0 = Normale channel-type.volvooncall.tyrePressure.state.option.1 = Dégonflé channel-type.volvooncall.window.label = Fenêtre diff --git a/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties new file mode 100644 index 0000000000000..0d239fbb647f9 --- /dev/null +++ b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties @@ -0,0 +1,64 @@ +# binding + +binding.xmltv.name = Extension XmlTV +binding.xmltv.description = Cette extension permet de lire et analyser les fichiers de programmes au format XmlTV + +# bridge types + +thing-type.xmltv.xmltvfile.label = Fichier XmlTV +thing-type.xmltv.xmltvfile.description = Interface vers un fichier XmlTV + +thing-type.config.xmltv.xmltvfile.filePath.label = Chemin du fichier XmlTV +thing-type.config.xmltv.xmltvfile.filePath.description = Chemin vers un fichier XmlTV. +thing-type.config.xmltv.xmltvfile.refresh.label = Intervalle d’actualisation +thing-type.config.xmltv.xmltvfile.refresh.description = Définit l'intervalle de rechargement du fichier XmlTV en heures. +thing-type.config.xmltv.xmltvfile.encoding.label = Encodage du fichier +thing-type.config.xmltv.xmltvfile.encoding.description = Définit le format d'encodage du fichier XmlTV. + +# thing types + +thing-type.xmltv.channel.label = Chaîne +thing-type.xmltv.channel.description = Ceci représente une chaîne pour un fichier TV donné + +thing-type.config.xmltv.channel.channelId.label = ID de la chaîne +thing-type.config.xmltv.channel.channelId.description = ID de la chaîne tel qu'il est présenté dans le fichier XmlTV. +thing-type.config.xmltv.channel.offset.label = Décalage +thing-type.config.xmltv.channel.offset.description = Anticipe ou retarde un événement ou une date/heure (en minutes) +thing-type.config.xmltv.channel.refresh.label = Intervalle d’actualisation +thing-type.config.xmltv.channel.refresh.description = Définit l'intervalle d'actualisation (en secondes). + +# channel group types + +channel-group-type.xmltv.channelprops.label = Propriétés de la chaîne +channel-group-type.xmltv.currentprog.label = Programme actuel +channel-group-type.xmltv.nextprog.label = Prochain programme + +# channel type + +channel-type.xmltv.iconUrl.label = URL Icône Chaîne +channel-type.xmltv.iconUrl.description = URL de l'icône de la chaîne TV. +channel-type.xmltv.progIconUrl.label = URL Programme +channel-type.xmltv.progIconUrl.description = URL vers une image du programme. +channel-type.xmltv.progTitle.label = Titre +channel-type.xmltv.progTitle.description = Nom du programme. +channel-type.xmltv.progCategory.label = Catégorie +channel-type.xmltv.progCategory.description = Catégorie du programme. +channel-type.xmltv.progStart.label = Heure Début +channel-type.xmltv.progStart.description = Heure de début du programme +channel-type.xmltv.progEnd.label = Heure Fin +channel-type.xmltv.progEnd.description = Heure de fin du programme +channel-type.xmltv.elapsedTime.label = Heure Actuelle +channel-type.xmltv.elapsedTime.description = Heure actuelle du programme en cours de lecture. +channel-type.xmltv.remainingTime.label = Temps Restant +channel-type.xmltv.remainingTime.description = Temps restant avant la fin du programme. +channel-type.xmltv.timeLeft.label = Temps restant +channel-type.xmltv.timeLeft.description = Temps restant avant le démarrage du programme +channel-type.xmltv.progress.label = Avancement +channel-type.xmltv.progress.description = Progression relative du programme actuel. +channel-type.xmltv.icon.label = Icône +channel-type.xmltv.icon.description = Icône de la chaîne / du programme. + +# messages +no-more-programs = Aucun programme à venir dans le fichier XmlTV actuel pour cette chaîne +no-file-available = Aucun fichier trouvé +file-outdated = Le fichier XmlTV semble obsolète diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties new file mode 100644 index 0000000000000..84388bfb80708 --- /dev/null +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties @@ -0,0 +1,14 @@ +# service + +service.io.openhabcloud.label = openHAB felhő + +# bundle config + +io.config.openhabcloud.baseURL.label = Alap webcím +io.config.openhabcloud.baseURL.description = Az openHAB felhő kiszolgáló alap címe. +io.config.openhabcloud.expose.label = Elemek közzététele +io.config.openhabcloud.expose.description = Azon elemek listája, melyek hozzáférhetők lesznek az IFTTT és egyéb szolgáltatások számára. +io.config.openhabcloud.mode.label = Mód +io.config.openhabcloud.mode.description = Az openHAB felhő használandó szolgáltatásainak listája. +io.config.openhabcloud.mode.option.notification = Értesítések +io.config.openhabcloud.mode.option.remote = Értesítések és távoli hozzáférés diff --git a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_de.properties b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_de.properties index 36004bcb06bd2..a56e2bf388737 100644 --- a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_de.properties +++ b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_de.properties @@ -1,6 +1,7 @@ # bundle config -profile.config.transform.function.label = Dateiname -profile.config.transform.function.description = Datei mit den Mapping-Informationen. -profile.config.transform.sourceFormat.label = State Format -profile.config.transform.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). +profile-type.transform.MAP.label = MAP +profile.config.transform.MAP.function.label = Dateiname +profile.config.transform.MAP.function.description = Datei mit den Mapping-Informationen. +profile.config.transform.MAP.sourceFormat.label = State Format +profile.config.transform.MAP.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). diff --git a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties index c0ae16aaa281d..17d8522d94182 100644 --- a/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties +++ b/bundles/org.openhab.transform.map/src/main/resources/OH-INF/i18n/transform_fr.properties @@ -1,6 +1,7 @@ # bundle config -profile.config.transform.function.label = Nom du fichier -profile.config.transform.function.description = Nom du fichier contenant les informations de mappage. -profile.config.transform.sourceFormat.label = Formatage de l'état -profile.config.transform.sourceFormat.description = Comment formater l'état du canal avant de le transformer, par exemple %s ou %.1f °C (par défaut %s) +profile-type.transform.MAP.label = MAP +profile.config.transform.MAP.function.label = Nom du fichier +profile.config.transform.MAP.function.description = Nom du fichier contenant les informations de mappage. +profile.config.transform.MAP.sourceFormat.label = Formatage de l'état +profile.config.transform.MAP.sourceFormat.description = Comment formater l'état du canal avant de le transformer, par exemple %s ou %.1f °C (par défaut %s). diff --git a/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_de.properties b/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_de.properties new file mode 100644 index 0000000000000..4a523d9aff4d8 --- /dev/null +++ b/bundles/org.openhab.voice.voicerss/src/main/resources/OH-INF/i18n/voicerss_de.properties @@ -0,0 +1,8 @@ +# service + +service.voice.voicerss.label = VoiceRSS Text-to-Speech + +# bundle config + +voice.config.voicerss.apiKey.label = API-Schlüssel +voice.config.voicerss.apiKey.description = API Schlüssel für den Zugriff auf die VoiceRSS API. From 084fb1fad766371ae00624b45685db720b47db6e Mon Sep 17 00:00:00 2001 From: Mark Hilbush Date: Sun, 5 Dec 2021 05:20:20 -0500 Subject: [PATCH 175/361] [sleepiq] Use constructor injection for ClientBuilder (#11700) Fixes #11696 Signed-off-by: Mark Hilbush Signed-off-by: Michael Schmidt --- .../openhab/binding/sleepiq/api/SleepIQ.java | 10 +- .../binding/sleepiq/api/impl/SleepIQImpl.java | 152 ++++++------------ .../binding/sleepiq/api/model/TimeSince.java | 76 +++------ .../internal/SleepIQHandlerFactory.java | 13 +- .../internal/handler/SleepIQCloudHandler.java | 11 +- 5 files changed, 101 insertions(+), 161 deletions(-) diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java index dcb01b80f7040..5785b24f791e9 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/SleepIQ.java @@ -17,6 +17,8 @@ import java.util.List; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.api.impl.SleepIQImpl; import org.openhab.binding.sleepiq.api.model.Bed; import org.openhab.binding.sleepiq.api.model.FamilyStatus; @@ -29,8 +31,7 @@ * * @author Gregory Moyer */ -public interface SleepIQ -{ +public interface SleepIQ { /** * Login to the {@link Configuration configured} account. This method is not * required to be called before other methods because all methods must @@ -94,8 +95,7 @@ public interface SleepIQ * the configuration to use for the new instance * @return a concrete implementation of this interface */ - public static SleepIQ create(Configuration config) - { - return new SleepIQImpl(config); + public static SleepIQ create(Configuration config, ClientBuilder clientBuilder) { + return new SleepIQImpl(config, clientBuilder); } } diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java index 666eb93388d92..df1b85a387bd7 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/impl/SleepIQImpl.java @@ -49,8 +49,7 @@ import org.openhab.binding.sleepiq.api.model.SleepersResponse; import org.openhab.binding.sleepiq.internal.GsonProvider; -public class SleepIQImpl extends AbstractClient implements SleepIQ -{ +public class SleepIQImpl extends AbstractClient implements SleepIQ { protected static final String PARAM_KEY = "_k"; protected static final String DATA_BED_ID = "bedId"; @@ -59,47 +58,36 @@ public class SleepIQImpl extends AbstractClient implements SleepIQ private volatile LoginInfo loginInfo; - public SleepIQImpl(Configuration config) - { + private final ClientBuilder clientBuilder; + + public SleepIQImpl(Configuration config, ClientBuilder clientBuilder) { this.config = config; + this.clientBuilder = clientBuilder; } @Override - public LoginInfo login() throws LoginException - { - if (loginInfo == null) - { - synchronized (this) - { - if (loginInfo == null) - { - Response response = getClient().target(config.getBaseUri()) - .path(Endpoints.login()) - .request(MediaType.APPLICATION_JSON_TYPE) - .put(Entity.json(new LoginRequest().withLogin(config.getUsername()) - .withPassword(config.getPassword()))); - - if (isUnauthorized(response)) - { + public LoginInfo login() throws LoginException { + if (loginInfo == null) { + synchronized (this) { + if (loginInfo == null) { + Response response = getClient().target(config.getBaseUri()).path(Endpoints.login()) + .request(MediaType.APPLICATION_JSON_TYPE).put(Entity.json(new LoginRequest() + .withLogin(config.getUsername()).withPassword(config.getPassword()))); + + if (isUnauthorized(response)) { throw new UnauthorizedException(response.readEntity(Failure.class)); } - if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) - { + if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) { throw new LoginException(response.readEntity(Failure.class)); } // add the received cookies to all future requests - getClient().register(new ClientRequestFilter() - { + getClient().register(new ClientRequestFilter() { @Override - public void filter(ClientRequestContext requestContext) throws IOException - { - List cookies = response.getCookies() - .values() - .stream() - .map(newCookie -> newCookie.toCookie()) - .collect(Collectors.toList()); + public void filter(ClientRequestContext requestContext) throws IOException { + List cookies = response.getCookies().values().stream() + .map(newCookie -> newCookie.toCookie()).collect(Collectors.toList()); requestContext.getHeaders().put("Cookie", cookies); } }); @@ -113,106 +101,76 @@ public void filter(ClientRequestContext requestContext) throws IOException } @Override - public List getBeds() - { + public List getBeds() { return getSessionResponse(this::getBedsResponse).readEntity(BedsResponse.class).getBeds(); } - protected Response getBedsResponse(Map data) throws LoginException - { + protected Response getBedsResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public List getSleepers() - { - return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class) - .getSleepers(); + public List getSleepers() { + return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class).getSleepers(); } - protected Response getSleepersResponse(Map data) throws LoginException - { + protected Response getSleepersResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.sleeper()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.sleeper()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public FamilyStatus getFamilyStatus() - { + public FamilyStatus getFamilyStatus() { return getSessionResponse(this::getFamilyStatusResponse).readEntity(FamilyStatus.class); } - protected Response getFamilyStatusResponse(Map data) throws LoginException - { + protected Response getFamilyStatusResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .path(Endpoints.familyStatus()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(Endpoints.familyStatus()) + .queryParam(PARAM_KEY, login.getKey()).request(MediaType.APPLICATION_JSON_TYPE).get(); } @Override - public PauseMode getPauseMode(String bedId) throws BedNotFoundException - { + public PauseMode getPauseMode(String bedId) throws BedNotFoundException { Map data = new HashMap<>(); data.put(DATA_BED_ID, bedId); Response response = getSessionResponse(this::getPauseModeResponse, data); - if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) - { + if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) { throw new BedNotFoundException(response.readEntity(Failure.class)); } return response.readEntity(PauseMode.class); } - protected Response getPauseModeResponse(Map data) throws LoginException - { + protected Response getPauseModeResponse(Map data) throws LoginException { LoginInfo login = login(); - return getClient().target(config.getBaseUri()) - .path(Endpoints.bed()) - .path(data.get(DATA_BED_ID).toString()) - .path(Endpoints.pauseMode()) - .queryParam(PARAM_KEY, login.getKey()) - .request(MediaType.APPLICATION_JSON_TYPE) - .get(); + return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(data.get(DATA_BED_ID).toString()) + .path(Endpoints.pauseMode()).queryParam(PARAM_KEY, login.getKey()) + .request(MediaType.APPLICATION_JSON_TYPE).get(); } - protected boolean isUnauthorized(Response response) - { + protected boolean isUnauthorized(Response response) { return Status.UNAUTHORIZED.getStatusCode() == response.getStatusInfo().getStatusCode(); } - protected synchronized void resetLogin() - { + protected synchronized void resetLogin() { loginInfo = null; } - protected Response getSessionResponse(Request request) - { + protected Response getSessionResponse(Request request) { return getSessionResponse(request, Collections.emptyMap()); } - protected Response getSessionResponse(Request request, Map data) - { - try - { + protected Response getSessionResponse(Request request, Map data) { + try { Response response = request.execute(data); - if (isUnauthorized(response)) - { + if (isUnauthorized(response)) { // session timed out response.close(); resetLogin(); @@ -220,35 +178,27 @@ protected Response getSessionResponse(Request request, Map data) } return response; - } - catch (LoginException e) - { + } catch (LoginException e) { throw new RuntimeException(e.getMessage(), e); } } @Override - protected Client createClient() - { - ClientBuilder builder = ClientBuilder.newBuilder(); - + protected Client createClient() { // setup Gson (de)serialization GsonProvider gsonProvider = new GsonProvider<>(getGson()); - builder.register(gsonProvider); + clientBuilder.register(gsonProvider); // turn on logging if requested - if (config.isLogging()) - { - builder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()), - true)); + if (config.isLogging()) { + clientBuilder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()), true)); } - return builder.build(); + return clientBuilder.build(); } @FunctionalInterface - public static interface Request - { + public static interface Request { public Response execute(Map data) throws LoginException; } } diff --git a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java index 674e2ef7449d9..c6c8704861863 100644 --- a/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java +++ b/bundles/org.openhab.binding.sleepiq/src/3rdparty/java/org/openhab/binding/sleepiq/api/model/TimeSince.java @@ -16,46 +16,37 @@ package org.openhab.binding.sleepiq.api.model; import java.time.Duration; -import java.time.format.DateTimeParseException; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class TimeSince -{ +public class TimeSince { private static final Pattern PATTERN = Pattern.compile("(([0-9]+) d )?([0-9]{2}):([0-9]{2}):([0-9]{2})", - Pattern.CASE_INSENSITIVE); + Pattern.CASE_INSENSITIVE); private Duration duration; - public Duration getDuration() - { + public Duration getDuration() { return duration; } - public void setDuration(Duration duration) - { + public void setDuration(Duration duration) { this.duration = duration == null ? null : duration.abs(); } - public TimeSince withDuration(long days, long hours, long minutes, long seconds) - { - return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) - + TimeUnit.HOURS.toSeconds(hours) - + TimeUnit.MINUTES.toSeconds(minutes) - + seconds)); + public TimeSince withDuration(long days, long hours, long minutes, long seconds) { + return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) + TimeUnit.HOURS.toSeconds(hours) + + TimeUnit.MINUTES.toSeconds(minutes) + seconds)); } - public TimeSince withDuration(Duration duration) - { + public TimeSince withDuration(Duration duration) { setDuration(duration); return this; } @Override - public int hashCode() - { + public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((duration == null) ? 0 : duration.hashCode()); @@ -63,38 +54,29 @@ public int hashCode() } @Override - public boolean equals(Object obj) - { - if (this == obj) - { + public boolean equals(Object obj) { + if (this == obj) { return true; } - if (obj == null) - { + if (obj == null) { return false; } - if (!(obj instanceof TimeSince)) - { + if (!(obj instanceof TimeSince)) { return false; } - TimeSince other = (TimeSince)obj; - if (duration == null) - { - if (other.duration != null) - { + TimeSince other = (TimeSince) obj; + if (duration == null) { + if (other.duration != null) { return false; } - } - else if (!duration.equals(other.duration)) - { + } else if (!duration.equals(other.duration)) { return false; } return true; } @Override - public String toString() - { + public String toString() { long totalDays = duration.toDays(); long totalHours = duration.toHours(); long totalMinutes = duration.toMinutes(); @@ -104,22 +86,19 @@ public String toString() long minutes = totalMinutes - TimeUnit.HOURS.toMinutes(totalHours); long seconds = totalSeconds - TimeUnit.MINUTES.toSeconds(totalMinutes); - if (totalDays > 0) - { + if (totalDays > 0) { return String.format("%d d %02d:%02d:%02d", totalDays, hours, minutes, seconds); } return String.format("%02d:%02d:%02d", hours, minutes, seconds); } - public static TimeSince parse(CharSequence text) - { + public static TimeSince parse(CharSequence text) { Objects.requireNonNull(text, "text"); Matcher matcher = PATTERN.matcher(text); - if (!matcher.matches()) - { - throw new DateTimeParseException("Text cannot be parsed", text, 0); + if (!matcher.matches()) { + return new TimeSince().withDuration(Duration.ZERO); } String dayMatch = matcher.group(2); @@ -128,17 +107,10 @@ public static TimeSince parse(CharSequence text) String secondMatch = matcher.group(5); StringBuilder sb = new StringBuilder("P"); - if (dayMatch != null) - { + if (dayMatch != null) { sb.append(dayMatch).append('D'); } - sb.append('T') - .append(hourMatch) - .append('H') - .append(minuteMatch) - .append('M') - .append(secondMatch) - .append('S'); + sb.append('T').append(hourMatch).append('H').append(minuteMatch).append('M').append(secondMatch).append('S'); return new TimeSince().withDuration(Duration.parse(sb.toString())); } diff --git a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java index 67ff44666fa7c..6717c178e63ca 100644 --- a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java +++ b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/SleepIQHandlerFactory.java @@ -20,6 +20,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.internal.discovery.SleepIQBedDiscoveryService; import org.openhab.binding.sleepiq.internal.handler.SleepIQCloudHandler; import org.openhab.binding.sleepiq.internal.handler.SleepIQDualBedHandler; @@ -32,7 +34,9 @@ import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,8 +53,15 @@ public class SleepIQHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(SleepIQHandlerFactory.class); + private final ClientBuilder clientBuilder; + private final Map> discoveryServiceReg = new HashMap<>(); + @Activate + public SleepIQHandlerFactory(@Reference ClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + @Override public boolean supportsThingType(final ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID); @@ -62,7 +73,7 @@ protected ThingHandler createHandler(final Thing thing) { if (SleepIQCloudHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) { logger.debug("Creating SleepIQ cloud thing handler"); - SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing); + SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing, clientBuilder); registerBedDiscoveryService(cloudHandler); return cloudHandler; } else if (SleepIQDualBedHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) { diff --git a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java index 1b8a4bf558098..1fcc2fb3650ab 100644 --- a/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java +++ b/bundles/org.openhab.binding.sleepiq/src/main/java/org/openhab/binding/sleepiq/internal/handler/SleepIQCloudHandler.java @@ -25,6 +25,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import javax.ws.rs.client.ClientBuilder; + import org.openhab.binding.sleepiq.api.Configuration; import org.openhab.binding.sleepiq.api.LoginException; import org.openhab.binding.sleepiq.api.SleepIQ; @@ -67,8 +69,11 @@ public class SleepIQCloudHandler extends ConfigStatusBridgeHandler { private SleepIQ cloud; - public SleepIQCloudHandler(final Bridge bridge) { + private ClientBuilder clientBuilder; + + public SleepIQCloudHandler(final Bridge bridge, ClientBuilder clientBuilder) { super(bridge); + this.clientBuilder = clientBuilder; } @Override @@ -100,6 +105,8 @@ public void initialize() { /** * Create a new SleepIQ cloud service connection. If a connection already exists, it will be lost. * + * @param clientBuilder2 + * * @throws LoginException if there is an error while authenticating to the service */ private void createCloudConnection() throws LoginException { @@ -109,7 +116,7 @@ private void createCloudConnection() throws LoginException { logger.debug("Creating SleepIQ client"); Configuration cloudConfig = new Configuration().withUsername(bindingConfig.username) .withPassword(bindingConfig.password).withLogging(logger.isDebugEnabled()); - cloud = SleepIQ.create(cloudConfig); + cloud = SleepIQ.create(cloudConfig, clientBuilder); logger.debug("Authenticating at the SleepIQ cloud service"); cloud.login(); From 0a1cd1e428d15ca4b948f6ee0660c4391cbaea54 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 5 Dec 2021 11:23:40 +0100 Subject: [PATCH 176/361] [miio] Add support for new dreame vacuum models (p2027,p2028,p2059) (#11669) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 324 +++- .../binding/miio/internal/MiIoDevices.java | 3 + .../miio/internal/miot/MiotParser.java | 3 +- .../database/dreame.vacuum.p2027-miot.json | 1373 +++++++++++++++++ .../database/dreame.vacuum.p2028-miot.json | 1316 ++++++++++++++++ .../database/dreame.vacuum.p2156o-miot.json | 1 - .../database/dreame.vacuum.p2259-miot.json | 1257 +++++++++++++++ 7 files changed, 4272 insertions(+), 5 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2027-miot.json create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2028-miot.json create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2259-miot.json diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index d7f875f9ed390..eb420223503a0 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -176,7 +176,7 @@ This will change the communication method and the Mi IO binding can communicate # Mi IO Devices -Currently the miio binding supports more than 300 different models. +Currently the miio binding supports more than 310 different models. | Device | ThingType | Device Model | Supported | Remark | |------------------------------|------------------|------------------------|-----------|------------| @@ -221,10 +221,13 @@ Currently the miio binding supports more than 300 different models. | Mi Robot Vacuum Mop 1C STYTJ01ZHM | miio:basic | [dreame.vacuum.mc1808](#dreame-vacuum-mc1808) | Yes | Identified manual actions for execution
`action{"did":"battery-start-charge","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-start-sweep","siid":3,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":3,"aiid":2,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":26,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":27,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":28,"aiid":1,"in":[]}`
`action{"did":"clean-start-clean","siid":18,"aiid":1,"in":[]}`
`action{"did":"clean-stop-clean","siid":18,"aiid":2,"in":[]}`
`action{"did":"remote-start-remote","siid":21,"aiid":1,"in":[1.0, 2.0]}`
`action{"did":"remote-stop-remote","siid":21,"aiid":2,"in":[]}`
`action{"did":"remote-exit-remote","siid":21,"aiid":3,"in":[]}`
`action{"did":"map-map-req","siid":23,"aiid":1,"in":[2.0]}`
`action{"did":"audio-position","siid":24,"aiid":1,"in":[]}`
`action{"did":"audio-set-voice","siid":24,"aiid":2,"in":[]}`
`action{"did":"audio-play-sound","siid":24,"aiid":3,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel. | | Dreame Robot Vacuum-Mop F9 | miio:basic | [dreame.vacuum.p2008](#dreame-vacuum-p2008) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Dreame Robot Vacuum D9 | miio:basic | [dreame.vacuum.p2009](#dreame-vacuum-p2009) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| +| Dreame Bot W10 | miio:basic | [dreame.vacuum.p2027](#dreame-vacuum-p2027) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Dreame Bot Z10 Pro | miio:basic | [dreame.vacuum.p2028](#dreame-vacuum-p2028) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Trouver Robot LDS Vacuum-Mop Finder | miio:basic | [dreame.vacuum.p2036](#dreame-vacuum-p2036) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| -| Mi Robot Vacuum-Mop 2 Pro+ | miio:basic | [dreame.vacuum.p2041o](#dreame-vacuum-p2041o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| MOVA Z500 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2156o](#dreame-vacuum-p2156o) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Robot Vacuum-Mop 2 Pro+ | miio:basic | [dreame.vacuum.p2041o](#dreame-vacuum-p2041o) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| MOVA Z500 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2156o](#dreame-vacuum-p2156o) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MOVA L600 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2157](#dreame-vacuum-p2157) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| +| Dreame Bot D9 Max | miio:basic | [dreame.vacuum.p2259](#dreame-vacuum-p2259) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO ARIES For Bedroom | miio:basic | [huayi.light.ari013](#huayi-light-ari013) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO ARIES For Living Room | miio:basic | [huayi.light.aries](#huayi-light-aries) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO Fan Light | miio:basic | [huayi.light.fanwy](#huayi-light-fanwy) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -1111,6 +1114,111 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | total-clean-times | Number | Clean Logs - Total Clean Times | | | total-clean-area | Number | Clean Logs - Total Clean Area | | +### Dreame Bot W10 (dreame.vacuum.p2027) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| actions | String | Actions | Value mapping `["vacuum-start-sweep"="Vacuum Start Sweep","vacuum-stop-sweeping"="Vacuum Stop Sweeping","vacuum-start-room-sweep"="Vacuum Start Room Sweep","battery-start-charge"="Battery Start Charge","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","filter-reset-filter-life"="Filter Reset Filter Life","vacuum-extend-start-clean"="Vacuum Extend Start Clean","vacuum-extend-stop-clean"="Vacuum Extend Stop Clean","map-map-req"="Map Map Req","map-update-map"="Map Update Map","audio-position"="Audio Position","audio-play-sound"="Audio Play Sound","time-delete-timer"="Time Delete Timer"]` | +| status | Number | Robot Cleaner - Status | Value mapping `["1"="Sweeping","2"="Idle","3"="Paused","4"="Error","5"="Go Charging","6"="Charging","7"="Mopping","8"="Drying","9"="Washing","10"="Go Washing","11"="Building","12"="Sweeping and Mopping","13"="Charging Completed"]` | +| fault | Number | Robot Cleaner - Device Fault | Value mapping `["0"="No Error","1"="Drop","2"="Cliff","3"="Bumper","4"="Gesture","5"="Bumper Repeat","6"="Drop Repeat","7"="Optical Flow","8"="No Box","9"="No Tankbox","10"="Waterbox Empty","11"="Box full","12"="Brush","13"="Side Brush","14"="Fan","15"="Left Wheel motor","16"="Right Wheel motor","17"="Turn suffocate","18"="Forward suffocate","19"="Charger get","20"="Battery low","21"="Charge fault","22"="Battery percentage","23"="Heart","24"="Camera occlusion","25"="Camera fault","26"="Event battery","27"="Forward looking","28"="Gyroscope"]` | +| mode | Number | Robot Cleaner - Mode | Value mapping `["0"="Silent","1"="Basic","2"="Strong","3"="Full Speed"]` | +| battery_level | Number:Dimensionless | Battery - Battery Level | | +| charging_state | Number | Battery - Charging State | Value mapping `["1"="Charging","2"="Not Charging","5"="Go Charging"]` | +| brush_left_time | Number:Time | Main Cleaning Brush - Brush Left Time | | +| brush_life_level | Number:Dimensionless | Main Cleaning Brush - Brush Life Level | | +| brush_left_time1 | Number:Time | Side Cleaning Brush - Brush Left Time | | +| brush_life_level1 | Number:Dimensionless | Side Cleaning Brush - Brush Life Level | | +| filter_life_level | Number:Dimensionless | Filter - Filter Life Level | | +| filter_left_time | Number:Time | Filter - Filter Left Time | | +| work_mode | Number | Vacuum Extend - Work Mode | | +| cleaning_time | Number:Time | Vacuum Extend - Cleaning Time | | +| cleaning-area | Number:Area | Vacuum Extend - Cleaning Area | | +| cleaning_mode | Number | Vacuum Extend - Cleaning Mode | Value mapping `["0"="mode 0","1"="mode 1","2"="mode 2","3"="mode 3"]` | +| mop_mode | Number | Vacuum Extend - Mop Mode | Value mapping `["1"="low water","2"="medium water","3"="high water"]` | +| waterbox_status | Number | Vacuum Extend - Waterbox Status | Value mapping `["0"="Status 0","1"="Status 1"]` | +| task_status | Number | Vacuum Extend - Task Status | Value mapping `["0"="Notask","1"="AutoClean","2"="CustomClean","3"="SelectAreanClean","4"="SpotArea"]` | +| clean_extend_data | String | Vacuum Extend - Clean Extend Data | | +| break_point_restart | Number | Vacuum Extend - Break Point Restart | Value mapping `["0"="Off","1"="On"]` | +| carpet_press | Number | Vacuum Extend - Carpet Press | Value mapping `["0"="Off","1"="On"]` | +| remote_state | String | Vacuum Extend - Remote State | | +| clean_rags_tip | Number:Time | Vacuum Extend - Clean Rags Tip | | +| keep_sweeper_time | Number:Time | Vacuum Extend - Keep Sweeper Time | | +| faults | String | Vacuum Extend - Faults | | +| nation_matched | String | Vacuum Extend - Nation Matched | | +| relocation_status | Number | Vacuum Extend - Relocation Status | | +| mop_status | Number | Vacuum Extend - Mop Status | | +| child_lock | Number | Vacuum Extend - Child Lock | Value mapping `["0"="Close","1"="Open"]` | +| clean_cancel | Number | Vacuum Extend - Clean Cancel | | +| enable | Switch | Do Not Disturb - Enable | | +| start_time | String | Do Not Disturb - Start Time | | +| end_time | String | Do Not Disturb - End Time | | +| frame_info | String | Map - Frame Info | | +| map_extend_data | String | Map - Map Extend Data | | +| mult_map_state | Number | Map - Mult Map State | Value mapping `["0"="Close","1"="Open"]` | +| mult_map_info | String | Map - Mult Map Info | | +| volume | Number:Dimensionless | Audio - Volume | | +| voice_packet_id | String | Audio - Voice Packet Id | | +| voice_change_state | String | Audio - Voice Change State | | +| set_voice | String | Audio - Set Voice | | +| time_zone | String | Time - Time Zone | | +| timer_clean | String | Time - Timer Clean | | +| first_clean_time | Number | Clean Logs - First Clean Time | | +| total_clean_time | Number:Time | Clean Logs - Total Clean Time | | +| total_clean_times | Number | Clean Logs - Total Clean Times | | +| total_clean_area | Number | Clean Logs - Total Clean Area | | + +### Dreame Bot Z10 Pro (dreame.vacuum.p2028) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| actions | String | Actions | Value mapping `["vacuum-start-sweep"="Vacuum Start Sweep","vacuum-stop-sweeping"="Vacuum Stop Sweeping","battery-start-charge"="Battery Start Charge","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","filter-reset-filter-life"="Filter Reset Filter Life","vacuum-extend-start-clean"="Vacuum Extend Start Clean","vacuum-extend-stop-clean"="Vacuum Extend Stop Clean","map-map-req"="Map Map Req","map-update-map"="Map Update Map","audio-position"="Audio Position","audio-play-sound"="Audio Play Sound","time-delete-timer"="Time Delete Timer","collect-dust-start-collect"="Collect Dust Start Collect"]` | +| status | Number | Robot Cleaner - Status | Value mapping `["1"="Sweeping","2"="Idle","3"="Paused","4"="Error","5"="Go Charging","6"="Charging","7"="Mopping"]` | +| fault | Number | Robot Cleaner - Device Fault | Value mapping `["0"="No Error","1"="Drop","2"="Cliff","3"="Bumper","4"="Gesture","5"="Bumper Repeat","6"="Drop Repeat","7"="Optical Flow","8"="No Box","9"="No Tankbox","10"="Waterbox Empty","11"="Box full","12"="Brush","13"="Side Brush","14"="Fan","15"="Left Wheel motor","16"="Right Wheel motor","17"="Turn suffocate","18"="Forward suffocate","19"="Charger get","20"="Battery low","21"="Charge fault","22"="Battery percentage","23"="Heart","24"="Camera occlusion","25"="Camera fault","26"="Event battery","27"="Forward looking","28"="Gyroscope"]` | +| battery_level | Number:Dimensionless | Battery - Battery Level | | +| charging_state | Number | Battery - Charging State | Value mapping `["1"="Charging","2"="Not Charging","5"="Go Charging"]` | +| brush_left_time | Number:Time | Main Cleaning Brush - Brush Left Time | | +| brush_life_level | Number:Dimensionless | Main Cleaning Brush - Brush Life Level | | +| brush_left_time1 | Number:Time | Side Cleaning Brush - Brush Left Time | | +| brush_life_level1 | Number:Dimensionless | Side Cleaning Brush - Brush Life Level | | +| filter_life_level | Number:Dimensionless | Filter - Filter Life Level | | +| filter_left_time | Number:Time | Filter - Filter Left Time | | +| work_mode | Number | Vacuum Extend - Work Mode | | +| cleaning_time | Number:Time | Vacuum Extend - Cleaning Time | | +| cleaning-area | Number:Area | Vacuum Extend - Cleaning Area | | +| cleaning_mode | Number | Vacuum Extend - Cleaning Mode | Value mapping `["0"="mode 0","1"="mode 1","2"="mode 2","3"="mode 3"]` | +| mop_mode | Number | Vacuum Extend - Mop Mode | Value mapping `["1"="low water","2"="medium water","3"="high water"]` | +| waterbox_status | Number | Vacuum Extend - Waterbox Status | Value mapping `["0"="Status 0","1"="Status 1"]` | +| task_status | Number | Vacuum Extend - Task Status | Value mapping `["0"="Notask","1"="AutoClean","2"="CustomClean","3"="SelectAreanClean","4"="SpotArea"]` | +| clean_extend_data | String | Vacuum Extend - Clean Extend Data | | +| break_point_restart | Number | Vacuum Extend - Break Point Restart | Value mapping `["0"="Off","1"="On"]` | +| carpet_press | Number | Vacuum Extend - Carpet Press | Value mapping `["0"="Off","1"="On"]` | +| remote_state | String | Vacuum Extend - Remote State | | +| clean_rags_tip | Number:Time | Vacuum Extend - Clean Rags Tip | | +| keep_sweeper_time | Number:Time | Vacuum Extend - Keep Sweeper Time | | +| faults | String | Vacuum Extend - Faults | | +| nation_matched | String | Vacuum Extend - Nation Matched | | +| relocation_status | Number | Vacuum Extend - Relocation Status | | +| enable | Switch | Do Not Disturb - Enable | | +| start_time | String | Do Not Disturb - Start Time | | +| end_time | String | Do Not Disturb - End Time | | +| frame_info | String | Map - Frame Info | | +| map_extend_data | String | Map - Map Extend Data | | +| mult_map_state | Number | Map - Mult Map State | Value mapping `["0"="Close","1"="Open"]` | +| mult_map_info | String | Map - Mult Map Info | | +| volume | Number:Dimensionless | Audio - Volume | | +| voice_packet_id | String | Audio - Voice Packet Id | | +| voice_change_state | String | Audio - Voice Change State | | +| set_voice | String | Audio - Set Voice | | +| time_zone | String | Time - Time Zone | | +| timer_clean | String | Time - Timer Clean | | +| first_clean_time | Number | Clean Logs - First Clean Time | | +| total_clean_time | Number:Time | Clean Logs - Total Clean Time | | +| total_clean_times | Number | Clean Logs - Total Clean Times | | +| total_clean_area | Number | Clean Logs - Total Clean Area | | +| auto_collect | Number | Collect Dust - Auto Collect | Value mapping `["0"="Close-auto-collect","1"="Open-auto-collect"]` | +| clean_times | Number | Collect Dust - Clean Times | | +| dust_enable | Number | Collect Dust - Dust Enable | Value mapping `["0"="Disable","1"="Enable"]` | + ### Trouver Robot LDS Vacuum-Mop Finder (dreame.vacuum.p2036) Channels | Channel | Type | Description | Comment | @@ -1279,6 +1387,54 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | total-clean-times | Number | Clean Logs - Total Clean Times | | | total-clean-area | Number | Clean Logs - Total Clean Area | | +### Dreame Bot D9 Max (dreame.vacuum.p2259) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| actions | String | Actions | Value mapping `["vacuum-start-sweep"="Vacuum Start Sweep","vacuum-stop-sweeping"="Vacuum Stop Sweeping","vacuum-start-room-sweep"="Vacuum Start Room Sweep","battery-start-charge"="Battery Start Charge","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","filter-reset-filter-life"="Filter Reset Filter Life","vacuum-extend-start-clean"="Vacuum Extend Start Clean","vacuum-extend-stop-clean"="Vacuum Extend Stop Clean","map-map-req"="Map Map Req","map-update-map"="Map Update Map","audio-position"="Audio Position","audio-play-sound"="Audio Play Sound","time-delete-timer"="Time Delete Timer"]` | +| status | Number | Robot Cleaner - Status | Value mapping `["1"="Sweeping","2"="Idle","3"="Paused","4"="Error","5"="Go Charging","6"="Charging","7"="Mopping"]` | +| fault | Number | Robot Cleaner - Device Fault | Value mapping `["0"="No Error","1"="Drop","2"="Cliff","3"="Bumper","4"="Gesture","5"="Bumper Repeat","6"="Drop Repeat","7"="Optical Flow","8"="No Box","9"="No Tankbox","10"="Waterbox Empty","11"="Box full","12"="Brush","13"="Side Brush","14"="Fan","15"="Left Wheel motor","16"="Right Wheel motor","17"="Turn suffocate","18"="Forward suffocate","19"="Charger get","20"="Battery low","21"="Charge fault","22"="Battery percentage","23"="Heart","24"="Camera occlusion","25"="Camera fault","26"="Event battery","27"="Forward looking","28"="Gyroscope"]` | +| mode | Number | Robot Cleaner - Mode | Value mapping `["0"="Silent","1"="Basic","2"="Strong","3"="Full Speed"]` | +| battery_level | Number:Dimensionless | Battery - Battery Level | | +| charging_state | Number | Battery - Charging State | Value mapping `["1"="Charging","2"="Not Charging","5"="Go Charging"]` | +| brush_left_time | Number:Time | Main Cleaning Brush - Brush Left Time | | +| brush_life_level | Number:Dimensionless | Main Cleaning Brush - Brush Life Level | | +| brush_left_time1 | Number:Time | Side Cleaning Brush - Brush Left Time | | +| brush_life_level1 | Number:Dimensionless | Side Cleaning Brush - Brush Life Level | | +| filter_life_level | Number:Dimensionless | Filter - Filter Life Level | | +| filter_left_time | Number:Time | Filter - Filter Left Time | | +| work_mode | Number | Vacuum Extend - Work Mode | | +| cleaning_time | Number:Time | Vacuum Extend - Cleaning Time | | +| cleaning_area | Number:Area | Vacuum Extend - Cleaning Area | | +| cleaning_mode | Number | Vacuum Extend - Cleaning Mode | Value mapping `["0"="mode 0","1"="mode 1","2"="mode 2","3"="mode 3"]` | +| mop_mode | Number | Vacuum Extend - Mop Mode | Value mapping `["1"="low water","2"="medium water","3"="high water"]` | +| waterbox_status | Number | Vacuum Extend - Waterbox Status | Value mapping `["0"="Status 0","1"="Status 1"]` | +| task_status | Number | Vacuum Extend - Task Status | Value mapping `["0"="Notask","1"="AutoClean","2"="CustomClean","3"="SelectAreanClean","4"="SpotArea"]` | +| clean_extend_data | String | Vacuum Extend - Clean Extend Data | | +| break_point_restart | Number | Vacuum Extend - Break Point Restart | Value mapping `["0"="Off","1"="On"]` | +| carpet_press | Number | Vacuum Extend - Carpet Press | Value mapping `["0"="Off","1"="On"]` | +| remote_state | String | Vacuum Extend - Remote State | | +| clean_rags_tip | Number:Time | Vacuum Extend - Clean Rags Tip | | +| keep_sweeper_time | Number:Time | Vacuum Extend - Keep Sweeper Time | | +| faults | String | Vacuum Extend - Faults | | +| enable | Switch | Do Not Disturb - Enable | | +| start_time | String | Do Not Disturb - Start Time | | +| end_time | String | Do Not Disturb - End Time | | +| frame_info | String | Map - Frame Info | | +| map_extend_data | String | Map - Map Extend Data | | +| mult_map_state | Number | Map - Mult Map State | Value mapping `["0"="Close","1"="Open"]` | +| mult_map_info | String | Map - Mult Map Info | | +| volume | Number:Dimensionless | Audio - Volume | | +| voice_packet_id | String | Audio - Voice Packet Id | | +| voice_change_state | String | Audio - Voice Change State | | +| set_voice | String | Audio - Set Voice | | +| time_zone | String | Time - Time Zone | | +| timer_clean | String | Time - Timer Clean | | +| first_clean_time | Number | Clean Logs - First Clean Time | | +| total_clean_time | Number:Time | Clean Logs - Total Clean Time | | +| total_clean_times | Number | Clean Logs - Total Clean Times | | +| total_clean_area | Number | Clean Logs - Total Clean Area | | + ### HUIZUO ARIES For Bedroom (huayi.light.ari013) Channels | Channel | Type | Description | Comment | @@ -6000,6 +6156,117 @@ Number total_clean_times "Clean Logs - Total Clean Times" (G_vacuum) {channel="m Number total_clean_area "Clean Logs - Total Clean Area" (G_vacuum) {channel="miio:basic:vacuum:total-clean-area"} ``` +### Dreame Bot W10 (dreame.vacuum.p2027) item file lines + +note: Autogenerated example. Replace the id (vacuum) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_vacuum "Dreame Bot W10" +String actions "Actions" (G_vacuum) {channel="miio:basic:vacuum:actions"} +Number status "Robot Cleaner - Status" (G_vacuum) {channel="miio:basic:vacuum:status"} +Number fault "Robot Cleaner - Device Fault" (G_vacuum) {channel="miio:basic:vacuum:fault"} +Number mode "Robot Cleaner - Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number:Dimensionless battery_level "Battery - Battery Level" (G_vacuum) {channel="miio:basic:vacuum:battery_level"} +Number charging_state "Battery - Charging State" (G_vacuum) {channel="miio:basic:vacuum:charging_state"} +Number:Time brush_left_time "Main Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time"} +Number:Dimensionless brush_life_level "Main Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level"} +Number:Time brush_left_time1 "Side Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time1"} +Number:Dimensionless brush_life_level1 "Side Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level1"} +Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_vacuum) {channel="miio:basic:vacuum:filter_life_level"} +Number:Time filter_left_time "Filter - Filter Left Time" (G_vacuum) {channel="miio:basic:vacuum:filter_left_time"} +Number work_mode "Vacuum Extend - Work Mode" (G_vacuum) {channel="miio:basic:vacuum:work_mode"} +Number:Time cleaning_time "Vacuum Extend - Cleaning Time" (G_vacuum) {channel="miio:basic:vacuum:cleaning_time"} +Number:Area cleaning_area "Vacuum Extend - Cleaning Area" (G_vacuum) {channel="miio:basic:vacuum:cleaning-area"} +Number cleaning_mode "Vacuum Extend - Cleaning Mode" (G_vacuum) {channel="miio:basic:vacuum:cleaning_mode"} +Number mop_mode "Vacuum Extend - Mop Mode" (G_vacuum) {channel="miio:basic:vacuum:mop_mode"} +Number waterbox_status "Vacuum Extend - Waterbox Status" (G_vacuum) {channel="miio:basic:vacuum:waterbox_status"} +Number task_status "Vacuum Extend - Task Status" (G_vacuum) {channel="miio:basic:vacuum:task_status"} +String clean_extend_data "Vacuum Extend - Clean Extend Data" (G_vacuum) {channel="miio:basic:vacuum:clean_extend_data"} +Number break_point_restart "Vacuum Extend - Break Point Restart" (G_vacuum) {channel="miio:basic:vacuum:break_point_restart"} +Number carpet_press "Vacuum Extend - Carpet Press" (G_vacuum) {channel="miio:basic:vacuum:carpet_press"} +String remote_state "Vacuum Extend - Remote State" (G_vacuum) {channel="miio:basic:vacuum:remote_state"} +Number:Time clean_rags_tip "Vacuum Extend - Clean Rags Tip" (G_vacuum) {channel="miio:basic:vacuum:clean_rags_tip"} +Number:Time keep_sweeper_time "Vacuum Extend - Keep Sweeper Time" (G_vacuum) {channel="miio:basic:vacuum:keep_sweeper_time"} +String faults "Vacuum Extend - Faults" (G_vacuum) {channel="miio:basic:vacuum:faults"} +String nation_matched "Vacuum Extend - Nation Matched" (G_vacuum) {channel="miio:basic:vacuum:nation_matched"} +Number relocation_status "Vacuum Extend - Relocation Status" (G_vacuum) {channel="miio:basic:vacuum:relocation_status"} +Number mop_status "Vacuum Extend - Mop Status" (G_vacuum) {channel="miio:basic:vacuum:mop_status"} +Number child_lock "Vacuum Extend - Child Lock" (G_vacuum) {channel="miio:basic:vacuum:child_lock"} +Number clean_cancel "Vacuum Extend - Clean Cancel" (G_vacuum) {channel="miio:basic:vacuum:clean_cancel"} +Switch enable "Do Not Disturb - Enable" (G_vacuum) {channel="miio:basic:vacuum:enable"} +String start_time "Do Not Disturb - Start Time" (G_vacuum) {channel="miio:basic:vacuum:start_time"} +String end_time "Do Not Disturb - End Time" (G_vacuum) {channel="miio:basic:vacuum:end_time"} +String frame_info "Map - Frame Info" (G_vacuum) {channel="miio:basic:vacuum:frame_info"} +String map_extend_data "Map - Map Extend Data" (G_vacuum) {channel="miio:basic:vacuum:map_extend_data"} +Number mult_map_state "Map - Mult Map State" (G_vacuum) {channel="miio:basic:vacuum:mult_map_state"} +String mult_map_info "Map - Mult Map Info" (G_vacuum) {channel="miio:basic:vacuum:mult_map_info"} +Number:Dimensionless volume "Audio - Volume" (G_vacuum) {channel="miio:basic:vacuum:volume"} +String voice_packet_id "Audio - Voice Packet Id" (G_vacuum) {channel="miio:basic:vacuum:voice_packet_id"} +String voice_change_state "Audio - Voice Change State" (G_vacuum) {channel="miio:basic:vacuum:voice_change_state"} +String set_voice "Audio - Set Voice" (G_vacuum) {channel="miio:basic:vacuum:set_voice"} +String time_zone "Time - Time Zone" (G_vacuum) {channel="miio:basic:vacuum:time_zone"} +String timer_clean "Time - Timer Clean" (G_vacuum) {channel="miio:basic:vacuum:timer_clean"} +Number first_clean_time "Clean Logs - First Clean Time" (G_vacuum) {channel="miio:basic:vacuum:first_clean_time"} +Number:Time total_clean_time "Clean Logs - Total Clean Time" (G_vacuum) {channel="miio:basic:vacuum:total_clean_time"} +Number total_clean_times "Clean Logs - Total Clean Times" (G_vacuum) {channel="miio:basic:vacuum:total_clean_times"} +Number total_clean_area "Clean Logs - Total Clean Area" (G_vacuum) {channel="miio:basic:vacuum:total_clean_area"} +``` + +### Dreame Bot Z10 Pro (dreame.vacuum.p2028) item file lines + +note: Autogenerated example. Replace the id (vacuum) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_vacuum "Dreame Bot Z10 Pro" +String actions "Actions" (G_vacuum) {channel="miio:basic:vacuum:actions"} +Number status "Robot Cleaner - Status" (G_vacuum) {channel="miio:basic:vacuum:status"} +Number fault "Robot Cleaner - Device Fault" (G_vacuum) {channel="miio:basic:vacuum:fault"} +Number:Dimensionless battery_level "Battery - Battery Level" (G_vacuum) {channel="miio:basic:vacuum:battery_level"} +Number charging_state "Battery - Charging State" (G_vacuum) {channel="miio:basic:vacuum:charging_state"} +Number:Time brush_left_time "Main Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time"} +Number:Dimensionless brush_life_level "Main Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level"} +Number:Time brush_left_time1 "Side Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time1"} +Number:Dimensionless brush_life_level1 "Side Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level1"} +Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_vacuum) {channel="miio:basic:vacuum:filter_life_level"} +Number:Time filter_left_time "Filter - Filter Left Time" (G_vacuum) {channel="miio:basic:vacuum:filter_left_time"} +Number work_mode "Vacuum Extend - Work Mode" (G_vacuum) {channel="miio:basic:vacuum:work_mode"} +Number:Time cleaning_time "Vacuum Extend - Cleaning Time" (G_vacuum) {channel="miio:basic:vacuum:cleaning_time"} +Number:Area cleaning_area "Vacuum Extend - Cleaning Area" (G_vacuum) {channel="miio:basic:vacuum:cleaning-area"} +Number cleaning_mode "Vacuum Extend - Cleaning Mode" (G_vacuum) {channel="miio:basic:vacuum:cleaning_mode"} +Number mop_mode "Vacuum Extend - Mop Mode" (G_vacuum) {channel="miio:basic:vacuum:mop_mode"} +Number waterbox_status "Vacuum Extend - Waterbox Status" (G_vacuum) {channel="miio:basic:vacuum:waterbox_status"} +Number task_status "Vacuum Extend - Task Status" (G_vacuum) {channel="miio:basic:vacuum:task_status"} +String clean_extend_data "Vacuum Extend - Clean Extend Data" (G_vacuum) {channel="miio:basic:vacuum:clean_extend_data"} +Number break_point_restart "Vacuum Extend - Break Point Restart" (G_vacuum) {channel="miio:basic:vacuum:break_point_restart"} +Number carpet_press "Vacuum Extend - Carpet Press" (G_vacuum) {channel="miio:basic:vacuum:carpet_press"} +String remote_state "Vacuum Extend - Remote State" (G_vacuum) {channel="miio:basic:vacuum:remote_state"} +Number:Time clean_rags_tip "Vacuum Extend - Clean Rags Tip" (G_vacuum) {channel="miio:basic:vacuum:clean_rags_tip"} +Number:Time keep_sweeper_time "Vacuum Extend - Keep Sweeper Time" (G_vacuum) {channel="miio:basic:vacuum:keep_sweeper_time"} +String faults "Vacuum Extend - Faults" (G_vacuum) {channel="miio:basic:vacuum:faults"} +String nation_matched "Vacuum Extend - Nation Matched" (G_vacuum) {channel="miio:basic:vacuum:nation_matched"} +Number relocation_status "Vacuum Extend - Relocation Status" (G_vacuum) {channel="miio:basic:vacuum:relocation_status"} +Switch enable "Do Not Disturb - Enable" (G_vacuum) {channel="miio:basic:vacuum:enable"} +String start_time "Do Not Disturb - Start Time" (G_vacuum) {channel="miio:basic:vacuum:start_time"} +String end_time "Do Not Disturb - End Time" (G_vacuum) {channel="miio:basic:vacuum:end_time"} +String frame_info "Map - Frame Info" (G_vacuum) {channel="miio:basic:vacuum:frame_info"} +String map_extend_data "Map - Map Extend Data" (G_vacuum) {channel="miio:basic:vacuum:map_extend_data"} +Number mult_map_state "Map - Mult Map State" (G_vacuum) {channel="miio:basic:vacuum:mult_map_state"} +String mult_map_info "Map - Mult Map Info" (G_vacuum) {channel="miio:basic:vacuum:mult_map_info"} +Number:Dimensionless volume "Audio - Volume" (G_vacuum) {channel="miio:basic:vacuum:volume"} +String voice_packet_id "Audio - Voice Packet Id" (G_vacuum) {channel="miio:basic:vacuum:voice_packet_id"} +String voice_change_state "Audio - Voice Change State" (G_vacuum) {channel="miio:basic:vacuum:voice_change_state"} +String set_voice "Audio - Set Voice" (G_vacuum) {channel="miio:basic:vacuum:set_voice"} +String time_zone "Time - Time Zone" (G_vacuum) {channel="miio:basic:vacuum:time_zone"} +String timer_clean "Time - Timer Clean" (G_vacuum) {channel="miio:basic:vacuum:timer_clean"} +Number first_clean_time "Clean Logs - First Clean Time" (G_vacuum) {channel="miio:basic:vacuum:first_clean_time"} +Number:Time total_clean_time "Clean Logs - Total Clean Time" (G_vacuum) {channel="miio:basic:vacuum:total_clean_time"} +Number total_clean_times "Clean Logs - Total Clean Times" (G_vacuum) {channel="miio:basic:vacuum:total_clean_times"} +Number total_clean_area "Clean Logs - Total Clean Area" (G_vacuum) {channel="miio:basic:vacuum:total_clean_area"} +Number auto_collect "Collect Dust - Auto Collect" (G_vacuum) {channel="miio:basic:vacuum:auto_collect"} +Number clean_times "Collect Dust - Clean Times" (G_vacuum) {channel="miio:basic:vacuum:clean_times"} +Number dust_enable "Collect Dust - Dust Enable" (G_vacuum) {channel="miio:basic:vacuum:dust_enable"} +``` + ### Trouver Robot LDS Vacuum-Mop Finder (dreame.vacuum.p2036) item file lines note: Autogenerated example. Replace the id (vacuum) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. @@ -6180,6 +6447,57 @@ Number total_clean_times "Clean Logs - Total Clean Times" (G_vacuum) {channel="m Number total_clean_area "Clean Logs - Total Clean Area" (G_vacuum) {channel="miio:basic:vacuum:total-clean-area"} ``` +### Dreame Bot D9 Max (dreame.vacuum.p2259) item file lines + +note: Autogenerated example. Replace the id (vacuum) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_vacuum "Dreame Bot D9 Max" +String actions "Actions" (G_vacuum) {channel="miio:basic:vacuum:actions"} +Number status "Robot Cleaner - Status" (G_vacuum) {channel="miio:basic:vacuum:status"} +Number fault "Robot Cleaner - Device Fault" (G_vacuum) {channel="miio:basic:vacuum:fault"} +Number mode "Robot Cleaner - Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number:Dimensionless battery_level "Battery - Battery Level" (G_vacuum) {channel="miio:basic:vacuum:battery_level"} +Number charging_state "Battery - Charging State" (G_vacuum) {channel="miio:basic:vacuum:charging_state"} +Number:Time brush_left_time "Main Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time"} +Number:Dimensionless brush_life_level "Main Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level"} +Number:Time brush_left_time1 "Side Cleaning Brush - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time1"} +Number:Dimensionless brush_life_level1 "Side Cleaning Brush - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level1"} +Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_vacuum) {channel="miio:basic:vacuum:filter_life_level"} +Number:Time filter_left_time "Filter - Filter Left Time" (G_vacuum) {channel="miio:basic:vacuum:filter_left_time"} +Number work_mode "Vacuum Extend - Work Mode" (G_vacuum) {channel="miio:basic:vacuum:work_mode"} +Number:Time cleaning_time "Vacuum Extend - Cleaning Time" (G_vacuum) {channel="miio:basic:vacuum:cleaning_time"} +Number:Area cleaning_area "Vacuum Extend - Cleaning Area" (G_vacuum) {channel="miio:basic:vacuum:cleaning_area"} +Number cleaning_mode "Vacuum Extend - Cleaning Mode" (G_vacuum) {channel="miio:basic:vacuum:cleaning_mode"} +Number mop_mode "Vacuum Extend - Mop Mode" (G_vacuum) {channel="miio:basic:vacuum:mop_mode"} +Number waterbox_status "Vacuum Extend - Waterbox Status" (G_vacuum) {channel="miio:basic:vacuum:waterbox_status"} +Number task_status "Vacuum Extend - Task Status" (G_vacuum) {channel="miio:basic:vacuum:task_status"} +String clean_extend_data "Vacuum Extend - Clean Extend Data" (G_vacuum) {channel="miio:basic:vacuum:clean_extend_data"} +Number break_point_restart "Vacuum Extend - Break Point Restart" (G_vacuum) {channel="miio:basic:vacuum:break_point_restart"} +Number carpet_press "Vacuum Extend - Carpet Press" (G_vacuum) {channel="miio:basic:vacuum:carpet_press"} +String remote_state "Vacuum Extend - Remote State" (G_vacuum) {channel="miio:basic:vacuum:remote_state"} +Number:Time clean_rags_tip "Vacuum Extend - Clean Rags Tip" (G_vacuum) {channel="miio:basic:vacuum:clean_rags_tip"} +Number:Time keep_sweeper_time "Vacuum Extend - Keep Sweeper Time" (G_vacuum) {channel="miio:basic:vacuum:keep_sweeper_time"} +String faults "Vacuum Extend - Faults" (G_vacuum) {channel="miio:basic:vacuum:faults"} +Switch enable "Do Not Disturb - Enable" (G_vacuum) {channel="miio:basic:vacuum:enable"} +String start_time "Do Not Disturb - Start Time" (G_vacuum) {channel="miio:basic:vacuum:start_time"} +String end_time "Do Not Disturb - End Time" (G_vacuum) {channel="miio:basic:vacuum:end_time"} +String frame_info "Map - Frame Info" (G_vacuum) {channel="miio:basic:vacuum:frame_info"} +String map_extend_data "Map - Map Extend Data" (G_vacuum) {channel="miio:basic:vacuum:map_extend_data"} +Number mult_map_state "Map - Mult Map State" (G_vacuum) {channel="miio:basic:vacuum:mult_map_state"} +String mult_map_info "Map - Mult Map Info" (G_vacuum) {channel="miio:basic:vacuum:mult_map_info"} +Number:Dimensionless volume "Audio - Volume" (G_vacuum) {channel="miio:basic:vacuum:volume"} +String voice_packet_id "Audio - Voice Packet Id" (G_vacuum) {channel="miio:basic:vacuum:voice_packet_id"} +String voice_change_state "Audio - Voice Change State" (G_vacuum) {channel="miio:basic:vacuum:voice_change_state"} +String set_voice "Audio - Set Voice" (G_vacuum) {channel="miio:basic:vacuum:set_voice"} +String time_zone "Time - Time Zone" (G_vacuum) {channel="miio:basic:vacuum:time_zone"} +String timer_clean "Time - Timer Clean" (G_vacuum) {channel="miio:basic:vacuum:timer_clean"} +Number first_clean_time "Clean Logs - First Clean Time" (G_vacuum) {channel="miio:basic:vacuum:first_clean_time"} +Number:Time total_clean_time "Clean Logs - Total Clean Time" (G_vacuum) {channel="miio:basic:vacuum:total_clean_time"} +Number total_clean_times "Clean Logs - Total Clean Times" (G_vacuum) {channel="miio:basic:vacuum:total_clean_times"} +Number total_clean_area "Clean Logs - Total Clean Area" (G_vacuum) {channel="miio:basic:vacuum:total_clean_area"} +``` + ### HUIZUO ARIES For Bedroom (huayi.light.ari013) item file lines note: Autogenerated example. Replace the id (light) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java index 5f925592cbb7a..603d2f7c016f7 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java @@ -66,10 +66,13 @@ public enum MiIoDevices { DREAME_VACUUM_MC1808("dreame.vacuum.mc1808", "Mi Robot Vacuum Mop 1C STYTJ01ZHM", THING_TYPE_BASIC), DREAME_VACUUM_P2008("dreame.vacuum.p2008", "Dreame Robot Vacuum-Mop F9", THING_TYPE_BASIC), DREAME_VACUUM_P2009("dreame.vacuum.p2009", "Dreame Robot Vacuum D9 ", THING_TYPE_BASIC), + DREAME_VACUUM_P2027("dreame.vacuum.p2027", "Dreame Bot W10", THING_TYPE_BASIC), + DREAME_VACUUM_P2028("dreame.vacuum.p2028", "Dreame Bot Z10 Pro", THING_TYPE_BASIC), DREAME_VACUUM_P2036("dreame.vacuum.p2036", "Trouver Robot LDS Vacuum-Mop Finder", THING_TYPE_BASIC), DREAME_VACUUM_P2041O("dreame.vacuum.p2041o", "Mi Robot Vacuum-Mop 2 Pro+", THING_TYPE_BASIC), DREAME_VACUUM_P2156O("dreame.vacuum.p2156o", "MOVA Z500 Robot Vacuum and Mop Cleaner", THING_TYPE_BASIC), DREAME_VACUUM_P2157("dreame.vacuum.p2157", "MOVA L600 Robot Vacuum and Mop Cleaner", THING_TYPE_BASIC), + DREAME_VACUUM_P2259("dreame.vacuum.p2259", "Dreame Bot D9 Max", THING_TYPE_BASIC), HUAYI_LIGHT_ARI013("huayi.light.ari013", "HUIZUO ARIES For Bedroom", THING_TYPE_BASIC), HUAYI_LIGHT_ARIES("huayi.light.aries", "HUIZUO ARIES For Living Room", THING_TYPE_BASIC), HUAYI_LIGHT_FANWY("huayi.light.fanwy", "HUIZUO Fan Light", THING_TYPE_BASIC), diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java index 7a23e11add20f..b29ece74a5ecf 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/miot/MiotParser.java @@ -66,6 +66,7 @@ public class MiotParser { private static final String BASEURL = "https://miot-spec.org/miot-spec-v2/"; private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final boolean SKIP_SIID_1 = true; + private static final boolean INCLUDE_MANUAL_ACTIONS_COMMENT = false; private String model; private @Nullable String urn; @@ -328,7 +329,7 @@ public MiIoBasicDevice getDevice(JsonElement urnData) throws MiotParseException } deviceMapping.setChannels(miIoBasicChannels); device.setDevice(deviceMapping); - if (actionText.length() > 35) { + if (actionText.length() > 35 && INCLUDE_MANUAL_ACTIONS_COMMENT) { deviceMapping.setReadmeComment( "Identified " + actionText.toString().replace("Manual", "manual").replace("\r\n", "
") + "Please test and feedback if they are working so they can be linked to a channel."); diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2027-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2027-miot.json new file mode 100644 index 0000000000000..f5a494538bb21 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2027-miot.json @@ -0,0 +1,1373 @@ +{ + "deviceMapping": { + "id": [ + "dreame.vacuum.p2027" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "vacuum-start-sweep", + "label": "Vacuum Start Sweep" + }, + { + "value": "vacuum-stop-sweeping", + "label": "Vacuum Stop Sweeping" + }, + { + "value": "vacuum-start-room-sweep", + "label": "Vacuum Start Room Sweep" + }, + { + "value": "battery-start-charge", + "label": "Battery Start Charge" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "filter-reset-filter-life", + "label": "Filter Reset Filter Life" + }, + { + "value": "vacuum-extend-start-clean", + "label": "Vacuum Extend Start Clean" + }, + { + "value": "vacuum-extend-stop-clean", + "label": "Vacuum Extend Stop Clean" + }, + { + "value": "map-map-req", + "label": "Map Map Req" + }, + { + "value": "map-update-map", + "label": "Map Update Map" + }, + { + "value": "audio-position", + "label": "Audio Position" + }, + { + "value": "audio-play-sound", + "label": "Audio Play Sound" + }, + { + "value": "time-delete-timer", + "label": "Time Delete Timer" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-stop-sweeping" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 4.0 + ], + "siid": 2, + "aiid": 3, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-room-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 3, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "battery-start-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 9, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 10, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 11, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "filter-reset-filter-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 10.0 + ], + "siid": 4, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-start-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 4, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-stop-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 2.0 + ], + "siid": 6, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-map-req" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 4.0 + ], + "siid": 6, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-update-map" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-position" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-play-sound" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 3.0 + ], + "siid": 8, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "time-delete-timer" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"vacuum-start-sweep\"\u003d\"Vacuum Start Sweep\",\"vacuum-stop-sweeping\"\u003d\"Vacuum Stop Sweeping\",\"vacuum-start-room-sweep\"\u003d\"Vacuum Start Room Sweep\",\"battery-start-charge\"\u003d\"Battery Start Charge\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"filter-reset-filter-life\"\u003d\"Filter Reset Filter Life\",\"vacuum-extend-start-clean\"\u003d\"Vacuum Extend Start Clean\",\"vacuum-extend-stop-clean\"\u003d\"Vacuum Extend Stop Clean\",\"map-map-req\"\u003d\"Map Map Req\",\"map-update-map\"\u003d\"Map Update Map\",\"audio-position\"\u003d\"Audio Position\",\"audio-play-sound\"\u003d\"Audio Play Sound\",\"time-delete-timer\"\u003d\"Time Delete Timer\"]`" + }, + { + "property": "status", + "siid": 2, + "piid": 1, + "friendlyName": "Robot Cleaner - Status", + "channel": "status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Sweeping" + }, + { + "value": "2", + "label": "Idle" + }, + { + "value": "3", + "label": "Paused" + }, + { + "value": "4", + "label": "Error" + }, + { + "value": "5", + "label": "Go Charging" + }, + { + "value": "6", + "label": "Charging" + }, + { + "value": "7", + "label": "Mopping" + }, + { + "value": "8", + "label": "Drying" + }, + { + "value": "9", + "label": "Washing" + }, + { + "value": "10", + "label": "Go Washing" + }, + { + "value": "11", + "label": "Building" + }, + { + "value": "12", + "label": "Sweeping and Mopping" + }, + { + "value": "13", + "label": "Charging Completed" + } + ] + }, + "refresh": true, + "actions": [], + "category": "status", + "tags": [ + "Status" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Sweeping\",\"2\"\u003d\"Idle\",\"3\"\u003d\"Paused\",\"4\"\u003d\"Error\",\"5\"\u003d\"Go Charging\",\"6\"\u003d\"Charging\",\"7\"\u003d\"Mopping\",\"8\"\u003d\"Drying\",\"9\"\u003d\"Washing\",\"10\"\u003d\"Go Washing\",\"11\"\u003d\"Building\",\"12\"\u003d\"Sweeping and Mopping\",\"13\"\u003d\"Charging Completed\"]`" + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Robot Cleaner - Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Error" + }, + { + "value": "1", + "label": "Drop" + }, + { + "value": "2", + "label": "Cliff" + }, + { + "value": "3", + "label": "Bumper" + }, + { + "value": "4", + "label": "Gesture" + }, + { + "value": "5", + "label": "Bumper Repeat" + }, + { + "value": "6", + "label": "Drop Repeat" + }, + { + "value": "7", + "label": "Optical Flow" + }, + { + "value": "8", + "label": "No Box" + }, + { + "value": "9", + "label": "No Tankbox" + }, + { + "value": "10", + "label": "Waterbox Empty" + }, + { + "value": "11", + "label": "Box full" + }, + { + "value": "12", + "label": "Brush" + }, + { + "value": "13", + "label": "Side Brush" + }, + { + "value": "14", + "label": "Fan" + }, + { + "value": "15", + "label": "Left Wheel motor" + }, + { + "value": "16", + "label": "Right Wheel motor" + }, + { + "value": "17", + "label": "Turn suffocate" + }, + { + "value": "18", + "label": "Forward suffocate" + }, + { + "value": "19", + "label": "Charger get" + }, + { + "value": "20", + "label": "Battery low" + }, + { + "value": "21", + "label": "Charge fault" + }, + { + "value": "22", + "label": "Battery percentage" + }, + { + "value": "23", + "label": "Heart" + }, + { + "value": "24", + "label": "Camera occlusion" + }, + { + "value": "25", + "label": "Camera fault" + }, + { + "value": "26", + "label": "Event battery" + }, + { + "value": "27", + "label": "Forward looking" + }, + { + "value": "28", + "label": "Gyroscope" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Error\",\"1\"\u003d\"Drop\",\"2\"\u003d\"Cliff\",\"3\"\u003d\"Bumper\",\"4\"\u003d\"Gesture\",\"5\"\u003d\"Bumper Repeat\",\"6\"\u003d\"Drop Repeat\",\"7\"\u003d\"Optical Flow\",\"8\"\u003d\"No Box\",\"9\"\u003d\"No Tankbox\",\"10\"\u003d\"Waterbox Empty\",\"11\"\u003d\"Box full\",\"12\"\u003d\"Brush\",\"13\"\u003d\"Side Brush\",\"14\"\u003d\"Fan\",\"15\"\u003d\"Left Wheel motor\",\"16\"\u003d\"Right Wheel motor\",\"17\"\u003d\"Turn suffocate\",\"18\"\u003d\"Forward suffocate\",\"19\"\u003d\"Charger get\",\"20\"\u003d\"Battery low\",\"21\"\u003d\"Charge fault\",\"22\"\u003d\"Battery percentage\",\"23\"\u003d\"Heart\",\"24\"\u003d\"Camera occlusion\",\"25\"\u003d\"Camera fault\",\"26\"\u003d\"Event battery\",\"27\"\u003d\"Forward looking\",\"28\"\u003d\"Gyroscope\"]`" + }, + { + "property": "mode", + "siid": 2, + "piid": 3, + "friendlyName": "Robot Cleaner - Mode", + "channel": "mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Silent" + }, + { + "value": "1", + "label": "Basic" + }, + { + "value": "2", + "label": "Strong" + }, + { + "value": "3", + "label": "Full Speed" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Silent\",\"1\"\u003d\"Basic\",\"2\"\u003d\"Strong\",\"3\"\u003d\"Full Speed\"]`" + }, + { + "property": "battery-level", + "siid": 3, + "piid": 1, + "friendlyName": "Battery - Battery Level", + "channel": "battery_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "charging-state", + "siid": 3, + "piid": 2, + "friendlyName": "Battery - Charging State", + "channel": "charging_state", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Charging" + }, + { + "value": "2", + "label": "Not Charging" + }, + { + "value": "5", + "label": "Go Charging" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"1\"\u003d\"Charging\",\"2\"\u003d\"Not Charging\",\"5\"\u003d\"Go Charging\"]`" + }, + { + "property": "brush-left-time", + "siid": 9, + "piid": 1, + "friendlyName": "Main Cleaning Brush - Brush Left Time", + "channel": "brush_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 300, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level", + "siid": 9, + "piid": 2, + "friendlyName": "Main Cleaning Brush - Brush Life Level", + "channel": "brush_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-left-time1", + "siid": 10, + "piid": 1, + "friendlyName": "Side Cleaning Brush - Brush Left Time", + "channel": "brush_left_time1", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 200, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level1", + "siid": 10, + "piid": 2, + "friendlyName": "Side Cleaning Brush - Brush Life Level", + "channel": "brush_life_level1", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-life-level", + "siid": 11, + "piid": 1, + "friendlyName": "Filter - Filter Life Level", + "channel": "filter_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-left-time", + "siid": 11, + "piid": 2, + "friendlyName": "Filter - Filter Left Time", + "channel": "filter_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 150, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "work-mode", + "siid": 4, + "piid": 1, + "friendlyName": "Vacuum Extend - Work Mode", + "channel": "work_mode", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 50, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-time", + "siid": 4, + "piid": 2, + "friendlyName": "Vacuum Extend - Cleaning Time", + "channel": "cleaning_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-area", + "siid": 4, + "piid": 3, + "friendlyName": "Vacuum Extend - Cleaning Area", + "channel": "cleaning-area", + "type": "Number:Area", + "unit": "square_meter", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.1f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-mode", + "siid": 4, + "piid": 4, + "friendlyName": "Vacuum Extend - Cleaning Mode", + "channel": "cleaning_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "mode 0" + }, + { + "value": "1", + "label": "mode 1" + }, + { + "value": "2", + "label": "mode 2" + }, + { + "value": "3", + "label": "mode 3" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"mode 0\",\"1\"\u003d\"mode 1\",\"2\"\u003d\"mode 2\",\"3\"\u003d\"mode 3\"]`" + }, + { + "property": "mop-mode", + "siid": 4, + "piid": 5, + "friendlyName": "Vacuum Extend - Mop Mode", + "channel": "mop_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "low water" + }, + { + "value": "2", + "label": "medium water" + }, + { + "value": "3", + "label": "high water" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"low water\",\"2\"\u003d\"medium water\",\"3\"\u003d\"high water\"]`" + }, + { + "property": "waterbox-status", + "siid": 4, + "piid": 6, + "friendlyName": "Vacuum Extend - Waterbox Status", + "channel": "waterbox_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Status 0" + }, + { + "value": "1", + "label": "Status 1" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Status 0\",\"1\"\u003d\"Status 1\"]`" + }, + { + "property": "task-status", + "siid": 4, + "piid": 7, + "friendlyName": "Vacuum Extend - Task Status", + "channel": "task_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Notask" + }, + { + "value": "1", + "label": "AutoClean" + }, + { + "value": "2", + "label": "CustomClean" + }, + { + "value": "3", + "label": "SelectAreanClean" + }, + { + "value": "4", + "label": "SpotArea" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Notask\",\"1\"\u003d\"AutoClean\",\"2\"\u003d\"CustomClean\",\"3\"\u003d\"SelectAreanClean\",\"4\"\u003d\"SpotArea\"]`" + }, + { + "property": "clean-extend-data", + "siid": 4, + "piid": 10, + "friendlyName": "Vacuum Extend - Clean Extend Data", + "channel": "clean_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "break-point-restart", + "siid": 4, + "piid": 11, + "friendlyName": "Vacuum Extend - Break Point Restart", + "channel": "break_point_restart", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "carpet-press", + "siid": 4, + "piid": 12, + "friendlyName": "Vacuum Extend - Carpet Press", + "channel": "carpet_press", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "remote-state", + "siid": 4, + "piid": 15, + "friendlyName": "Vacuum Extend - Remote State", + "channel": "remote_state", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "clean-rags-tip", + "siid": 4, + "piid": 16, + "friendlyName": "Vacuum Extend - Clean Rags Tip", + "channel": "clean_rags_tip", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 120, + "step": 1, + "pattern": "%.0f %unit%" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "keep-sweeper-time", + "siid": 4, + "piid": 17, + "friendlyName": "Vacuum Extend - Keep Sweeper Time", + "channel": "keep_sweeper_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": -1, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "faults", + "siid": 4, + "piid": 18, + "friendlyName": "Vacuum Extend - Faults", + "channel": "faults", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "nation-matched", + "siid": 4, + "piid": 19, + "friendlyName": "Vacuum Extend - Nation Matched", + "channel": "nation_matched", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "relocation-status", + "siid": 4, + "piid": 20, + "friendlyName": "Vacuum Extend - Relocation Status", + "channel": "relocation_status", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "mop-status", + "siid": 4, + "piid": 25, + "friendlyName": "Vacuum Extend - Mop Status", + "channel": "mop_status", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 255, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "child-lock", + "siid": 4, + "piid": 27, + "friendlyName": "Vacuum Extend - Child Lock", + "channel": "child_lock", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Close" + }, + { + "value": "1", + "label": "Open" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Close\",\"1\"\u003d\"Open\"]`" + }, + { + "property": "clean-cancel", + "siid": 4, + "piid": 30, + "friendlyName": "Vacuum Extend - Clean Cancel", + "channel": "clean_cancel", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 255, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "enable", + "siid": 5, + "piid": 1, + "friendlyName": "Do Not Disturb - Enable", + "channel": "enable", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "start-time", + "siid": 5, + "piid": 2, + "friendlyName": "Do Not Disturb - Start Time", + "channel": "start_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "end-time", + "siid": 5, + "piid": 3, + "friendlyName": "Do Not Disturb - End Time", + "channel": "end_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "frame-info", + "siid": 6, + "piid": 2, + "friendlyName": "Map - Frame Info", + "channel": "frame_info", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "map-extend-data", + "siid": 6, + "piid": 4, + "friendlyName": "Map - Map Extend Data", + "channel": "map_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "mult-map-state", + "siid": 6, + "piid": 7, + "friendlyName": "Map - Mult Map State", + "channel": "mult_map_state", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Close" + }, + { + "value": "1", + "label": "Open" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Close\",\"1\"\u003d\"Open\"]`" + }, + { + "property": "mult-map-info", + "siid": 6, + "piid": 8, + "friendlyName": "Map - Mult Map Info", + "channel": "mult_map_info", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "volume", + "siid": 7, + "piid": 1, + "friendlyName": "Audio - Volume", + "channel": "volume", + "type": "Number:Dimensionless", + "unit": "PERCENT", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "voice-packet-id", + "siid": 7, + "piid": 2, + "friendlyName": "Audio - Voice Packet Id", + "channel": "voice_packet_id", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "voice-change-state", + "siid": 7, + "piid": 3, + "friendlyName": "Audio - Voice Change State", + "channel": "voice_change_state", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "set-voice", + "siid": 7, + "piid": 4, + "friendlyName": "Audio - Set Voice", + "channel": "set_voice", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "time-zone", + "siid": 8, + "piid": 1, + "friendlyName": "Time - Time Zone", + "channel": "time_zone", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "timer-clean", + "siid": 8, + "piid": 2, + "friendlyName": "Time - Timer Clean", + "channel": "timer_clean", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "first-clean-time", + "siid": 12, + "piid": 1, + "friendlyName": "Clean Logs - First Clean Time", + "channel": "first_clean_time", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-time", + "siid": 12, + "piid": 2, + "friendlyName": "Clean Logs - Total Clean Time", + "channel": "total_clean_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-times", + "siid": 12, + "piid": 3, + "friendlyName": "Clean Logs - Total Clean Times", + "channel": "total_clean_times", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-area", + "siid": 12, + "piid": 4, + "friendlyName": "Clean Logs - Total Clean Area", + "channel": "total_clean_area", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + } + ], + "experimental": true + } +} diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2028-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2028-miot.json new file mode 100644 index 0000000000000..c42ef35a8a0ca --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2028-miot.json @@ -0,0 +1,1316 @@ +{ + "deviceMapping": { + "id": [ + "dreame.vacuum.p2028" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "vacuum-start-sweep", + "label": "Vacuum Start Sweep" + }, + { + "value": "vacuum-stop-sweeping", + "label": "Vacuum Stop Sweeping" + }, + { + "value": "battery-start-charge", + "label": "Battery Start Charge" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "filter-reset-filter-life", + "label": "Filter Reset Filter Life" + }, + { + "value": "vacuum-extend-start-clean", + "label": "Vacuum Extend Start Clean" + }, + { + "value": "vacuum-extend-stop-clean", + "label": "Vacuum Extend Stop Clean" + }, + { + "value": "map-map-req", + "label": "Map Map Req" + }, + { + "value": "map-update-map", + "label": "Map Update Map" + }, + { + "value": "audio-position", + "label": "Audio Position" + }, + { + "value": "audio-play-sound", + "label": "Audio Play Sound" + }, + { + "value": "time-delete-timer", + "label": "Time Delete Timer" + }, + { + "value": "collect-dust-start-collect", + "label": "Collect Dust Start Collect" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-stop-sweeping" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 3, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "battery-start-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 9, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 10, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 11, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "filter-reset-filter-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 10.0 + ], + "siid": 4, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-start-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 4, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-stop-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 2.0 + ], + "siid": 6, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-map-req" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 4.0 + ], + "siid": 6, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-update-map" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-position" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-play-sound" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 3.0 + ], + "siid": 8, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "time-delete-timer" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 15, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "collect-dust-start-collect" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"vacuum-start-sweep\"\u003d\"Vacuum Start Sweep\",\"vacuum-stop-sweeping\"\u003d\"Vacuum Stop Sweeping\",\"battery-start-charge\"\u003d\"Battery Start Charge\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"filter-reset-filter-life\"\u003d\"Filter Reset Filter Life\",\"vacuum-extend-start-clean\"\u003d\"Vacuum Extend Start Clean\",\"vacuum-extend-stop-clean\"\u003d\"Vacuum Extend Stop Clean\",\"map-map-req\"\u003d\"Map Map Req\",\"map-update-map\"\u003d\"Map Update Map\",\"audio-position\"\u003d\"Audio Position\",\"audio-play-sound\"\u003d\"Audio Play Sound\",\"time-delete-timer\"\u003d\"Time Delete Timer\",\"collect-dust-start-collect\"\u003d\"Collect Dust Start Collect\"]`" + }, + { + "property": "status", + "siid": 2, + "piid": 1, + "friendlyName": "Robot Cleaner - Status", + "channel": "status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Sweeping" + }, + { + "value": "2", + "label": "Idle" + }, + { + "value": "3", + "label": "Paused" + }, + { + "value": "4", + "label": "Error" + }, + { + "value": "5", + "label": "Go Charging" + }, + { + "value": "6", + "label": "Charging" + }, + { + "value": "7", + "label": "Mopping" + } + ] + }, + "refresh": true, + "actions": [], + "category": "status", + "tags": [ + "Status" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Sweeping\",\"2\"\u003d\"Idle\",\"3\"\u003d\"Paused\",\"4\"\u003d\"Error\",\"5\"\u003d\"Go Charging\",\"6\"\u003d\"Charging\",\"7\"\u003d\"Mopping\"]`" + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Robot Cleaner - Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Error" + }, + { + "value": "1", + "label": "Drop" + }, + { + "value": "2", + "label": "Cliff" + }, + { + "value": "3", + "label": "Bumper" + }, + { + "value": "4", + "label": "Gesture" + }, + { + "value": "5", + "label": "Bumper Repeat" + }, + { + "value": "6", + "label": "Drop Repeat" + }, + { + "value": "7", + "label": "Optical Flow" + }, + { + "value": "8", + "label": "No Box" + }, + { + "value": "9", + "label": "No Tankbox" + }, + { + "value": "10", + "label": "Waterbox Empty" + }, + { + "value": "11", + "label": "Box full" + }, + { + "value": "12", + "label": "Brush" + }, + { + "value": "13", + "label": "Side Brush" + }, + { + "value": "14", + "label": "Fan" + }, + { + "value": "15", + "label": "Left Wheel motor" + }, + { + "value": "16", + "label": "Right Wheel motor" + }, + { + "value": "17", + "label": "Turn suffocate" + }, + { + "value": "18", + "label": "Forward suffocate" + }, + { + "value": "19", + "label": "Charger get" + }, + { + "value": "20", + "label": "Battery low" + }, + { + "value": "21", + "label": "Charge fault" + }, + { + "value": "22", + "label": "Battery percentage" + }, + { + "value": "23", + "label": "Heart" + }, + { + "value": "24", + "label": "Camera occlusion" + }, + { + "value": "25", + "label": "Camera fault" + }, + { + "value": "26", + "label": "Event battery" + }, + { + "value": "27", + "label": "Forward looking" + }, + { + "value": "28", + "label": "Gyroscope" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Error\",\"1\"\u003d\"Drop\",\"2\"\u003d\"Cliff\",\"3\"\u003d\"Bumper\",\"4\"\u003d\"Gesture\",\"5\"\u003d\"Bumper Repeat\",\"6\"\u003d\"Drop Repeat\",\"7\"\u003d\"Optical Flow\",\"8\"\u003d\"No Box\",\"9\"\u003d\"No Tankbox\",\"10\"\u003d\"Waterbox Empty\",\"11\"\u003d\"Box full\",\"12\"\u003d\"Brush\",\"13\"\u003d\"Side Brush\",\"14\"\u003d\"Fan\",\"15\"\u003d\"Left Wheel motor\",\"16\"\u003d\"Right Wheel motor\",\"17\"\u003d\"Turn suffocate\",\"18\"\u003d\"Forward suffocate\",\"19\"\u003d\"Charger get\",\"20\"\u003d\"Battery low\",\"21\"\u003d\"Charge fault\",\"22\"\u003d\"Battery percentage\",\"23\"\u003d\"Heart\",\"24\"\u003d\"Camera occlusion\",\"25\"\u003d\"Camera fault\",\"26\"\u003d\"Event battery\",\"27\"\u003d\"Forward looking\",\"28\"\u003d\"Gyroscope\"]`" + }, + { + "property": "battery-level", + "siid": 3, + "piid": 1, + "friendlyName": "Battery - Battery Level", + "channel": "battery_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "charging-state", + "siid": 3, + "piid": 2, + "friendlyName": "Battery - Charging State", + "channel": "charging_state", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Charging" + }, + { + "value": "2", + "label": "Not Charging" + }, + { + "value": "5", + "label": "Go Charging" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"1\"\u003d\"Charging\",\"2\"\u003d\"Not Charging\",\"5\"\u003d\"Go Charging\"]`" + }, + { + "property": "brush-left-time", + "siid": 9, + "piid": 1, + "friendlyName": "Main Cleaning Brush - Brush Left Time", + "channel": "brush_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 300, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level", + "siid": 9, + "piid": 2, + "friendlyName": "Main Cleaning Brush - Brush Life Level", + "channel": "brush_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-left-time1", + "siid": 10, + "piid": 1, + "friendlyName": "Side Cleaning Brush - Brush Left Time", + "channel": "brush_left_time1", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 200, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level1", + "siid": 10, + "piid": 2, + "friendlyName": "Side Cleaning Brush - Brush Life Level", + "channel": "brush_life_level1", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-life-level", + "siid": 11, + "piid": 1, + "friendlyName": "Filter - Filter Life Level", + "channel": "filter_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-left-time", + "siid": 11, + "piid": 2, + "friendlyName": "Filter - Filter Left Time", + "channel": "filter_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 150, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "work-mode", + "siid": 4, + "piid": 1, + "friendlyName": "Vacuum Extend - Work Mode", + "channel": "work_mode", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 50, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-time", + "siid": 4, + "piid": 2, + "friendlyName": "Vacuum Extend - Cleaning Time", + "channel": "cleaning_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-area", + "siid": 4, + "piid": 3, + "friendlyName": "Vacuum Extend - Cleaning Area", + "channel": "cleaning-area", + "type": "Number:Area", + "unit": "square_meter", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.1f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-mode", + "siid": 4, + "piid": 4, + "friendlyName": "Vacuum Extend - Cleaning Mode", + "channel": "cleaning_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "mode 0" + }, + { + "value": "1", + "label": "mode 1" + }, + { + "value": "2", + "label": "mode 2" + }, + { + "value": "3", + "label": "mode 3" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"mode 0\",\"1\"\u003d\"mode 1\",\"2\"\u003d\"mode 2\",\"3\"\u003d\"mode 3\"]`" + }, + { + "property": "mop-mode", + "siid": 4, + "piid": 5, + "friendlyName": "Vacuum Extend - Mop Mode", + "channel": "mop_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "low water" + }, + { + "value": "2", + "label": "medium water" + }, + { + "value": "3", + "label": "high water" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"low water\",\"2\"\u003d\"medium water\",\"3\"\u003d\"high water\"]`" + }, + { + "property": "waterbox-status", + "siid": 4, + "piid": 6, + "friendlyName": "Vacuum Extend - Waterbox Status", + "channel": "waterbox_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Status 0" + }, + { + "value": "1", + "label": "Status 1" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Status 0\",\"1\"\u003d\"Status 1\"]`" + }, + { + "property": "task-status", + "siid": 4, + "piid": 7, + "friendlyName": "Vacuum Extend - Task Status", + "channel": "task_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Notask" + }, + { + "value": "1", + "label": "AutoClean" + }, + { + "value": "2", + "label": "CustomClean" + }, + { + "value": "3", + "label": "SelectAreanClean" + }, + { + "value": "4", + "label": "SpotArea" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Notask\",\"1\"\u003d\"AutoClean\",\"2\"\u003d\"CustomClean\",\"3\"\u003d\"SelectAreanClean\",\"4\"\u003d\"SpotArea\"]`" + }, + { + "property": "clean-extend-data", + "siid": 4, + "piid": 10, + "friendlyName": "Vacuum Extend - Clean Extend Data", + "channel": "clean_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "break-point-restart", + "siid": 4, + "piid": 11, + "friendlyName": "Vacuum Extend - Break Point Restart", + "channel": "break_point_restart", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "carpet-press", + "siid": 4, + "piid": 12, + "friendlyName": "Vacuum Extend - Carpet Press", + "channel": "carpet_press", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "remote-state", + "siid": 4, + "piid": 15, + "friendlyName": "Vacuum Extend - Remote State", + "channel": "remote_state", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "clean-rags-tip", + "siid": 4, + "piid": 16, + "friendlyName": "Vacuum Extend - Clean Rags Tip", + "channel": "clean_rags_tip", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 120, + "step": 1, + "pattern": "%.0f %unit%" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "keep-sweeper-time", + "siid": 4, + "piid": 17, + "friendlyName": "Vacuum Extend - Keep Sweeper Time", + "channel": "keep_sweeper_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": -1, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "faults", + "siid": 4, + "piid": 18, + "friendlyName": "Vacuum Extend - Faults", + "channel": "faults", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "nation-matched", + "siid": 4, + "piid": 19, + "friendlyName": "Vacuum Extend - Nation Matched", + "channel": "nation_matched", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "relocation-status", + "siid": 4, + "piid": 20, + "friendlyName": "Vacuum Extend - Relocation Status", + "channel": "relocation_status", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "enable", + "siid": 5, + "piid": 1, + "friendlyName": "Do Not Disturb - Enable", + "channel": "enable", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "start-time", + "siid": 5, + "piid": 2, + "friendlyName": "Do Not Disturb - Start Time", + "channel": "start_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "end-time", + "siid": 5, + "piid": 3, + "friendlyName": "Do Not Disturb - End Time", + "channel": "end_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "frame-info", + "siid": 6, + "piid": 2, + "friendlyName": "Map - Frame Info", + "channel": "frame_info", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "map-extend-data", + "siid": 6, + "piid": 4, + "friendlyName": "Map - Map Extend Data", + "channel": "map_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "mult-map-state", + "siid": 6, + "piid": 7, + "friendlyName": "Map - Mult Map State", + "channel": "mult_map_state", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Close" + }, + { + "value": "1", + "label": "Open" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Close\",\"1\"\u003d\"Open\"]`" + }, + { + "property": "mult-map-info", + "siid": 6, + "piid": 8, + "friendlyName": "Map - Mult Map Info", + "channel": "mult_map_info", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "volume", + "siid": 7, + "piid": 1, + "friendlyName": "Audio - Volume", + "channel": "volume", + "type": "Number:Dimensionless", + "unit": "PERCENT", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "voice-packet-id", + "siid": 7, + "piid": 2, + "friendlyName": "Audio - Voice Packet Id", + "channel": "voice_packet_id", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "voice-change-state", + "siid": 7, + "piid": 3, + "friendlyName": "Audio - Voice Change State", + "channel": "voice_change_state", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "set-voice", + "siid": 7, + "piid": 4, + "friendlyName": "Audio - Set Voice", + "channel": "set_voice", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "time-zone", + "siid": 8, + "piid": 1, + "friendlyName": "Time - Time Zone", + "channel": "time_zone", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "timer-clean", + "siid": 8, + "piid": 2, + "friendlyName": "Time - Timer Clean", + "channel": "timer_clean", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "first-clean-time", + "siid": 12, + "piid": 1, + "friendlyName": "Clean Logs - First Clean Time", + "channel": "first_clean_time", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-time", + "siid": 12, + "piid": 2, + "friendlyName": "Clean Logs - Total Clean Time", + "channel": "total_clean_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-times", + "siid": 12, + "piid": 3, + "friendlyName": "Clean Logs - Total Clean Times", + "channel": "total_clean_times", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-area", + "siid": 12, + "piid": 4, + "friendlyName": "Clean Logs - Total Clean Area", + "channel": "total_clean_area", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "auto-collect", + "siid": 15, + "piid": 1, + "friendlyName": "Collect Dust - Auto Collect", + "channel": "auto_collect", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Close-auto-collect" + }, + { + "value": "1", + "label": "Open-auto-collect" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Close-auto-collect\",\"1\"\u003d\"Open-auto-collect\"]`" + }, + { + "property": "clean-times", + "siid": 15, + "piid": 2, + "friendlyName": "Collect Dust - Clean Times", + "channel": "clean_times", + "type": "Number", + "stateDescription": { + "minimum": 1, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f" + }, + "refresh": true, + "actions": [] + }, + { + "property": "dust-enable", + "siid": 15, + "piid": 3, + "friendlyName": "Collect Dust - Dust Enable", + "channel": "dust_enable", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Disable" + }, + { + "value": "1", + "label": "Enable" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Disable\",\"1\"\u003d\"Enable\"]`" + } + ], + "experimental": true + } +} diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json index 0a698c2083f42..dcb5f1f25954f 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2156o-miot.json @@ -1019,7 +1019,6 @@ "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2259-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2259-miot.json new file mode 100644 index 0000000000000..24b75c8b1f32e --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2259-miot.json @@ -0,0 +1,1257 @@ +{ + "deviceMapping": { + "id": [ + "dreame.vacuum.p2259" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "vacuum-start-sweep", + "label": "Vacuum Start Sweep" + }, + { + "value": "vacuum-stop-sweeping", + "label": "Vacuum Stop Sweeping" + }, + { + "value": "vacuum-start-room-sweep", + "label": "Vacuum Start Room Sweep" + }, + { + "value": "battery-start-charge", + "label": "Battery Start Charge" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "filter-reset-filter-life", + "label": "Filter Reset Filter Life" + }, + { + "value": "vacuum-extend-start-clean", + "label": "Vacuum Extend Start Clean" + }, + { + "value": "vacuum-extend-stop-clean", + "label": "Vacuum Extend Stop Clean" + }, + { + "value": "map-map-req", + "label": "Map Map Req" + }, + { + "value": "map-update-map", + "label": "Map Update Map" + }, + { + "value": "audio-position", + "label": "Audio Position" + }, + { + "value": "audio-play-sound", + "label": "Audio Play Sound" + }, + { + "value": "time-delete-timer", + "label": "Time Delete Timer" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-stop-sweeping" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 4.0 + ], + "siid": 2, + "aiid": 3, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-room-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 3, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "battery-start-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 9, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 10, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 11, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "filter-reset-filter-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 10.0 + ], + "siid": 4, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-start-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 4, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-extend-stop-clean" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 2.0 + ], + "siid": 6, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-map-req" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 4.0 + ], + "siid": 6, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-update-map" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-position" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 7, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "audio-play-sound" + } + ] + } + }, + { + "command": "action", + "parameterType": "NUMBER", + "parameters": [ + 3.0 + ], + "siid": 8, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "time-delete-timer" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"vacuum-start-sweep\"\u003d\"Vacuum Start Sweep\",\"vacuum-stop-sweeping\"\u003d\"Vacuum Stop Sweeping\",\"vacuum-start-room-sweep\"\u003d\"Vacuum Start Room Sweep\",\"battery-start-charge\"\u003d\"Battery Start Charge\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"filter-reset-filter-life\"\u003d\"Filter Reset Filter Life\",\"vacuum-extend-start-clean\"\u003d\"Vacuum Extend Start Clean\",\"vacuum-extend-stop-clean\"\u003d\"Vacuum Extend Stop Clean\",\"map-map-req\"\u003d\"Map Map Req\",\"map-update-map\"\u003d\"Map Update Map\",\"audio-position\"\u003d\"Audio Position\",\"audio-play-sound\"\u003d\"Audio Play Sound\",\"time-delete-timer\"\u003d\"Time Delete Timer\"]`" + }, + { + "property": "status", + "siid": 2, + "piid": 1, + "friendlyName": "Robot Cleaner - Status", + "channel": "status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Sweeping" + }, + { + "value": "2", + "label": "Idle" + }, + { + "value": "3", + "label": "Paused" + }, + { + "value": "4", + "label": "Error" + }, + { + "value": "5", + "label": "Go Charging" + }, + { + "value": "6", + "label": "Charging" + }, + { + "value": "7", + "label": "Mopping" + } + ] + }, + "refresh": true, + "actions": [], + "category": "status", + "tags": [ + "Status" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Sweeping\",\"2\"\u003d\"Idle\",\"3\"\u003d\"Paused\",\"4\"\u003d\"Error\",\"5\"\u003d\"Go Charging\",\"6\"\u003d\"Charging\",\"7\"\u003d\"Mopping\"]`" + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Robot Cleaner - Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Error" + }, + { + "value": "1", + "label": "Drop" + }, + { + "value": "2", + "label": "Cliff" + }, + { + "value": "3", + "label": "Bumper" + }, + { + "value": "4", + "label": "Gesture" + }, + { + "value": "5", + "label": "Bumper Repeat" + }, + { + "value": "6", + "label": "Drop Repeat" + }, + { + "value": "7", + "label": "Optical Flow" + }, + { + "value": "8", + "label": "No Box" + }, + { + "value": "9", + "label": "No Tankbox" + }, + { + "value": "10", + "label": "Waterbox Empty" + }, + { + "value": "11", + "label": "Box full" + }, + { + "value": "12", + "label": "Brush" + }, + { + "value": "13", + "label": "Side Brush" + }, + { + "value": "14", + "label": "Fan" + }, + { + "value": "15", + "label": "Left Wheel motor" + }, + { + "value": "16", + "label": "Right Wheel motor" + }, + { + "value": "17", + "label": "Turn suffocate" + }, + { + "value": "18", + "label": "Forward suffocate" + }, + { + "value": "19", + "label": "Charger get" + }, + { + "value": "20", + "label": "Battery low" + }, + { + "value": "21", + "label": "Charge fault" + }, + { + "value": "22", + "label": "Battery percentage" + }, + { + "value": "23", + "label": "Heart" + }, + { + "value": "24", + "label": "Camera occlusion" + }, + { + "value": "25", + "label": "Camera fault" + }, + { + "value": "26", + "label": "Event battery" + }, + { + "value": "27", + "label": "Forward looking" + }, + { + "value": "28", + "label": "Gyroscope" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Error\",\"1\"\u003d\"Drop\",\"2\"\u003d\"Cliff\",\"3\"\u003d\"Bumper\",\"4\"\u003d\"Gesture\",\"5\"\u003d\"Bumper Repeat\",\"6\"\u003d\"Drop Repeat\",\"7\"\u003d\"Optical Flow\",\"8\"\u003d\"No Box\",\"9\"\u003d\"No Tankbox\",\"10\"\u003d\"Waterbox Empty\",\"11\"\u003d\"Box full\",\"12\"\u003d\"Brush\",\"13\"\u003d\"Side Brush\",\"14\"\u003d\"Fan\",\"15\"\u003d\"Left Wheel motor\",\"16\"\u003d\"Right Wheel motor\",\"17\"\u003d\"Turn suffocate\",\"18\"\u003d\"Forward suffocate\",\"19\"\u003d\"Charger get\",\"20\"\u003d\"Battery low\",\"21\"\u003d\"Charge fault\",\"22\"\u003d\"Battery percentage\",\"23\"\u003d\"Heart\",\"24\"\u003d\"Camera occlusion\",\"25\"\u003d\"Camera fault\",\"26\"\u003d\"Event battery\",\"27\"\u003d\"Forward looking\",\"28\"\u003d\"Gyroscope\"]`" + }, + { + "property": "mode", + "siid": 2, + "piid": 3, + "friendlyName": "Robot Cleaner - Mode", + "channel": "mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Silent" + }, + { + "value": "1", + "label": "Basic" + }, + { + "value": "2", + "label": "Strong" + }, + { + "value": "3", + "label": "Full Speed" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Silent\",\"1\"\u003d\"Basic\",\"2\"\u003d\"Strong\",\"3\"\u003d\"Full Speed\"]`" + }, + { + "property": "battery-level", + "siid": 3, + "piid": 1, + "friendlyName": "Battery - Battery Level", + "channel": "battery_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "charging-state", + "siid": 3, + "piid": 2, + "friendlyName": "Battery - Charging State", + "channel": "charging_state", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Charging" + }, + { + "value": "2", + "label": "Not Charging" + }, + { + "value": "5", + "label": "Go Charging" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"1\"\u003d\"Charging\",\"2\"\u003d\"Not Charging\",\"5\"\u003d\"Go Charging\"]`" + }, + { + "property": "brush-left-time", + "siid": 9, + "piid": 1, + "friendlyName": "Main Cleaning Brush - Brush Left Time", + "channel": "brush_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 300, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level", + "siid": 9, + "piid": 2, + "friendlyName": "Main Cleaning Brush - Brush Life Level", + "channel": "brush_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-left-time1", + "siid": 10, + "piid": 1, + "friendlyName": "Side Cleaning Brush - Brush Left Time", + "channel": "brush_left_time1", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 200, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "brush-life-level1", + "siid": 10, + "piid": 2, + "friendlyName": "Side Cleaning Brush - Brush Life Level", + "channel": "brush_life_level1", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-life-level", + "siid": 11, + "piid": 1, + "friendlyName": "Filter - Filter Life Level", + "channel": "filter_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "filter-left-time", + "siid": 11, + "piid": 2, + "friendlyName": "Filter - Filter Left Time", + "channel": "filter_left_time", + "type": "Number:Time", + "unit": "hours", + "stateDescription": { + "minimum": 0, + "maximum": 150, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "work-mode", + "siid": 4, + "piid": 1, + "friendlyName": "Vacuum Extend - Work Mode", + "channel": "work_mode", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 50, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-time", + "siid": 4, + "piid": 2, + "friendlyName": "Vacuum Extend - Cleaning Time", + "channel": "cleaning_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-area", + "siid": 4, + "piid": 3, + "friendlyName": "Vacuum Extend - Cleaning Area", + "channel": "cleaning_area", + "type": "Number:Area", + "unit": "square_meter", + "stateDescription": { + "minimum": 0, + "maximum": 32767, + "step": 1, + "pattern": "%.1f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "cleaning-mode", + "siid": 4, + "piid": 4, + "friendlyName": "Vacuum Extend - Cleaning Mode", + "channel": "cleaning_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "mode 0" + }, + { + "value": "1", + "label": "mode 1" + }, + { + "value": "2", + "label": "mode 2" + }, + { + "value": "3", + "label": "mode 3" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"mode 0\",\"1\"\u003d\"mode 1\",\"2\"\u003d\"mode 2\",\"3\"\u003d\"mode 3\"]`" + }, + { + "property": "mop-mode", + "siid": 4, + "piid": 5, + "friendlyName": "Vacuum Extend - Mop Mode", + "channel": "mop_mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "low water" + }, + { + "value": "2", + "label": "medium water" + }, + { + "value": "3", + "label": "high water" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"low water\",\"2\"\u003d\"medium water\",\"3\"\u003d\"high water\"]`" + }, + { + "property": "waterbox-status", + "siid": 4, + "piid": 6, + "friendlyName": "Vacuum Extend - Waterbox Status", + "channel": "waterbox_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Status 0" + }, + { + "value": "1", + "label": "Status 1" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Status 0\",\"1\"\u003d\"Status 1\"]`" + }, + { + "property": "task-status", + "siid": 4, + "piid": 7, + "friendlyName": "Vacuum Extend - Task Status", + "channel": "task_status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Notask" + }, + { + "value": "1", + "label": "AutoClean" + }, + { + "value": "2", + "label": "CustomClean" + }, + { + "value": "3", + "label": "SelectAreanClean" + }, + { + "value": "4", + "label": "SpotArea" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Notask\",\"1\"\u003d\"AutoClean\",\"2\"\u003d\"CustomClean\",\"3\"\u003d\"SelectAreanClean\",\"4\"\u003d\"SpotArea\"]`" + }, + { + "property": "clean-extend-data", + "siid": 4, + "piid": 10, + "friendlyName": "Vacuum Extend - Clean Extend Data", + "channel": "clean_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "break-point-restart", + "siid": 4, + "piid": 11, + "friendlyName": "Vacuum Extend - Break Point Restart", + "channel": "break_point_restart", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "carpet-press", + "siid": 4, + "piid": 12, + "friendlyName": "Vacuum Extend - Carpet Press", + "channel": "carpet_press", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Off" + }, + { + "value": "1", + "label": "On" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\"]`" + }, + { + "property": "remote-state", + "siid": 4, + "piid": 15, + "friendlyName": "Vacuum Extend - Remote State", + "channel": "remote_state", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "clean-rags-tip", + "siid": 4, + "piid": 16, + "friendlyName": "Vacuum Extend - Clean Rags Tip", + "channel": "clean_rags_tip", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 120, + "step": 1, + "pattern": "%.0f %unit%" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "keep-sweeper-time", + "siid": 4, + "piid": 17, + "friendlyName": "Vacuum Extend - Keep Sweeper Time", + "channel": "keep_sweeper_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": -1, + "maximum": 1000000, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "faults", + "siid": 4, + "piid": 18, + "friendlyName": "Vacuum Extend - Faults", + "channel": "faults", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "enable", + "siid": 5, + "piid": 1, + "friendlyName": "Do Not Disturb - Enable", + "channel": "enable", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "start-time", + "siid": 5, + "piid": 2, + "friendlyName": "Do Not Disturb - Start Time", + "channel": "start_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "end-time", + "siid": 5, + "piid": 3, + "friendlyName": "Do Not Disturb - End Time", + "channel": "end_time", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "frame-info", + "siid": 6, + "piid": 2, + "friendlyName": "Map - Frame Info", + "channel": "frame_info", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "map-extend-data", + "siid": 6, + "piid": 4, + "friendlyName": "Map - Map Extend Data", + "channel": "map_extend_data", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "mult-map-state", + "siid": 6, + "piid": 7, + "friendlyName": "Map - Mult Map State", + "channel": "mult_map_state", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Close" + }, + { + "value": "1", + "label": "Open" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Close\",\"1\"\u003d\"Open\"]`" + }, + { + "property": "mult-map-info", + "siid": 6, + "piid": 8, + "friendlyName": "Map - Mult Map Info", + "channel": "mult_map_info", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "volume", + "siid": 7, + "piid": 1, + "friendlyName": "Audio - Volume", + "channel": "volume", + "type": "Number:Dimensionless", + "unit": "PERCENT", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "voice-packet-id", + "siid": 7, + "piid": 2, + "friendlyName": "Audio - Voice Packet Id", + "channel": "voice_packet_id", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "voice-change-state", + "siid": 7, + "piid": 3, + "friendlyName": "Audio - Voice Change State", + "channel": "voice_change_state", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "set-voice", + "siid": 7, + "piid": 4, + "friendlyName": "Audio - Set Voice", + "channel": "set_voice", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "time-zone", + "siid": 8, + "piid": 1, + "friendlyName": "Time - Time Zone", + "channel": "time_zone", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "timer-clean", + "siid": 8, + "piid": 2, + "friendlyName": "Time - Timer Clean", + "channel": "timer_clean", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "first-clean-time", + "siid": 12, + "piid": 1, + "friendlyName": "Clean Logs - First Clean Time", + "channel": "first_clean_time", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-time", + "siid": 12, + "piid": 2, + "friendlyName": "Clean Logs - Total Clean Time", + "channel": "total_clean_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-times", + "siid": 12, + "piid": 3, + "friendlyName": "Clean Logs - Total Clean Times", + "channel": "total_clean_times", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-area", + "siid": 12, + "piid": 4, + "friendlyName": "Clean Logs - Total Clean Area", + "channel": "total_clean_area", + "type": "Number", + "stateDescription": { + "minimum": 0, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + } + ], + "experimental": true + } +} From 9b8158d6c48789ebae8516179e8bac18667599fb Mon Sep 17 00:00:00 2001 From: M Valla <12682715+mvalla@users.noreply.github.com> Date: Sun, 5 Dec 2021 11:26:36 +0100 Subject: [PATCH 177/361] [openwebnet] Fixes discovery of devices on local bus. Added it translation (#11644) Signed-off-by: Massimo Valla Signed-off-by: Michael Schmidt --- .../OpenWebNetDeviceDiscoveryService.java | 2 +- .../handler/OpenWebNetBridgeHandler.java | 2 +- .../OH-INF/i18n/openwebnet.properties | 26 ++++++++++++------- .../OH-INF/i18n/openwebnet_hu.properties | 2 +- .../OH-INF/i18n/openwebnet_it.properties | 18 +++++++++++++ 5 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java index e6857d837de46..2c75705e40ab2 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java @@ -188,7 +188,7 @@ public void newDiscoveryResult(Where where, OpenDeviceType deviceType, @Nullable DiscoveryResult discoveryResult = null; - String whereConfig = bridgeHandler.normalizeWhere(where); + String whereConfig = where.value(); if (where instanceof WhereZigBee && WhereZigBee.UNIT_02.equals(((WhereZigBee) where).getUnit())) { logger.debug("UNIT=02 found (WHERE={}) -> will remove previous result if exists", where); thingRemoved(thingUID); // remove previously discovered thing diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetBridgeHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetBridgeHandler.java index 7908f63d84b16..5bf23e76ee380 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetBridgeHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetBridgeHandler.java @@ -600,7 +600,7 @@ public String thingIdFromWhere(Where where) { } /** - * Normalize a Where address + * Normalize a Where address to generate ownId and Thing id * * @param where the Where address * @return the normalized address as String diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties index be9950b25e8f5..bf3bac400e37d 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties @@ -1,12 +1,18 @@ -# Thing status descriptions -offline.conf-error-no-ip-address = Cannot connect to gateway. No host/IP has been provided in Bridge configuration. -offline.conf-error-no-serial-port = Cannot connect to gateway. No serial port has been provided in Bridge configuration. -offline.conf-error-where = WHERE parameter in Thing configuration is null or invalid -offline.conf-error-no-bridge = No bridge associated, please assign a bridge in Thing configuration. -offline.conf-error-auth = Authentication error. Check gateway password in Thing Configuration Parameters - -offline.comm-error-disconnected = Disconnected from gateway -offline.comm-error-timeout = Connection to gateway timed out -offline.comm-error-connection = Could not connect to gateway +# binding + +binding.openwebnet.name = OpenWebNet (BTicino/Legrand) Binding +binding.openwebnet.description = The OpenWebNet binding integrates BTicino (Legrand) MyHOME® BUS and wireless systems using the OpenWebNet protocol. + +# thing status descriptions + +offline.conf-error-no-ip-address = Cannot connect to gateway. No host/IP address has been provided in configuration. +offline.conf-error-no-serial-port = Cannot connect to gateway. No serial port has been provided in configuration. +offline.conf-error-where = OpenWebNet Address (where) parameter in configuration is null or invalid. +offline.conf-error-no-bridge = No bridge associated. Assign a bridge in configuration. +offline.conf-error-auth = Authentication failed. Check gateway password in configuration. + +offline.comm-error-disconnected = Disconnected from gateway. +offline.comm-error-timeout = Connection to gateway timed out. +offline.comm-error-connection = Could not connect to gateway. unknown.waiting-state = Waiting state update... diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_hu.properties b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_hu.properties index 9a6cce7256250..83fd55f249834 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_hu.properties +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_hu.properties @@ -1,7 +1,7 @@ # Thing status descriptions offline.conf-error-no-ip-address = Nem lehet az átjáróhoz csatlakozni. Nincs gazdanév/IP megadva a híd konfigurációjában. offline.conf-error-no-serial-port = Nem lehet az átjáróhoz csatlakozni. Nincs soros port megadva a híd konfigurációjában. -offline.conf-error-where = WHERE paraméter a dolog konfigurációjában null vagy érvénytelen +offline.conf-error-where = OpenWebNet Address (where) paraméter a dolog konfigurációjában null vagy érvénytelen offline.conf-error-no-bridge = Nincs híd hozzárendelve, a dolog konfigurációjában adjon meg egyet. offline.conf-error-auth = Hitelesítési hiba. Ellenőrizze az átjáró jelszavát a dolog beállítási paramétereiben diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties new file mode 100644 index 0000000000000..666f18cc4f400 --- /dev/null +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties @@ -0,0 +1,18 @@ +# binding + +binding.openwebnet.name = OpenWebNet (BTicino/Legrand) Binding +binding.openwebnet.description = Il binding OpenWebNet integra i sistemi BTicino (Legrand) MyHOME® BUS e wireless tramite il protocollo OpenWebNet. + +# thing status descriptions + +offline.conf-error-no-ip-address = Impossibile connettersi al gateway. Nessun host/IP specificato nella configurazione. +offline.conf-error-no-serial-port = Impossibile connettersi al gateway. Nessuna porta seriale specificata nella configurazione. +offline.conf-error-where = Il parametro OpenWebNet Address (where) nella configurazione nullo o non valido. +offline.conf-error-no-bridge = Nessun bridge associato. Assegnare un bridge nella configurazione. +offline.conf-error-auth = Autenticazione fallita. Verificare la password nella configurazione. + +offline.comm-error-disconnected = Disconnesso dal gateway. +offline.comm-error-timeout = Connessione al gateway non riuscita in tempo. +offline.comm-error-connection = Impossibile connettersi al gateway. + +unknown.waiting-state = In attesa di aggiornamento di stato... From 783bca16772eca72af1088de82afa66991f3218a Mon Sep 17 00:00:00 2001 From: jlaur Date: Sun, 5 Dec 2021 17:48:37 +0100 Subject: [PATCH 178/361] Fix initialization of shade handler. (#11707) Fixes #11702 Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- .../handler/HDPowerViewHubHandler.java | 2 +- .../handler/HDPowerViewShadeHandler.java | 20 +++++++++++++++---- .../OH-INF/i18n/hdpowerview.properties | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index 35f1696932efa..2eda6b8b23598 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -135,7 +135,7 @@ public void initialize() { if (host == null || host.isEmpty()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "@text/offline.conf-error-no-host-address"); + "@text/offline.conf-error.no-host-address"); return; } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java index 42514597bafbf..038b4f71a370a 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java @@ -39,6 +39,7 @@ import org.openhab.core.library.types.StopMoveType; import org.openhab.core.library.types.UpDownType; import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -80,14 +81,25 @@ public void initialize() { getShadeId(); } catch (NumberFormatException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Configuration 'id' not a valid integer"); + "@text/offline.conf-error.invalid-id"); return; } - if (getBridgeHandler() == null) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Hub not configured"); + Bridge bridge = getBridge(); + if (bridge == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED); return; } - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); + if (!(bridge.getHandler() instanceof HDPowerViewHubHandler)) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, + "@text/offline.conf-error.invalid-bridge-handler"); + return; + } + ThingStatus bridgeStatus = bridge.getStatus(); + if (bridgeStatus == ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + } } @Override diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties index 34875ac80c592..9e8e94cd18179 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties @@ -36,7 +36,9 @@ channel-type.hdpowerview.shade-vane.description = The opening of the slats in th # thing status descriptions -offline.conf-error-no-host-address = Host address must be set +offline.conf-error.no-host-address = Host address must be set +offline.conf-error.invalid-id = Configuration 'id' not a valid integer +offline.conf-error.invalid-bridge-handler = Invalid bridge handler # dynamic channels From f50fc0028302abdee8729fc8cc8d0da6b328f9de Mon Sep 17 00:00:00 2001 From: Daniel Lienert Date: Sun, 5 Dec 2021 17:51:31 +0100 Subject: [PATCH 179/361] [systeminfo] Fix Thing and Sitemap example (#11708) Signed-off-by: Daniel Lienert Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.systeminfo/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.systeminfo/README.md b/bundles/org.openhab.binding.systeminfo/README.md index e910f65dbddf1..713f160abf20f 100644 --- a/bundles/org.openhab.binding.systeminfo/README.md +++ b/bundles/org.openhab.binding.systeminfo/README.md @@ -171,7 +171,7 @@ For a general problem with the binding report the issue directly to openHAB. Things: ``` -systeminfo:computer:work [interval_high=3, interval_medium=60] +Thing systeminfo:computer:work [interval_high=3, interval_medium=60] ``` Items: @@ -249,7 +249,7 @@ String Process_path "Path" { chann Sitemap: ``` -Text label="Systeminfo" { +sitemap systeminfo label="Systeminfo" { Frame label="Network Information" { Default item=Network_AdapterName Default item=Network_Name From 8c9630643b0526b1b394088267a2398e185a3fc9 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 5 Dec 2021 19:29:44 +0100 Subject: [PATCH 180/361] Remove unnecessary executable permissions (#11710) These files are marked as executable for no good reason at all. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../src/main/feature/feature.xml | 0 .../jythonscripting/JythonScriptEngineFactory.java | 0 .../BroadlinkThermostatBindingConstants.java | 0 .../internal/BroadlinkThermostatHandlerFactory.java | 0 .../BroadlinkThermostatDiscoveryService.java | 0 .../handler/BroadlinkThermostatHandler.java | 0 .../internal/handler/FloureonThermostatHandler.java | 0 bundles/org.openhab.binding.folderwatcher/README.md | 0 .../internal/FolderWatcherBindingConstants.java | 0 .../internal/FolderWatcherHandlerFactory.java | 0 .../internal/common/WatcherCommon.java | 0 .../config/FtpFolderWatcherConfiguration.java | 0 .../config/LocalFolderWatcherConfiguration.java | 0 .../internal/handler/FtpFolderWatcherHandler.java | 0 .../internal/handler/LocalFolderWatcherHandler.java | 0 .../src/main/resources/OH-INF/binding/binding.xml | 0 .../src/main/resources/OH-INF/thing/thing-types.xml | 0 .../internal/MagentaTVBindingConstants.java | 0 .../magentatv/internal/MagentaTVException.java | 0 .../magentatv/internal/MagentaTVGsonDTO.java | 0 .../magentatv/internal/MagentaTVHandlerFactory.java | 0 .../config/MagentaTVThingConfiguration.java | 0 .../discovery/MagentaTVDiscoveryParticipant.java | 0 .../internal/handler/MagentaTVControl.java | 0 .../internal/handler/MagentaTVHandler.java | 0 .../internal/handler/MagentaTVListener.java | 0 .../magentatv/internal/network/MagentaTVHttp.java | 0 .../internal/network/MagentaTVNetwork.java | 0 .../internal/network/MagentaTVNotifyServlet.java | 0 .../magentatv/internal/network/MagentaTVOAuth.java | 0 .../internal/network/MagentaTVPoweroffListener.java | 0 .../src/main/resources/OH-INF/binding/binding.xml | 0 .../src/main/resources/OH-INF/thing/thing-types.xml | 0 .../mielecloud/internal/config/assets/css/main.css | 0 .../doc/the-worm-small.png | Bin bundles/org.openhab.binding.playstation/NOTICE | 0 bundles/org.openhab.binding.playstation/README.md | 0 bundles/org.openhab.binding.playstation/pom.xml | 0 .../playstation/internal/PS3Configuration.java | 0 .../binding/playstation/internal/PS3Handler.java | 0 .../playstation/internal/PS4ArtworkHandler.java | 0 .../binding/playstation/internal/PS4Command.java | 0 .../playstation/internal/PS4Configuration.java | 0 .../binding/playstation/internal/PS4Crypto.java | 0 .../playstation/internal/PS4ErrorStatus.java | 0 .../binding/playstation/internal/PS4Handler.java | 0 .../playstation/internal/PS4PacketHandler.java | 0 .../internal/PlayStationBindingConstants.java | 0 .../internal/PlayStationHandlerFactory.java | 0 .../internal/discovery/PlayStationDiscovery.java | 0 .../src/main/resources/OH-INF/binding/binding.xml | 0 .../src/main/resources/OH-INF/config/config.xml | 0 .../src/main/resources/OH-INF/thing/thing-types.xml | 0 53 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml mode change 100755 => 100644 bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java mode change 100755 => 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatBindingConstants.java mode change 100755 => 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatHandlerFactory.java mode change 100755 => 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/discovery/BroadlinkThermostatDiscoveryService.java mode change 100755 => 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/BroadlinkThermostatHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/FloureonThermostatHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/README.md mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherBindingConstants.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherHandlerFactory.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/common/WatcherCommon.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/FtpFolderWatcherConfiguration.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/LocalFolderWatcherConfiguration.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/FtpFolderWatcherHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/LocalFolderWatcherHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/binding/binding.xml mode change 100755 => 100644 bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/thing/thing-types.xml mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVBindingConstants.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVException.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVGsonDTO.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVHandlerFactory.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/config/MagentaTVThingConfiguration.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/discovery/MagentaTVDiscoveryParticipant.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVControl.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVListener.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVHttp.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNetwork.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNotifyServlet.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVOAuth.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVPoweroffListener.java mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/binding/binding.xml mode change 100755 => 100644 bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/thing/thing-types.xml mode change 100755 => 100644 bundles/org.openhab.binding.mielecloud/src/main/resources/org/openhab/binding/mielecloud/internal/config/assets/css/main.css mode change 100755 => 100644 bundles/org.openhab.binding.nanoleaf/doc/the-worm-small.png mode change 100755 => 100644 bundles/org.openhab.binding.playstation/NOTICE mode change 100755 => 100644 bundles/org.openhab.binding.playstation/README.md mode change 100755 => 100644 bundles/org.openhab.binding.playstation/pom.xml mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Configuration.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Handler.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ArtworkHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Command.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Configuration.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Crypto.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ErrorStatus.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Handler.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4PacketHandler.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationBindingConstants.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationHandlerFactory.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/discovery/PlayStationDiscovery.java mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/binding/binding.xml mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/config/config.xml mode change 100755 => 100644 bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml b/bundles/org.openhab.automation.jythonscripting/src/main/feature/feature.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java b/bundles/org.openhab.automation.jythonscripting/src/main/java/org/openhab/automation/jythonscripting/JythonScriptEngineFactory.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatBindingConstants.java b/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatBindingConstants.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatHandlerFactory.java b/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/BroadlinkThermostatHandlerFactory.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/discovery/BroadlinkThermostatDiscoveryService.java b/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/discovery/BroadlinkThermostatDiscoveryService.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/BroadlinkThermostatHandler.java b/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/BroadlinkThermostatHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/FloureonThermostatHandler.java b/bundles/org.openhab.binding.broadlinkthermostat/src/main/java/org/openhab/binding/broadlinkthermostat/internal/handler/FloureonThermostatHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/README.md b/bundles/org.openhab.binding.folderwatcher/README.md old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherBindingConstants.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherBindingConstants.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherHandlerFactory.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/FolderWatcherHandlerFactory.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/common/WatcherCommon.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/common/WatcherCommon.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/FtpFolderWatcherConfiguration.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/FtpFolderWatcherConfiguration.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/LocalFolderWatcherConfiguration.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/config/LocalFolderWatcherConfiguration.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/FtpFolderWatcherHandler.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/FtpFolderWatcherHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/LocalFolderWatcherHandler.java b/bundles/org.openhab.binding.folderwatcher/src/main/java/org/openhab/binding/folderwatcher/internal/handler/LocalFolderWatcherHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/binding/binding.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/thing/thing-types.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVBindingConstants.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVBindingConstants.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVException.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVException.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVGsonDTO.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVGsonDTO.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVHandlerFactory.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/MagentaTVHandlerFactory.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/config/MagentaTVThingConfiguration.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/config/MagentaTVThingConfiguration.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/discovery/MagentaTVDiscoveryParticipant.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/discovery/MagentaTVDiscoveryParticipant.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVControl.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVControl.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVHandler.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVListener.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/handler/MagentaTVListener.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVHttp.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVHttp.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNetwork.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNetwork.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNotifyServlet.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVNotifyServlet.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVOAuth.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVOAuth.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVPoweroffListener.java b/bundles/org.openhab.binding.magentatv/src/main/java/org/openhab/binding/magentatv/internal/network/MagentaTVPoweroffListener.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/binding/binding.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/thing/thing-types.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.mielecloud/src/main/resources/org/openhab/binding/mielecloud/internal/config/assets/css/main.css b/bundles/org.openhab.binding.mielecloud/src/main/resources/org/openhab/binding/mielecloud/internal/config/assets/css/main.css old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.nanoleaf/doc/the-worm-small.png b/bundles/org.openhab.binding.nanoleaf/doc/the-worm-small.png old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/NOTICE b/bundles/org.openhab.binding.playstation/NOTICE old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/README.md b/bundles/org.openhab.binding.playstation/README.md old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/pom.xml b/bundles/org.openhab.binding.playstation/pom.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Configuration.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Configuration.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Handler.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS3Handler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ArtworkHandler.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ArtworkHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Command.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Command.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Configuration.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Configuration.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Crypto.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Crypto.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ErrorStatus.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4ErrorStatus.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Handler.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4Handler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4PacketHandler.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PS4PacketHandler.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationBindingConstants.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationBindingConstants.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationHandlerFactory.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/PlayStationHandlerFactory.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/discovery/PlayStationDiscovery.java b/bundles/org.openhab.binding.playstation/src/main/java/org/openhab/binding/playstation/internal/discovery/PlayStationDiscovery.java old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/binding/binding.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/config/config.xml old mode 100755 new mode 100644 diff --git a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/thing/thing-types.xml old mode 100755 new mode 100644 From edbce2456474d1bb978ebb4a0587b6a352320714 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 5 Dec 2021 20:14:44 +0100 Subject: [PATCH 181/361] Rename English i18n properties to follow Crowdin naming conventions (#11709) This allows these files to be used for creating translations with Crowdin. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../i18n/{digitalstrom_en.properties => digitalstrom.properties} | 0 .../resources/OH-INF/i18n/{dsmr_en.properties => dsmr.properties} | 0 .../OH-INF/i18n/{enphase_en.properties => enphase.properties} | 0 .../OH-INF/i18n/{lghombot_en.properties => lghombot.properties} | 0 .../i18n/{mqttbroker_en.properties => mqttbroker.properties} | 0 .../i18n/{playstation_en.properties => playstation.properties} | 0 .../i18n/{pushbullet_en.properties => pushbullet.properties} | 0 .../OH-INF/i18n/{spotify_en.properties => spotify.properties} | 0 .../OH-INF/i18n/{urtsi_en.properties => urtsi.properties} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename bundles/org.openhab.binding.digitalstrom/src/main/resources/OH-INF/i18n/{digitalstrom_en.properties => digitalstrom.properties} (100%) rename bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/{dsmr_en.properties => dsmr.properties} (100%) rename bundles/org.openhab.binding.enphase/src/main/resources/OH-INF/i18n/{enphase_en.properties => enphase.properties} (100%) rename bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/{lghombot_en.properties => lghombot.properties} (100%) rename bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/{mqttbroker_en.properties => mqttbroker.properties} (100%) rename bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/{playstation_en.properties => playstation.properties} (100%) mode change 100755 => 100644 rename bundles/org.openhab.binding.pushbullet/src/main/resources/OH-INF/i18n/{pushbullet_en.properties => pushbullet.properties} (100%) rename bundles/org.openhab.binding.spotify/src/main/resources/OH-INF/i18n/{spotify_en.properties => spotify.properties} (100%) rename bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/{urtsi_en.properties => urtsi.properties} (100%) diff --git a/bundles/org.openhab.binding.digitalstrom/src/main/resources/OH-INF/i18n/digitalstrom_en.properties b/bundles/org.openhab.binding.digitalstrom/src/main/resources/OH-INF/i18n/digitalstrom.properties similarity index 100% rename from bundles/org.openhab.binding.digitalstrom/src/main/resources/OH-INF/i18n/digitalstrom_en.properties rename to bundles/org.openhab.binding.digitalstrom/src/main/resources/OH-INF/i18n/digitalstrom.properties diff --git a/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr_en.properties b/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties similarity index 100% rename from bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr_en.properties rename to bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties diff --git a/bundles/org.openhab.binding.enphase/src/main/resources/OH-INF/i18n/enphase_en.properties b/bundles/org.openhab.binding.enphase/src/main/resources/OH-INF/i18n/enphase.properties similarity index 100% rename from bundles/org.openhab.binding.enphase/src/main/resources/OH-INF/i18n/enphase_en.properties rename to bundles/org.openhab.binding.enphase/src/main/resources/OH-INF/i18n/enphase.properties diff --git a/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_en.properties b/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot.properties similarity index 100% rename from bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_en.properties rename to bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot.properties diff --git a/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_en.properties b/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties similarity index 100% rename from bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_en.properties rename to bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties diff --git a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_en.properties b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation.properties old mode 100755 new mode 100644 similarity index 100% rename from bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_en.properties rename to bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation.properties diff --git a/bundles/org.openhab.binding.pushbullet/src/main/resources/OH-INF/i18n/pushbullet_en.properties b/bundles/org.openhab.binding.pushbullet/src/main/resources/OH-INF/i18n/pushbullet.properties similarity index 100% rename from bundles/org.openhab.binding.pushbullet/src/main/resources/OH-INF/i18n/pushbullet_en.properties rename to bundles/org.openhab.binding.pushbullet/src/main/resources/OH-INF/i18n/pushbullet.properties diff --git a/bundles/org.openhab.binding.spotify/src/main/resources/OH-INF/i18n/spotify_en.properties b/bundles/org.openhab.binding.spotify/src/main/resources/OH-INF/i18n/spotify.properties similarity index 100% rename from bundles/org.openhab.binding.spotify/src/main/resources/OH-INF/i18n/spotify_en.properties rename to bundles/org.openhab.binding.spotify/src/main/resources/OH-INF/i18n/spotify.properties diff --git a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_en.properties b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties similarity index 100% rename from bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_en.properties rename to bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties From 38653e65b6b90c7a49e2a285e0a30080901e440f Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 5 Dec 2021 22:07:39 +0100 Subject: [PATCH 182/361] [mqtt] Add missing English translations (#11714) Without these English defaults Crowdin would remove German translations. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/mqttbroker.properties | 100 +++++++++++++++--- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties b/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties index 11495228186b1..fca41c5352f70 100644 --- a/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties +++ b/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker.properties @@ -1,14 +1,86 @@ -offline.notextualconfig=The system connection with the name {0} doesn't exist anymore. -offline.dyninsteadoftextual=A binding owned connection was found instead of a system connection for the broker name: {0}. -offline.textualinsteadofdny=A system connection was found instead of a dynamic connection for the broker name: {0}. -offline.sharedremoved=Another binding unexpectedly removed the internal broker connection. - -actionLabel=publish an MQTT message -actionDesc=Publishes a value to the given MQTT topic. - -actionInputTopicLabel=MQTT Topic -actionInputTopicDesc=The topic to publish a value to. -actionInputValueLabel=Value -actionInputValueDesc=The value to publish -actionInputRetainLabel=Retain -actionInputRetainDesc=Retain message +# binding + +binding.mqtt.name = MQTT Binding +binding.mqtt.description = Allows management of MQTT broker connections and linking of MQTT topics to Things and Channels + +# thing types + +thing-type.mqtt.broker.label = MQTT Broker +thing-type.mqtt.broker.description = A connection to a MQTT broker +thing-type.mqtt.systemBroker.label = System MQTT Broker +thing-type.mqtt.systemBroker.description = A system configured and therefore read-only broker connection. Properties are reflecting the configuration and internal connection status. + +# thing types config + +thing-type.config.mqtt.broker.certificate.label = Certificate Hash +thing-type.config.mqtt.broker.certificate.description = If **certificatepin** is set this hash is used to verify the connection. Clear to allow a new certificate pinning on the next connection attempt. If empty will be filled automatically by the next successful connection. An example input would be `SHA-256:83F9171E06A313118889F7D79302BD1B7A2042EE0CFD029ABF8DD06FFA6CD9D3`. +thing-type.config.mqtt.broker.certificatepin.label = Certificate Pinning +thing-type.config.mqtt.broker.certificatepin.description = If this and SSL is set: After the next connection has been successfully established, the certificate is pinned. The connection will be refused if another certificate is used. Clear **certificate** to allow a new certificate for the next connection attempt. This option can increase security. +thing-type.config.mqtt.broker.clientID.label = Client ID +thing-type.config.mqtt.broker.clientID.description = Use a fixed client ID. Defaults to empty which means a client ID is generated for this connection. +thing-type.config.mqtt.broker.enableDiscovery.label = Enable Discovery +thing-type.config.mqtt.broker.enableDiscovery.description = If set to true enables this broker for all discovery services. +thing-type.config.mqtt.broker.host.label = Broker Hostname/IP +thing-type.config.mqtt.broker.host.description = The IP/Hostname of the MQTT broker +thing-type.config.mqtt.broker.keepAlive.label = Heartbeat +thing-type.config.mqtt.broker.keepAlive.description = Keep alive / heartbeat timer in s. It can take up to this time to determine if a server connection is lost. A lower value may keep the broker unnecessarily busy for no or little additional value. +thing-type.config.mqtt.broker.lwtMessage.label = Last Will Message +thing-type.config.mqtt.broker.lwtMessage.description = The last will message. +thing-type.config.mqtt.broker.lwtQos.label = Last Will QoS +thing-type.config.mqtt.broker.lwtQos.description = The quality of service parameter of the last will. +thing-type.config.mqtt.broker.lwtQos.option.0 = At most once (0) +thing-type.config.mqtt.broker.lwtQos.option.1 = At least once (1) +thing-type.config.mqtt.broker.lwtQos.option.2 = Exactly once (2) +thing-type.config.mqtt.broker.lwtRetain.label = Last Will Retain +thing-type.config.mqtt.broker.lwtRetain.description = True if last Will should be retained (defaults to false) +thing-type.config.mqtt.broker.lwtTopic.label = Last Will Topic +thing-type.config.mqtt.broker.lwtTopic.description = Defaults to empty and therefore disables the last will. +thing-type.config.mqtt.broker.password.label = Password +thing-type.config.mqtt.broker.password.description = The MQTT password +thing-type.config.mqtt.broker.port.label = Broker Port +thing-type.config.mqtt.broker.port.description = The port is optional, if none is provided, the typical ports 1883 and 8883 (SSL) are used. +thing-type.config.mqtt.broker.publickey.label = Public Key Hash +thing-type.config.mqtt.broker.publickey.description = If **publickeypin** is set this hash is used to verify the connection. Clear to allow a new public key pinning on the next connection attempt. If empty will be filled automatically by the next successful connection. An example input would be `SHA-256:83F9171E06A313118889F7D79302BD1B7A2042EE0CFD029ABF8DD06FFA6CD9D3` +thing-type.config.mqtt.broker.publickeypin.label = Public Key Pinning +thing-type.config.mqtt.broker.publickeypin.description = If this and SSL is set: After the next connection has been successfully established, the public key of the broker is pinned. The connection will be refused if another public key is used. Clear **publickey** to allow a new public key for the next connection attempt. This option can increase security. +thing-type.config.mqtt.broker.qos.label = Quality of Service +thing-type.config.mqtt.broker.qos.option.0 = At most once (0) +thing-type.config.mqtt.broker.qos.option.1 = At least once (1) +thing-type.config.mqtt.broker.qos.option.2 = Exactly once (2) +thing-type.config.mqtt.broker.reconnectTime.label = Reconnect Time +thing-type.config.mqtt.broker.reconnectTime.description = Reconnect time in ms. If a connection is lost, the binding will wait this time before it tries to reconnect. +thing-type.config.mqtt.broker.secure.label = Secure Connection +thing-type.config.mqtt.broker.secure.description = Uses TLS/SSL to establish a secure connection to the broker. +thing-type.config.mqtt.broker.username.label = Username +thing-type.config.mqtt.broker.username.description = The MQTT username +thing-type.config.mqtt.systemBroker.brokerid.label = Broker ID +thing-type.config.mqtt.systemBroker.brokerid.description = Each system wide configured MQTT broker has a unique broker ID. +thing-type.config.mqtt.systemBroker.enableDiscovery.label = Enable Discovery +thing-type.config.mqtt.systemBroker.enableDiscovery.description = If set to true enables this broker for all discovery services. + +# channel types + +channel-type.mqtt.publishTrigger.label = Publish Trigger +channel-type.mqtt.publishTrigger.description = This channel is triggered when a value is published to the configured MQTT topic on this broker connection. The event payload will be the received MQTT topic value. + +# channel types config + +channel-type.config.mqtt.publishTrigger.payload.label = Payload Condition +channel-type.config.mqtt.publishTrigger.payload.description = An optional condition on the value of the MQTT topic that must match before this channel is triggered. +channel-type.config.mqtt.publishTrigger.separator.label = Separator Character +channel-type.config.mqtt.publishTrigger.separator.description = The trigger channel payload usually only contains the received MQTT topic value. If you define a separator character, for example '#', the topic and received value will be in the trigger channel payload. For example: my_topic#my_received_value. +channel-type.config.mqtt.publishTrigger.stateTopic.label = MQTT Topic +channel-type.config.mqtt.publishTrigger.stateTopic.description = This channel will trigger on this MQTT topic. This topic can contain wildcards like + and # for example "all/in/#" or "sensors/+/config". + +actionInputTopicLabel = MQTT Topic +actionInputTopicDesc = The topic to publish a value to. +actionInputValueLabel = Value +actionInputValueDesc = The value to publish +actionInputRetainLabel = Retain +actionInputRetainDesc = Retain message +actionLabel = publish an MQTT message +actionDesc = Publishes a value to the given MQTT topic. +offline.notextualconfig = The system connection with the name {0} doesn't exist anymore. +offline.dyninsteadoftextual = A binding owned connection was found instead of a system connection for the broker name: {0}. +offline.textualinsteadofdny = A system connection was found instead of a dynamic connection for the broker name: {0}. +offline.sharedremoved = Another binding unexpectedly removed the internal broker connection. From 6698bb2b9b0ded42582234a8dc5d8894690e4987 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 5 Dec 2021 22:12:41 +0100 Subject: [PATCH 183/361] [dsmr] Add missing English translations (#11713) Without these English defaults Crowdin would remove Dutch translations. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/dsmr.properties | 312 +++++++++++++++++- 1 file changed, 302 insertions(+), 10 deletions(-) diff --git a/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties b/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties index 16879e0480c60..dca842bf55456 100644 --- a/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties +++ b/bundles/org.openhab.binding.dsmr/src/main/resources/OH-INF/i18n/dsmr.properties @@ -1,6 +1,303 @@ -# Text used in the source code. +# binding + +binding.dsmr.name = DSMR Binding +binding.dsmr.description = This binding integrates Dutch, Belgium, Luxembourg and Austrian Smart Meters + +# thing types + +thing-type.dsmr.cooling_ace4000.label = Cooling Meter (ACE4000) +thing-type.dsmr.cooling_ace4000.description = This is a cooling meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.cooling_v2_2.label = Cooling Meter (DSMR V2.2) +thing-type.dsmr.cooling_v2_2.description = This is a cooling meter that complies to the DSMR V2.2 specification. +thing-type.dsmr.device_emucs_v1_0.label = Device Meter (e-MUCS V1.0) +thing-type.dsmr.device_emucs_v1_0.description = This is the device meter that complies to the e-MUCS 1.0 specification. +thing-type.dsmr.device_v2_v3.label = Device Meter (DSMR V2.x or V3.0) +thing-type.dsmr.device_v2_v3.description = This is the device meter that complies to the DSMR V2.x or V3 specification. +thing-type.dsmr.device_v4.label = Device Meter (DSMR V4.x) +thing-type.dsmr.device_v4.description = This is the device meter that complies to the DSMR V4 specification. +thing-type.dsmr.device_v5.label = Device Meter (DSMR V5) +thing-type.dsmr.device_v5.description = This is the device meter that complies to the DSMR V5 specification. +thing-type.dsmr.dsmrBridge.label = Smart Meter +thing-type.dsmr.dsmrBridge.description = The Dutch/Belgium Smart Meter (DSMR/e-MUCS) +thing-type.dsmr.electricity_ace4000.label = Electricity Meter (ACE4000) +thing-type.dsmr.electricity_ace4000.description = This is an electricity meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.electricity_emucs_v1_0.label = Electricity Meter (e-MUCS V1.0) +thing-type.dsmr.electricity_emucs_v1_0.description = This is an electricity meter that complies to the e-MUCS V1.0 specification. +thing-type.dsmr.electricity_smarty_v1_0.label = Electricity Meter (Smarty V1.0) +thing-type.dsmr.electricity_smarty_v1_0.description = This is an electricity meter that complies to the Luxembourg's Smarty V1.0 specification. +thing-type.dsmr.electricity_smarty_v1_0_austria.label = Electricity Meter Austria +thing-type.dsmr.electricity_smarty_v1_0_austria.description = This is an electricity meter that complies to the Austria's Smarty V1.0 specification. +thing-type.dsmr.electricity_v2_1.label = Electricity Meter (DSMR V2.1) +thing-type.dsmr.electricity_v2_1.description = This is an electricity meter that complies to the DSMR V2.1 specification. +thing-type.dsmr.electricity_v2_2.label = Electricity Meter (DSMR V2.2) +thing-type.dsmr.electricity_v2_2.description = This is an electricity meter that complies to the DSMR V2.2 specification. +thing-type.dsmr.electricity_v3_0.label = Electricity Meter (DSMR V3) +thing-type.dsmr.electricity_v3_0.description = This is an electricity meter that complies to the DSMR V3 specification. +thing-type.dsmr.electricity_v4_0.label = Electricity Meter (DSMR V4.0) +thing-type.dsmr.electricity_v4_0.description = This is an electricity meter that complies to the DSMR V4.0 specification. +thing-type.dsmr.electricity_v4_0_4.label = Electricity Meter (DSMR V4.0.4) +thing-type.dsmr.electricity_v4_0_4.description = This is an electricity meter that complies to the DSMR V4.0.4 specification. +thing-type.dsmr.electricity_v4_2.label = Electricity Meter (DSMR V4.2) +thing-type.dsmr.electricity_v4_2.description = This is an electricity meter that complies to the DSMR V4.2 specification. +thing-type.dsmr.electricity_v5_0.label = Electricity Meter (DSMR V5.0) +thing-type.dsmr.electricity_v5_0.description = This is an electricity meter that complies to the DSMR V5.0 specification. +thing-type.dsmr.gas_ace4000.label = Gas Meter (ACE4000) +thing-type.dsmr.gas_ace4000.description = This is a gas meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.gas_emucs_v1_0.label = Gas Meter (e-MUCS V1.0) +thing-type.dsmr.gas_emucs_v1_0.description = This is a gas meter that complies to the e-MUCS V1.0 specification. +thing-type.dsmr.gas_v2_1.label = Gas Meter (DSMR V2.1) +thing-type.dsmr.gas_v2_1.description = This is a gas meter that complies to the DSMR V2.1 specification. +thing-type.dsmr.gas_v3_0.label = Gas Meter (DSMR V3.0) +thing-type.dsmr.gas_v3_0.description = This is a gas meter that complies to the DSMR V3.0 specification. +thing-type.dsmr.gasv2_2.label = Gas Meter (DSMR V2.2) +thing-type.dsmr.gasv2_2.description = This is a gas meter that complies to the DSMR V2.2 specification. +thing-type.dsmr.generic_v3_0.label = Generic Meter (DSMR V3.0) +thing-type.dsmr.generic_v3_0.description = This is a generic meter that complies to the DSMR V3.0 specification. +thing-type.dsmr.gj_v3_0.label = GJ Meter (DSMR V3.0) +thing-type.dsmr.gj_v3_0.description = This is a Giga Joule meter that complies to the DSMR V3.0 specification. +thing-type.dsmr.gj_v4.label = GJ Meter (DSMR V4.x) +thing-type.dsmr.gj_v4.description = This is a Giga Joule meter that complies to the DSMR V4.x specification. +thing-type.dsmr.gj_v5_0.label = GJ Meter (DSMR V5.0) +thing-type.dsmr.gj_v5_0.description = This is a Giga Joule meter that complies to the DSMR V5.0 specification. +thing-type.dsmr.heating_ace4000.label = Heating Meter (ACE4000) +thing-type.dsmr.heating_ace4000.description = This is a heating meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.heating_v2_2.label = Heating Meter (DSMR V2.2) +thing-type.dsmr.heating_v2_2.description = This is a heating meter that complies to the DSMR V2.2 specification. +thing-type.dsmr.m3_v4.label = M3 Meter (DSMR V4.x) +thing-type.dsmr.m3_v4.description = This is a m3 meter that complies to the DSMR V4.x specification. +thing-type.dsmr.m3_v5_0.label = M3 Meter (DSMR V5.0) +thing-type.dsmr.m3_v5_0.description = This is a m3 meter that complies to the DSMR V5.0 specification. +thing-type.dsmr.slave_electricity1_ace4000.label = Slave Electricity Meter 1 (ACE4000) +thing-type.dsmr.slave_electricity1_ace4000.description = This is the first slave electricity meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.slave_electricity2_ace4000.label = Slave Electricity Meter 2 (ACE4000) +thing-type.dsmr.slave_electricity2_ace4000.description = This is the second slave electricity meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.slave_electricity_v4.label = Slave Electricity Meter (DSMR V4.x) +thing-type.dsmr.slave_electricity_v4.description = This is the slave electricity meter that complies to the DSMR 4.x specification. +thing-type.dsmr.slave_electricity_v5.label = Slave Electricity Meter (DSMR V5.x) +thing-type.dsmr.slave_electricity_v5.description = This is the slave electricity meter that complies to the DSMR 5.x specification. +thing-type.dsmr.smartyBridge.label = Smarty Meter +thing-type.dsmr.smartyBridge.description = The Luxembourgian Smart Meter 'Smarty' +thing-type.dsmr.water_ace4000.label = Water Meter (ACE4000) +thing-type.dsmr.water_ace4000.description = This is a water meter that complies to the ACE4000 GTMM Mk3 specification. +thing-type.dsmr.water_v2_2.label = Water Meter (DSMR V2.2) +thing-type.dsmr.water_v2_2.description = This is a water meter that complies to the DSMR V2.2 specification. +thing-type.dsmr.water_v3_0.label = Water Meter (DSMR V3.0) +thing-type.dsmr.water_v3_0.description = This is a water meter that complies to the DSMR V3.0 specification. + +# thing types config + +thing-type.config.dsmr.bridgesettings.baudrate.label = Baud Rate +thing-type.config.dsmr.bridgesettings.baudrate.description = Set the baud rate in case auto detect fails. +thing-type.config.dsmr.bridgesettings.baudrate.option.4800 = 4800 +thing-type.config.dsmr.bridgesettings.baudrate.option.9600 = 9600 +thing-type.config.dsmr.bridgesettings.baudrate.option.19200 = 19200 +thing-type.config.dsmr.bridgesettings.baudrate.option.38400 = 38400 +thing-type.config.dsmr.bridgesettings.baudrate.option.57600 = 57600 +thing-type.config.dsmr.bridgesettings.baudrate.option.115200 = 115200 +thing-type.config.dsmr.bridgesettings.databits.label = Data Bits +thing-type.config.dsmr.bridgesettings.databits.description = Set the data bits in case auto detect fails. +thing-type.config.dsmr.bridgesettings.databits.option.5 = 5 +thing-type.config.dsmr.bridgesettings.databits.option.6 = 6 +thing-type.config.dsmr.bridgesettings.databits.option.7 = 7 +thing-type.config.dsmr.bridgesettings.databits.option.8 = 8 +thing-type.config.dsmr.bridgesettings.parity.label = Parity +thing-type.config.dsmr.bridgesettings.parity.description = Set the parity in case auto detect fails. +thing-type.config.dsmr.bridgesettings.parity.option.E = E(ven) +thing-type.config.dsmr.bridgesettings.parity.option.O = O(dd) +thing-type.config.dsmr.bridgesettings.parity.option.N = N(ormal) +thing-type.config.dsmr.bridgesettings.receivedTimeout.label = Received Timeout +thing-type.config.dsmr.bridgesettings.receivedTimeout.description = The time period within results are expected in seconds +thing-type.config.dsmr.bridgesettings.serialPort.label = Serial Port +thing-type.config.dsmr.bridgesettings.serialPort.description = The serial port where the P1 port of the Smart Meter is connected (e.g. Linux: /dev/ttyUSB0, Windows: COM1) +thing-type.config.dsmr.bridgesettings.stopbits.label = Stop Bits +thing-type.config.dsmr.bridgesettings.stopbits.description = Set the stop bits in case auto detect fails. +thing-type.config.dsmr.bridgesettings.stopbits.option.1 = 1 +thing-type.config.dsmr.bridgesettings.stopbits.option.1.5 = 1.5 +thing-type.config.dsmr.bridgesettings.stopbits.option.2 = 2 +thing-type.config.dsmr.meterdescriptor.channel.label = Channel +thing-type.config.dsmr.meterdescriptor.channel.description = The DSMR-device channel for this meter (M-Bus channel). The binding will auto detect this value. In normal situations it is not necessary to adapt this value. If the auto detection failed or if physical changes are made to the meter setup (changed water, gas, heating) meters it can be necessary to update the M-Bus channel. +thing-type.config.dsmr.meterdescriptor.refresh.label = Refresh +thing-type.config.dsmr.meterdescriptor.refresh.description = The time interval the data is refreshed in seconds +thing-type.config.dsmr.smartybridgesettings.decryptionKey.label = Decryption Key +thing-type.config.dsmr.smartybridgesettings.decryptionKey.description = The Luxembourgian Smart meter decryption key. Ask for your energy grid operator for your Smart meter P1 key. +thing-type.config.dsmr.smartybridgesettings.receivedTimeout.label = Received Timeout +thing-type.config.dsmr.smartybridgesettings.receivedTimeout.description = The time period within results are expected in seconds +thing-type.config.dsmr.smartybridgesettings.serialPort.label = Serial Port +thing-type.config.dsmr.smartybridgesettings.serialPort.description = The serial port where the P1 port of the Smart Meter is connected (e.g. Linux: /dev/ttyUSB0, Windows: COM1) + +# channel types + +channel-type.dsmr.activeImportPowerType.label = Aggregate Active Import Power +channel-type.dsmr.activeImportPowerType.description = The aggregate active import power. +channel-type.dsmr.activeThresholdSmax.label = Active Threshold +channel-type.dsmr.activeThresholdSmax.description = Active threshold (SMAX). +channel-type.dsmr.actualDeliveryType.label = Actual Power Delivery +channel-type.dsmr.actualDeliveryType.description = The current power delivery. +channel-type.dsmr.actualFuseThresholdAType.label = Actual Fuse Threshold +channel-type.dsmr.actualFuseThresholdAType.description = The actual fuse threshold. +channel-type.dsmr.actualProductionType.label = Actual Power Production +channel-type.dsmr.actualProductionType.description = The current power production. +channel-type.dsmr.actualReactiveDeliveryType.label = Actual Reactive Power Delivery +channel-type.dsmr.actualReactiveDeliveryType.description = The current reactive power delivery. +channel-type.dsmr.actualReactiveProductionType.label = Actual Reactive Power Production +channel-type.dsmr.actualReactiveProductionType.description = The current reactive power production. +channel-type.dsmr.actualTresholdAType.label = Actual Threshold Current +channel-type.dsmr.actualTresholdAType.description = The actual threshold. +channel-type.dsmr.actualTresholdkWType.label = Actual Threshold +channel-type.dsmr.actualTresholdkWType.description = The actual threshold. +channel-type.dsmr.coolingValueType.label = Cooling Delivery (GJ) +channel-type.dsmr.coolingValueType.description = The total amount of cooling used. +channel-type.dsmr.deliveryTariff0AntiFraudType.label = Delivery Tariff 0 +channel-type.dsmr.deliveryTariff0AntiFraudType.description = The total amount of electricity used for tariff 0 (anti fraud). +channel-type.dsmr.deliveryTariff0Type.label = Delivery Tariff 0 +channel-type.dsmr.deliveryTariff0Type.description = The total amount of electricity used for tariff 0. +channel-type.dsmr.deliveryTariff1AntiFraudType.label = Delivery Tariff 1 +channel-type.dsmr.deliveryTariff1AntiFraudType.description = The total amount of electricity used for tariff 1 (anti fraud). +channel-type.dsmr.deliveryTariff1BelgiumType.label = Delivery Tariff 1 +channel-type.dsmr.deliveryTariff1BelgiumType.description = The total amount of electricity used for tariff 1. +channel-type.dsmr.deliveryTariff1Type.label = Delivery Tariff 1 +channel-type.dsmr.deliveryTariff1Type.description = The total amount of electricity used for tariff 1. +channel-type.dsmr.deliveryTariff2AntiFraudType.label = Delivery Tariff 2 +channel-type.dsmr.deliveryTariff2AntiFraudType.description = The total amount of electricity used for tariff 2 (anti fraud). +channel-type.dsmr.deliveryTariff2BelgiumType.label = Delivery Tariff 2 +channel-type.dsmr.deliveryTariff2BelgiumType.description = The total amount of electricity used for tariff 2. +channel-type.dsmr.deliveryTariff2Type.label = Delivery Tariff 2 +channel-type.dsmr.deliveryTariff2Type.description = The total amount of electricity used for tariff 2. +channel-type.dsmr.deliveryType.label = Delivery +channel-type.dsmr.deliveryType.description = The total amount of electricity used. +channel-type.dsmr.deviceType.label = Device Type +channel-type.dsmr.deviceType.description = The meter device type. +channel-type.dsmr.equipmentIdType.label = Equipment ID +channel-type.dsmr.equipmentIdType.description = Equipment identifier of the device. +channel-type.dsmr.gasCompensatedDelivery24HType.label = Compensated Gas Delivery 24 Hour +channel-type.dsmr.gasCompensatedDelivery24HType.description = The total compensated amount of gas used in the past 24 hour. +channel-type.dsmr.gasDelivery24HType.label = Gas Delivery 24 Hour +channel-type.dsmr.gasDelivery24HType.description = The total amount of gas used in the past 24 hour. +channel-type.dsmr.gasDeliveryType.label = Gas Delivery +channel-type.dsmr.gasDeliveryType.description = The total amount used in the past period. +channel-type.dsmr.gasLastDeliveryType.label = Gas Delivery +channel-type.dsmr.gasLastDeliveryType.description = Last value of not temperature corrected gas volume. +channel-type.dsmr.gasLastTimestampType.label = Timestamp +channel-type.dsmr.gasLastTimestampType.description = Timestamp of the last gas meter capture time. +channel-type.dsmr.gasValvePositionType.label = Gas Valve Position +channel-type.dsmr.gasValvePositionType.description = The gas valve switch position. +channel-type.dsmr.genValueType.label = Delivery +channel-type.dsmr.genValueType.description = The total amount delivered in the past period. +channel-type.dsmr.genValvePositionType.label = Valve Position +channel-type.dsmr.genValvePositionType.description = The valve switch position. +channel-type.dsmr.gjValueType.label = Delivery +channel-type.dsmr.gjValueType.description = The total amount delivered in the past period. +channel-type.dsmr.gjValvePositionType.label = Valve Position +channel-type.dsmr.gjValvePositionType.description = The valve switch position. +channel-type.dsmr.heatingValueType.label = Heating Delivery +channel-type.dsmr.heatingValueType.description = The total amount of heating used in the past period. +channel-type.dsmr.instantCurrentL1Type.label = Instant Current L1 +channel-type.dsmr.instantCurrentL1Type.description = The instant current L1. +channel-type.dsmr.instantCurrentL2Type.label = Instant Current L2 +channel-type.dsmr.instantCurrentL2Type.description = The instant current L2. +channel-type.dsmr.instantCurrentL3Type.label = Instant Current L3 +channel-type.dsmr.instantCurrentL3Type.description = The instant current L3. +channel-type.dsmr.instantPowerDeliveryL1Type.label = Instant Power Delivery L1 +channel-type.dsmr.instantPowerDeliveryL1Type.description = The instant power delivery L1. +channel-type.dsmr.instantPowerDeliveryL2Type.label = Instant Power Delivery L2 +channel-type.dsmr.instantPowerDeliveryL2Type.description = The instant power delivery L2. +channel-type.dsmr.instantPowerDeliveryL3Type.label = Instant Power Delivery L3 +channel-type.dsmr.instantPowerDeliveryL3Type.description = The instant power delivery L3. +channel-type.dsmr.instantPowerProductionL1Type.label = Instant Power Production L1 +channel-type.dsmr.instantPowerProductionL1Type.description = The instant power production L1. +channel-type.dsmr.instantPowerProductionL2Type.label = Instant Power Production L2 +channel-type.dsmr.instantPowerProductionL2Type.description = The instant power production L2. +channel-type.dsmr.instantPowerProductionL3Type.label = Instant Power Production L3 +channel-type.dsmr.instantPowerProductionL3Type.description = The instant power production L3. +channel-type.dsmr.instantReactivePowerDeliveryL1Type.label = Instant Reactive Power Delivery L1 +channel-type.dsmr.instantReactivePowerDeliveryL1Type.description = The instant reactive power delivery L1. +channel-type.dsmr.instantReactivePowerDeliveryL2Type.label = Instant Reactive Power Delivery L2 +channel-type.dsmr.instantReactivePowerDeliveryL2Type.description = The instant reactive power delivery L2. +channel-type.dsmr.instantReactivePowerDeliveryL3Type.label = Instant Reactive Power Delivery L3 +channel-type.dsmr.instantReactivePowerDeliveryL3Type.description = The instant reactive power delivery L3. +channel-type.dsmr.instantReactivePowerProductionL1Type.label = Instant Reactive Power Production L1 +channel-type.dsmr.instantReactivePowerProductionL1Type.description = The instant reactive power production L1. +channel-type.dsmr.instantReactivePowerProductionL2Type.label = Instant Reactive Power Production L2 +channel-type.dsmr.instantReactivePowerProductionL2Type.description = The instant reactive power production L2. +channel-type.dsmr.instantReactivePowerProductionL3Type.label = Instant Reactive Power Production L3 +channel-type.dsmr.instantReactivePowerProductionL3Type.description = The instant reactive power production L3. +channel-type.dsmr.instantVoltageL1Type.label = Instant Voltage L1 +channel-type.dsmr.instantVoltageL1Type.description = The instant voltage L1. +channel-type.dsmr.instantVoltageL2Type.label = Instant Voltage L2 +channel-type.dsmr.instantVoltageL2Type.description = The instant voltage L2. +channel-type.dsmr.instantVoltageL3Type.label = Instant Voltage L3 +channel-type.dsmr.instantVoltageL3Type.description = The instant voltage L3. +channel-type.dsmr.longPowerFailuresType.label = Number of Long Power Failures +channel-type.dsmr.longPowerFailuresType.description = The number of long power failures. +channel-type.dsmr.m3ValueType.label = Delivery +channel-type.dsmr.m3ValueType.description = The total amount delivered in the past period. +channel-type.dsmr.m3ValvePositionType.label = Valve Position +channel-type.dsmr.m3ValvePositionType.description = The valve switch position. +channel-type.dsmr.p1TextCodeType.label = Text Code +channel-type.dsmr.p1TextCodeType.description = Text code from the device. +channel-type.dsmr.p1TextStringType.label = Text Message +channel-type.dsmr.p1TextStringType.description = Text message from the device. +channel-type.dsmr.p1TimestampType.label = Timestamp +channel-type.dsmr.p1TimestampType.description = Timestamp of the last meter reading. +channel-type.dsmr.p1VersionType.label = Version +channel-type.dsmr.p1VersionType.description = Version information for the device output (This mostly refers to the DSMR specification level). +channel-type.dsmr.powerFailureLogDurationType.label = Power Failure Duration +channel-type.dsmr.powerFailureLogDurationType.description = Duration of the power failure. Each entry has its own channel (emeter_power_failure_log_duration*x*, *x* = 0 - 9) +channel-type.dsmr.powerFailureLogEndType.label = Power Failure End +channel-type.dsmr.powerFailureLogEndType.description = Timestamp when the power failure ended. There can be multiple log entries. Each entry has its own channel (emeter_power_failure_log_timestamp*x*, *x* = 0 - 9) +channel-type.dsmr.powerFailureLogEntriesType.label = Power Failure Log Entries +channel-type.dsmr.powerFailureLogEntriesType.description = Number of log entries. +channel-type.dsmr.powerFailuresType.label = Number of Power Failures +channel-type.dsmr.powerFailuresType.description = The number of power failures. +channel-type.dsmr.productionTariff0Type.label = Production Tariff 0 +channel-type.dsmr.productionTariff0Type.description = The total amount of electricity produced for tariff 0. +channel-type.dsmr.productionTariff1BelgiumType.label = Production Tariff 1 +channel-type.dsmr.productionTariff1BelgiumType.description = The total amount of electricity produced for tariff 1. +channel-type.dsmr.productionTariff1Type.label = Production Tariff 1 +channel-type.dsmr.productionTariff1Type.description = The total amount of electricity produced for tariff 1. +channel-type.dsmr.productionTariff2BelgiumType.label = Production Tariff 2 +channel-type.dsmr.productionTariff2BelgiumType.description = The total amount of electricity produced for tariff 2. +channel-type.dsmr.productionTariff2Type.label = Production Tariff 2 +channel-type.dsmr.productionTariff2Type.description = The total amount of electricity produced for tariff 2. +channel-type.dsmr.switchPositionType.label = Switch Position +channel-type.dsmr.switchPositionType.description = The switch position. +channel-type.dsmr.tariffIndicatorType.label = Tariff Indicator +channel-type.dsmr.tariffIndicatorType.description = The current tariff indicator. +channel-type.dsmr.totalExportedEnergyRegisterPType.label = Total Exported Energy (P+) +channel-type.dsmr.totalExportedEnergyRegisterPType.description = The total exported energy register (P-). +channel-type.dsmr.totalExportedEnergyRegisterQType.label = Total Exported Energy (Q-) +channel-type.dsmr.totalExportedEnergyRegisterQType.description = The total exported energy register (Q-). +channel-type.dsmr.totalExportedEnergyRegisterRRate1Type.label = Total Exported Energy R1 +channel-type.dsmr.totalExportedEnergyRegisterRRate1Type.description = The total exported energy register R Rate1. +channel-type.dsmr.totalExportedEnergyRegisterRRate2Type.label = Total Exported Energy R +channel-type.dsmr.totalExportedEnergyRegisterRRate2Type.description = The total exported energy register R Rate2. +channel-type.dsmr.totalImportedEnergyRegisterPType.label = Total Imported Energy (P+) +channel-type.dsmr.totalImportedEnergyRegisterPType.description = The total imported energy register (P+). +channel-type.dsmr.totalImportedEnergyRegisterQType.label = Total Imported Energy (Q+) +channel-type.dsmr.totalImportedEnergyRegisterQType.description = The total imported energy register (Q+). +channel-type.dsmr.totalImportedEnergyRegisterRRate1Type.label = Total Imported Energy R1 +channel-type.dsmr.totalImportedEnergyRegisterRRate1Type.description = The total imported energy register R Rate1. +channel-type.dsmr.totalImportedEnergyRegisterRRate2Type.label = Total Imported Energy R2 +channel-type.dsmr.totalImportedEnergyRegisterRRate2Type.description = The total imported energy register R Rate2. +channel-type.dsmr.voltageSagsL1Type.label = Number of Voltage Sags L1 +channel-type.dsmr.voltageSagsL1Type.description = The number of voltage sags L1. +channel-type.dsmr.voltageSagsL2Type.label = Number of Voltage Sags L2 +channel-type.dsmr.voltageSagsL2Type.description = The number of voltage sags L2. +channel-type.dsmr.voltageSagsL3Type.label = Number of Voltage Sags L3 +channel-type.dsmr.voltageSagsL3Type.description = The number of voltage sags L3. +channel-type.dsmr.voltageSwellsL1Type.label = Number of Voltage Swells L1 +channel-type.dsmr.voltageSwellsL1Type.description = The number of voltage swells L1. +channel-type.dsmr.voltageSwellsL2Type.label = Number of Voltage Swells L2 +channel-type.dsmr.voltageSwellsL2Type.description = The number of voltage swells L2. +channel-type.dsmr.voltageSwellsL3Type.label = Number of Voltage Swells L3 +channel-type.dsmr.voltageSwellsL3Type.description = The number of voltage swells L3. +channel-type.dsmr.waterValueType.label = Water Delivery +channel-type.dsmr.waterValueType.description = The total amount of water used in the past period. +channel-type.dsmr.waterValvePositionType.label = Water Valve Position +channel-type.dsmr.waterValvePositionType.description = The water valve switch position. # meter kind names + meterKind.invalid.label = Invalid Meter meterKind.device.label = Generic DSMR Device meterKind.main_electricity.label = Main Electricity Meter @@ -14,19 +311,14 @@ meterKind.m3.label = M3 Meter meterKind.slave_electricity1.label = Slave Electricity Meter meterKind.slave_electricity2.label = Slave Electricity Meter 2 -# Connector error messages +# connector error messages + error.bridge.nodata = Not receiving data from meter. error.configuration.invalidmetertype = The thing could not be initialized. Delete and re-add thing if the problem persists. error.configuration.invalidsmartykey = The given Smarty decyption key is to short. The decyption key must be 32 characters long. error.thing.nodata = Not receiving data from meter. -error.connector.dont_exists = Serial port does not exist. +error.connector.dont_exists = Serial port does not exist. error.connector.in_use = Serial port is already in use. -error.connector.internal_error = Unexpected error, possible bug. Please report. +error.connector.internal_error = Unexpected error, possible bug. Please report. error.connector.not_compatible = Serial port is not compatible. error.connector.read_error = Read error. - -# thing types -thing-type.dsmr.dsmrBridge.label = Smart Meter -thing-type.dsmr.dsmrBridge.description = The Dutch Smart Meter (DSMR) -thing-type.dsmr.smartyBridge.label = Smarty Meter -thing-type.dsmr.smartyBridge.description = The Luxembourgian Smart Meter 'Smarty' From fa1cab0f1110b0725924281edf4032d5d2561138 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Mon, 6 Dec 2021 18:52:54 +0100 Subject: [PATCH 184/361] Rerun i18n tool (#11721) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/i18n/chromecast.properties | 3 +++ .../src/main/resources/OH-INF/i18n/kodi.properties | 5 +++++ .../main/resources/OH-INF/i18n/logreader.properties | 1 + .../main/resources/OH-INF/i18n/openhabcloud.properties | 10 ++++------ .../main/resources/OH-INF/i18n/googletts.properties | 10 ++++------ 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast.properties b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast.properties index b48a749f03a67..70ad719bc5a9a 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast.properties +++ b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast.properties @@ -38,10 +38,12 @@ channel-type.chromecast.appName.label = App channel-type.chromecast.appName.description = Name of the currently running application channel-type.chromecast.broadcastDate.label = Broadcast Date channel-type.chromecast.broadcastDate.description = The broadcast date of the currently playing media +channel-type.chromecast.broadcastDate.state.pattern = %1$tY-%1$tm-%1$td channel-type.chromecast.composer.label = Composer channel-type.chromecast.composer.description = The composer of the current track channel-type.chromecast.creationDate.label = Creation Date channel-type.chromecast.creationDate.description = The creation date of the currently playing media +channel-type.chromecast.creationDate.state.pattern = %1$tY-%1$tm-%1$td channel-type.chromecast.currentTime.label = Current Time channel-type.chromecast.currentTime.description = Current time of currently playing media channel-type.chromecast.discNumber.label = Disc Number @@ -64,6 +66,7 @@ channel-type.chromecast.playuri.label = Play URI channel-type.chromecast.playuri.description = Plays a given URI channel-type.chromecast.releaseDate.label = Release Date channel-type.chromecast.releaseDate.description = The release date of the currently playing media +channel-type.chromecast.releaseDate.state.pattern = %1$tY-%1$tm-%1$td channel-type.chromecast.seasonNumber.label = Season Number channel-type.chromecast.seasonNumber.description = The season number of the currently playing media channel-type.chromecast.seriesTitle.label = Series Title diff --git a/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties b/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties index b3227c0f3f198..3131ec95ed228 100644 --- a/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties +++ b/bundles/org.openhab.binding.kodi/src/main/resources/OH-INF/i18n/kodi.properties @@ -345,6 +345,11 @@ channel-type.kodi.stop.label = Stop channel-type.kodi.stop.description = Stops the player. ON if the player is stopped. channel-type.kodi.systemcommand.label = Send System Command channel-type.kodi.systemcommand.description = Sends a system command to Kodi. This allows to shutdown/suspend/hibernate/reboot/quit Kodi +channel-type.kodi.systemcommand.command.option.Shutdown = Shutdown +channel-type.kodi.systemcommand.command.option.Suspend = Suspend +channel-type.kodi.systemcommand.command.option.Hibernate = Hibernate +channel-type.kodi.systemcommand.command.option.Reboot = Reboot +channel-type.kodi.systemcommand.command.option.Quit = Quit channel-type.kodi.thumbnail.label = Thumbnail channel-type.kodi.thumbnail.description = The current thumbnail channel-type.kodi.uniqueid.label = UniqueID diff --git a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader.properties b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader.properties index 0fc9c8933e2d1..0008f9e77850a 100644 --- a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader.properties +++ b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader.properties @@ -41,6 +41,7 @@ channel-type.logreader.lastWarningEvent.label = Last Warning Event channel-type.logreader.lastWarningEvent.description = Displays contents of last [WARN] event channel-type.logreader.logRotated.label = Log Rotated channel-type.logreader.logRotated.description = Last time when log rotated recognized +channel-type.logreader.logRotated.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS channel-type.logreader.newCustomEvent.label = New Custom Event channel-type.logreader.newCustomEvent.description = Fires when a new [CUSTOM] appears in the log channel-type.logreader.newErrorEvent.label = New Error Event diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties index cb76d5404a13b..8998a3b824fba 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud.properties @@ -1,9 +1,3 @@ -# service - -service.io.openhabcloud.label = openHAB Cloud - -# bundle config - io.config.openhabcloud.baseURL.label = Base URL io.config.openhabcloud.baseURL.description = Base URL for the openHAB Cloud server. io.config.openhabcloud.expose.label = Items to Expose @@ -12,3 +6,7 @@ io.config.openhabcloud.mode.label = Mode io.config.openhabcloud.mode.description = What features of the openHAB Cloud service should be used. io.config.openhabcloud.mode.option.notification = Notifications io.config.openhabcloud.mode.option.remote = Notifications & Remote Access + +# service + +service.io.openhabcloud.label = openHAB Cloud diff --git a/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts.properties b/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts.properties index c819fd28d9433..651501187ec42 100644 --- a/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts.properties +++ b/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts.properties @@ -1,9 +1,3 @@ -# service - -service.voice.googletts.label = Google Cloud Text-to-Speech - -# bundle config - voice.config.googletts.authcode.label = Authorization Code voice.config.googletts.authcode.description = The auth-code is a one-time code needed to retrieve the necessary access-codes from Google Cloud Platform. Please go to your browser ... https://accounts.google.com/o/oauth2/auth?client_id={{clientId}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/cloud-platform&response_type=code ... to generate an auth-code and paste it here. voice.config.googletts.clientId.label = Client Id @@ -22,3 +16,7 @@ voice.config.googletts.speakingRate.label = Speaking Rate voice.config.googletts.speakingRate.description = Speaking rate can be 4x faster or slower than the normal rate. voice.config.googletts.volumeGain.label = Volume Gain voice.config.googletts.volumeGain.description = Increase the volume of the output by up to 16db or decrease the volume up to -96db. + +# service + +service.voice.googletts.label = Google Cloud Text-to-Speech From 303b8a99749a2f92b2d637ae5dd6e0aad8d87925 Mon Sep 17 00:00:00 2001 From: eugen Date: Mon, 6 Dec 2021 19:11:36 +0100 Subject: [PATCH 185/361] restart HomeKit bridge on network changes (#11720) Signed-off-by: Eugen Freiter Co-authored-by: Eugen Freiter Signed-off-by: Michael Schmidt --- .../io/homekit/internal/HomekitImpl.java | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java index a347c471f229a..f6a38905225f0 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java @@ -33,6 +33,8 @@ import org.openhab.core.io.transport.mdns.MDNSClient; import org.openhab.core.items.ItemRegistry; import org.openhab.core.items.MetadataRegistry; +import org.openhab.core.net.CidrAddress; +import org.openhab.core.net.NetworkAddressChangeListener; import org.openhab.core.net.NetworkAddressService; import org.openhab.core.storage.StorageService; import org.openhab.io.homekit.Homekit; @@ -61,7 +63,7 @@ Constants.SERVICE_PID + "=org.openhab.homekit", "port:Integer=9123" }) @ConfigurableService(category = "io", label = "HomeKit Integration", description_uri = "io:homekit") @NonNullByDefault -public class HomekitImpl implements Homekit { +public class HomekitImpl implements Homekit, NetworkAddressChangeListener { private final Logger logger = LoggerFactory.getLogger(HomekitImpl.class); private final NetworkAddressService networkAddressService; @@ -88,13 +90,14 @@ public HomekitImpl(@Reference StorageService storageService, @Reference ItemRegi this.configAdmin = configAdmin; this.settings = processConfig(properties); this.mdnsClient = mdnsClient; + networkAddressService.addNetworkAddressChangeListener(this); this.changeListener = new HomekitChangeListener(itemRegistry, settings, metadataRegistry, storageService); try { authInfo = new HomekitAuthInfoImpl(storageService.getStorage(HomekitAuthInfoImpl.STORAGE_KEY), settings.pin, settings.setupId); startHomekitServer(); } catch (IOException | InvalidAlgorithmParameterException e) { - logger.warn("Cannot activate HomeKit binding. {}", e.getMessage()); + logger.warn("cannot activate HomeKit binding. {}", e.getMessage()); throw e; } } @@ -107,7 +110,7 @@ private HomekitSettings processConfig(Map properties) { config = configAdmin.getConfiguration(HomekitSettings.CONFIG_PID); props = config.getProperties(); } catch (IOException e) { - logger.warn("Cannot retrieve config admin {}", e.getMessage()); + logger.warn("cannot retrieve config admin {}", e.getMessage()); } if (props == null) { // if null, the configuration is new @@ -133,7 +136,7 @@ private HomekitSettings processConfig(Map properties) { try { config.updateIfDifferent(props); } catch (IOException e) { - logger.warn("Cannot update configuration {}", e.getMessage()); + logger.warn("cannot update configuration {}", e.getMessage()); } } return settings; @@ -158,7 +161,7 @@ protected synchronized void modified(Map config) { startHomekitServer(); } } catch (IOException e) { - logger.warn("Could not initialize HomeKit connector: {}", e.getMessage()); + logger.warn("could not initialize HomeKit bridge: {}", e.getMessage()); } } @@ -185,7 +188,7 @@ private void startBridge() throws IOException { int currentAccessoryCount = changeListener.getAccessories().size(); if (currentAccessoryCount < lastAccessoryCount) { logger.debug( - "It looks like not all items were initialized yet. Old configuration had {} accessories, the current one has only {} accessories. Delay HomeKit bridge start for {} seconds.", + "it looks like not all items were initialized yet. Old configuration had {} accessories, the current one has only {} accessories. Delay HomeKit bridge start for {} seconds.", lastAccessoryCount, currentAccessoryCount, settings.startDelay); scheduler.schedule(() -> { if (currentAccessoryCount < lastAccessoryCount) { @@ -205,17 +208,18 @@ private void startBridge() throws IOException { } private void startHomekitServer() throws IOException { + logger.trace("start HomeKit bridge"); if (homekitServer == null) { if (settings.useOHmDNS) { if ((settings.networkInterface == null) || (settings.networkInterface.isEmpty())) { logger.trace( - "No IP address configured in HomeKit settings. HomeKit will use the first configured address of openHAB"); + "no IP address configured in HomeKit settings. HomeKit will use the first configured address of openHAB"); homekitServer = new HomekitServer(mdnsClient.getClientInstances().iterator().next(), settings.port); } else { networkInterface = InetAddress.getByName(settings.networkInterface); for (JmDNS mdns : mdnsClient.getClientInstances()) { if (mdns.getInetAddress().equals(networkInterface)) { - logger.trace("Suitable mDNS client for IP {} found and will be used for HomeKit", + logger.trace("suitable mDNS client for IP {} found and will be used for HomeKit", networkInterface); homekitServer = new HomekitServer(mdns, settings.port); } @@ -224,9 +228,9 @@ private void startHomekitServer() throws IOException { } if (homekitServer == null) { if (settings.useOHmDNS) { - logger.trace("Not suitable mDNS server for IP {} found", networkInterface); + logger.trace("no suitable mDNS server for IP {} found", networkInterface); } - logger.trace("Create HomeKit server with dedicated mDNS server"); + logger.trace("create HomeKit server with dedicated mDNS server"); homekitServer = new HomekitServer(networkInterface, settings.port); } startBridge(); @@ -236,6 +240,7 @@ private void startHomekitServer() throws IOException { } private void stopHomekitServer() { + logger.trace("stop HomeKit bridge"); final @Nullable HomekitServer homekit = this.homekitServer; if (homekit != null) { if (bridge != null) { @@ -248,6 +253,7 @@ private void stopHomekitServer() { @Deactivate protected void deactivate() { + networkAddressService.removeNetworkAddressChangeListener(this); changeListener.clearAccessories(); stopHomekitServer(); changeListener.stop(); @@ -280,7 +286,18 @@ public void clearHomekitPairings() { authInfo.clear(); refreshAuthInfo(); } catch (Exception e) { - logger.warn("Could not clear HomeKit pairings", e); + logger.warn("could not clear HomeKit pairings", e); + } + } + + @Override + public void onChanged(final List list, final List list1) { + logger.trace("restarting homekit bridge on network interface changes."); + stopHomekitServer(); + try { + startHomekitServer(); + } catch (IOException e) { + logger.warn("could not initialize HomeKit bridge: {}", e.getMessage()); } } } From 8652633656bbbcf378725746fd7f30f73d35e919 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Tue, 7 Dec 2021 09:32:39 +0100 Subject: [PATCH 186/361] Added support for HAN-FUN Color and Dimmable bulbs (#11723) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../org.openhab.binding.avmfritz/README.md | 10 ++-- .../internal/AVMFritzBindingConstants.java | 11 ++++- .../internal/dto/ColorControlModel.java | 34 +++++++++++++ .../avmfritz/internal/dto/HeatingModel.java | 8 ++-- .../handler/AVMFritzBaseBridgeHandler.java | 4 ++ .../handler/AVMFritzBaseThingHandler.java | 14 +++--- .../resources/OH-INF/i18n/avmfritz.properties | 4 ++ .../resources/OH-INF/thing/thing-types.xml | 37 +++++++++++++- .../internal/dto/ColorControlModelTest.java | 48 +++++++++++++++++++ .../AVMFritzDiscoveryServiceOSGiTest.java | 4 +- 10 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java diff --git a/bundles/org.openhab.binding.avmfritz/README.md b/bundles/org.openhab.binding.avmfritz/README.md index 015375899947e..8e1c8251c26c8 100644 --- a/bundles/org.openhab.binding.avmfritz/README.md +++ b/bundles/org.openhab.binding.avmfritz/README.md @@ -92,6 +92,8 @@ The following sensors have been successfully tested using FRITZ!OS 7 for FRITZ!B - [SmartHome Zwischenstecker außen](https://www.smarthome.de/geraete/smarthome-zwischenstecker-aussen-schwarz) - a switchable outdoor outlet (thing type `HAN_FUN_ON_OFF`) - [Rollotron DECT 1213](https://www.rademacher.de/shop/rollladen-sonnenschutz/elektrischer-gurtwickler/rollotron-dect-1213) - an electronic belt winder (thing type `HAN_FUN_BLINDS`) - [Becker BoxCTRL](https://becker-antriebe.shop/) - a radio controlled roller shutter drive (thing type `HAN_FUN_BLINDS`) +- SmartHome LED-Lampe E27 (farbig) - a dimmable colorized light bulb (thing type `HAN_FUN_COLOR_BULB`) +- SmartHome LED-Lampe E27 (warmweiß) - a dimmable light bulb (thing type `HAN_FUN_DIMMABLE_BULB`) The use of other Sensors should be possible, if these are compatible with DECT-ULE / HAN-FUN standards. @@ -177,12 +179,14 @@ The AIN (actor identification number) can be found in the FRITZ!Box interface -> | locked | Contact | Device is locked for switching over external sources (OPEN/CLOSE) | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E, FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT | | device_locked | Contact | Device is locked for switching manually (OPEN/CLOSE) - FRITZ!OS 6.90 | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E, FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT | | temperature | Number:Temperature | Current measured temperature | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!DECT Repeater 100, FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT, FRITZ!DECT 440 | -| humidity | Number:Dimensionless | Current measured humidity - FRITZ!OS 7.24 | FRITZ!DECT 440 | +| humidity | Number:Dimensionless | Current measured humidity - FRITZ!OS 7.24 | FRITZ!DECT 440 | | energy | Number:Energy | Accumulated energy consumption | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E | | power | Number:Power | Current power consumption | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E | | voltage | Number:ElectricPotential | Current voltage - FRITZ!OS 7 | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E | | outlet | Switch | Switchable outlet (ON/OFF) | FRITZ!DECT 210, FRITZ!DECT 200, FRITZ!Powerline 546E | -| on_off | Switch | Switchable device (ON/OFF) | FRITZ!DECT 500, HAN_FUN_ON_OFF | +| on_off | Switch | Switchable device (ON/OFF) | HAN_FUN_ON_OFF | +| brightness | Dimmer | Dimmable lights | HAN_FUN_DIMMABLE_BULB | +| color | Color | Color lights | FRITZ!DECT 500, HAN_FUN_COLOR_BULB | | actual_temp | Number:Temperature | Current temperature of heating thermostat | FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT | | set_temp | Number:Temperature | Set Temperature of heating thermostat | FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT | | eco_temp | Number:Temperature | Eco Temperature of heating thermostat | FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT | @@ -194,7 +198,7 @@ The AIN (actor identification number) can be found in the FRITZ!Box interface -> | battery_low | Switch | Battery level low (ON/OFF) - FRITZ!OS 6.80 | FRITZ!DECT 301, FRITZ!DECT 300, Comet DECT, FRITZ!DECT 400, FRITZ!DECT 440 | | contact_state | Contact | Contact state information (OPEN/CLOSED). | HAN-FUN contact (e.g. SmartHome Tür-/Fensterkontakt or SmartHome Bewegungsmelder)- FRITZ!OS 7 | | last_change | DateTime | States the last time the button was pressed. | FRITZ!DECT 400, FRITZ!DECT 440, HAN-FUN switch (e.g. SmartHome Wandtaster) - FRITZ!OS 7 | -| rollershutter | Rollershutter | Rollershutter control and status. Accepts UP/DOWN/STOP commands and the opening level in percent. States the opening level in percent. | HAN-FUN blind (e.g. Rolltron DECT 1213) - FRITZ!OS 7 | +| rollershutter | Rollershutter | Rollershutter control and status. Accepts UP/DOWN/STOP commands and the opening level in percent. States the opening level in percent. | HAN-FUN blind (e.g. Rolltron DECT 1213) - FRITZ!OS 7 | ### Triggers diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java index c9c7354e65230..0c30a57e2528f 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java @@ -55,6 +55,8 @@ public class AVMFritzBindingConstants { public static final String DEVICE_HAN_FUN_SWITCH = "HAN_FUN_SWITCH"; public static final String DEVICE_HAN_FUN_ON_OFF = "HAN_FUN_ON_OFF"; public static final String DEVICE_HAN_FUN_BLINDS = "HAN_FUN_BLINDS"; + public static final String DEVICE_HAN_FUN_COLOR_BULB = "HAN_FUN_COLOR_BULB"; + public static final String DEVICE_HAN_FUN_DIMMABLE_BULB = "HAN_FUN_DIMMABLE_BULB"; // List of main group types public static final String GROUP_HEATING = "FRITZ_GROUP_HEATING"; @@ -78,6 +80,10 @@ public class AVMFritzBindingConstants { public static final ThingTypeUID HAN_FUN_SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_SWITCH); public static final ThingTypeUID HAN_FUN_ON_OFF_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_ON_OFF); public static final ThingTypeUID HAN_FUN_BLINDS_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_BLINDS); + public static final ThingTypeUID HAN_FUN_COLOR_BULB_THING_TYPE = new ThingTypeUID(BINDING_ID, + DEVICE_HAN_FUN_COLOR_BULB); + public static final ThingTypeUID HAN_FUN_DIMMABLE_BULB_THING_TYPE = new ThingTypeUID(BINDING_ID, + DEVICE_HAN_FUN_DIMMABLE_BULB); public static final ThingTypeUID GROUP_HEATING_THING_TYPE = new ThingTypeUID(BINDING_ID, GROUP_HEATING); public static final ThingTypeUID GROUP_SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, GROUP_SWITCH); @@ -132,9 +138,9 @@ public class AVMFritzBindingConstants { public static final String CHANNEL_PRESS = "press"; public static final String CHANNEL_LAST_CHANGE = "last_change"; public static final String CHANNEL_ROLLERSHUTTER = "rollershutter"; - public static final String CHANNEL_ON_OFF = "on_off"; public static final String CHANNEL_COLOR = "color"; public static final String CHANNEL_BRIGHTNESS = "brightness"; + public static final String CHANNEL_ON_OFF = "on_off"; // List of all Channel config ids public static final String CONFIG_CHANNEL_TEMP_OFFSET = "offset"; @@ -167,7 +173,8 @@ public class AVMFritzBindingConstants { public static final String MODE_WINDOW_OPEN = "WINDOW_OPEN"; public static final String MODE_UNKNOWN = "UNKNOWN"; - public static final Set SUPPORTED_LIGHTING_THING_TYPES = Set.of(DECT500_THING_TYPE); + public static final Set SUPPORTED_LIGHTING_THING_TYPES = Set.of(DECT500_THING_TYPE, + HAN_FUN_COLOR_BULB_THING_TYPE, HAN_FUN_DIMMABLE_BULB_THING_TYPE); public static final Set SUPPORTED_BUTTON_THING_TYPES_UIDS = Set.of(DECT400_THING_TYPE, DECT440_THING_TYPE, HAN_FUN_SWITCH_THING_TYPE); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java index 37a9522df3eda..9afd0eec3727b 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java @@ -17,6 +17,8 @@ import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; +import org.openhab.core.library.types.PercentType; + /** * See {@link DeviceListModel}. * @@ -26,6 +28,8 @@ @XmlRootElement(name = "colorcontrol") public class ColorControlModel { + private static final double SATURATION_FACTOR = 2.54; + @XmlAttribute(name = "supported_modes") public int supportedModes; @XmlAttribute(name = "current_mode") @@ -34,10 +38,40 @@ public class ColorControlModel { public int saturation; public int temperature; + /** + * Converts a FRITZ!Box value to a percent value. + * + * @param fritzValue The FRITZ!Box value to be converted + * @return The percent value + */ + public static PercentType toPercent(int saturation) { + int saturationInPercent = (int) Math.ceil(saturation / SATURATION_FACTOR); + return restrictToBounds(saturationInPercent); + } + + /** + * Converts a percent value to a FRITZ!Box value. + * + * @param saturationInPercent The percent value to be converted + * @return The FRITZ!Box value + */ + public static int fromPercent(PercentType saturationInPercent) { + return (int) Math.floor(saturationInPercent.intValue() * SATURATION_FACTOR); + } + @Override public String toString() { return new StringBuilder("[supportedModes=").append(supportedModes).append(",currentMode=").append(currentMode) .append(",hue=").append(hue).append(",saturation=").append(saturation).append(",temperature=") .append(temperature).append("]").toString(); } + + private static PercentType restrictToBounds(int percentValue) { + if (percentValue < 0) { + return PercentType.ZERO; + } else if (percentValue > 100) { + return PercentType.HUNDRED; + } + return new PercentType(percentValue); + } } diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java index 21390dc21af63..62d3640c5f8e6 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java @@ -240,12 +240,10 @@ public static BigDecimal fromCelsius(BigDecimal celsiusValue) { } /** - * Converts a celsius value to a FRITZ!Box value. - * Valid celsius values: 8 to 28 °C > 16 to 56 - * 16 <= 8°C, 17 = 8.5°C...... 56 >= 28°C, 254 = ON, 253 = OFF + * Converts a FRITZ!Box value to a celsius value. * - * @param celsiusValue The celsius value to be converted - * @return The FRITZ!Box value + * @param fritzValue The FRITZ!Box value to be converted + * @return The celsius value */ public static BigDecimal toCelsius(BigDecimal fritzValue) { if (fritzValue == null) { diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java index 4656fa79d846b..db9548093658c 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java @@ -329,6 +329,10 @@ public String getThingTypeId(AVMFritzBaseModel device) { } else if (device instanceof DeviceModel && device.isHANFUNUnit()) { if (device.isHANFUNBlinds()) { return DEVICE_HAN_FUN_BLINDS; + } else if (device.isColorLight()) { + return DEVICE_HAN_FUN_COLOR_BULB; + } else if (device.isDimmableLight()) { + return DEVICE_HAN_FUN_DIMMABLE_BULB; } List interfaces = Arrays .asList(((DeviceModel) device).getEtsiunitinfo().getInterfaces().split(",")); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java index 9befbbd8ab782..c587b45ce4fa9 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java @@ -143,9 +143,6 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { if (device.isHeatingThermostat()) { updateHeatingThermostat(device.getHkr()); } - if (device.isHANFUNUnit() && device.isHANFUNOnOff()) { - updateSimpleOnOffUnit(device.getSimpleOnOffUnit()); - } if (device instanceof DeviceModel) { DeviceModel deviceModel = (DeviceModel) device; if (deviceModel.isTemperatureSensor()) { @@ -164,6 +161,8 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { updateColorLight(deviceModel.getColorControlModel(), deviceModel.getLevelControlModel()); } else if (deviceModel.isDimmableLight()) { updateDimmableLight(deviceModel.getLevelControlModel()); + } else if (device.isHANFUNUnit() && device.isHANFUNOnOff()) { + updateSimpleOnOffUnit(device.getSimpleOnOffUnit()); } } } @@ -208,10 +207,9 @@ private void updateColorLight(@Nullable ColorControlModel colorControlModel, @Nullable LevelControlModel levelControlModel) { if (colorControlModel != null && levelControlModel != null) { DecimalType hue = new DecimalType(colorControlModel.hue); - PercentType saturation = new PercentType(colorControlModel.saturation); + PercentType saturation = ColorControlModel.toPercent(colorControlModel.saturation); PercentType brightness = new PercentType(levelControlModel.getLevelPercentage()); updateThingChannelState(CHANNEL_COLOR, new HSBType(hue, saturation, brightness)); - updateThingChannelState(CHANNEL_BRIGHTNESS, brightness); } } @@ -414,10 +412,12 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (command instanceof HSBType) { HSBType hsbType = (HSBType) command; brightness = hsbType.getBrightness().toBigDecimal(); - fritzBox.setHueAndSaturation(ain, hsbType.getHue().intValue(), hsbType.getSaturation().intValue(), - 0); + fritzBox.setHueAndSaturation(ain, hsbType.getHue().intValue(), + ColorControlModel.fromPercent(hsbType.getSaturation()), 0); } else if (command instanceof PercentType) { brightness = ((PercentType) command).toBigDecimal(); + } else if (command instanceof OnOffType) { + fritzBox.setSwitch(ain, OnOffType.ON.equals(command)); } if (brightness != null) { fritzBox.setLevelPercentage(ain, brightness); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties index 3a60e32708cd2..5a2944b867237 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties @@ -39,8 +39,12 @@ thing-type.avmfritz.FRITZ_Powerline_546E_Solo.label = FRITZ!Powerline 546E thing-type.avmfritz.FRITZ_Powerline_546E_Solo.description = A FRITZ!Powerline 546E with switchable outlet in stand-alone mode. thing-type.avmfritz.HAN_FUN_BLINDS.label = HAN-FUN Blinds thing-type.avmfritz.HAN_FUN_BLINDS.description = HAN-FUN blinds (e.g. RolloTron DECT 1213) +thing-type.avmfritz.HAN_FUN_COLOR_BULB.label = HAN-FUN Color Light +thing-type.avmfritz.HAN_FUN_COLOR_BULB.description = HAN-FUN color light (e.g SmartHome LED-Lampe E27 (farbig)). thing-type.avmfritz.HAN_FUN_CONTACT.label = HAN-FUN Contact thing-type.avmfritz.HAN_FUN_CONTACT.description = HAN-FUN contact (e.g. SmartHome Tür-/Fensterkontakt or SmartHome Bewegungsmelder). +thing-type.avmfritz.HAN_FUN_DIMMABLE_BULB.label = HAN-FUN Dimmable Light +thing-type.avmfritz.HAN_FUN_DIMMABLE_BULB.description = HAN-FUN dimmable light (e.g. SmartHome LED-Lampe E27 (warmweiß)). thing-type.avmfritz.HAN_FUN_ON_OFF.label = HAN-FUN On / Off Device thing-type.avmfritz.HAN_FUN_ON_OFF.description = HAN-FUN switchable device (e.g. SmartHome Zwischenstecker innen / SmartHome Zwischenstecker außen) thing-type.avmfritz.HAN_FUN_SWITCH.label = HAN-FUN Switch diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml index 291ca23f16048..8ff4a8e806e7b 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml @@ -14,8 +14,6 @@ FRITZ!DECT500 color light. - - @@ -314,6 +312,41 @@ + + + + + + + HAN-FUN color light (e.g SmartHome LED-Lampe E27 (farbig)). + + + + + + ain + + + + + + + + + + + + HAN-FUN dimmable light (e.g. SmartHome LED-Lampe E27 (warmweiß)). + + + + + + ain + + + + diff --git a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java new file mode 100644 index 0000000000000..a2076f4c2d34d --- /dev/null +++ b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.avmfritz.internal.dto; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.core.library.types.PercentType; + +/** + * Tests for {@link ColorControlModel} methods. + * + * @author Christoph Weitkamp - Initial contribution + */ +@NonNullByDefault +class ColorControlModelTest { + + @Test + public void testColorControlModelSaturationConversionIsBijective() { + for (int percent = 0; percent <= 100; ++percent) { + PercentType percentType = new PercentType(percent); + int saturation = ColorControlModel.fromPercent(percentType); + assertThat(ColorControlModel.toPercent(saturation).intValue(), is(percent)); + } + } + + @Test + public void hsbSaturationAlwaysGreaterThanZero() { + // a saturation greater than 1 should result in a percentage greater than 1 + for (int saturation = 1; saturation <= 254; ++saturation) { + PercentType percentType = ColorControlModel.toPercent(saturation); + assertTrue(ColorControlModel.fromPercent(percentType) > 0); + } + } +} diff --git a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java index ce927e9a6f5db..44907df305c9b 100644 --- a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java +++ b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java @@ -89,7 +89,7 @@ public void cleanUp() { @Test public void correctSupportedTypes() { - assertEquals(16, discovery.getSupportedThingTypes().size()); + assertEquals(18, discovery.getSupportedThingTypes().size()); assertTrue(discovery.getSupportedThingTypes().contains(DECT100_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT200_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT210_THING_TYPE)); @@ -104,6 +104,8 @@ public void correctSupportedTypes() { assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_SWITCH_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_ON_OFF_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_BLINDS_THING_TYPE)); + assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_COLOR_BULB_THING_TYPE)); + assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_DIMMABLE_BULB_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(GROUP_HEATING_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(GROUP_SWITCH_THING_TYPE)); } From a6284443e7eb6c56c35ff2434ffc2c1e793f6644 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 7 Dec 2021 12:50:10 +0100 Subject: [PATCH 187/361] [miio] Fix zhimi.airpurifier.vb2 channel unit (#11722) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 4 ++-- .../main/resources/database/zhimi.airpurifier.vb2-miot.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index eb420223503a0..11ef52ce5fc98 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -5043,7 +5043,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | buttom_door | String | Others - Buttom Door | | | reboot_cause | Number | Others - Reboot_cause | Value mapping `["0"="REASON_HW_BOOT","1"="REASON_USER_REBOOT","2"="REASON_UPDATE","3"="REASON_WDT"]` | | manual_level | Number | Others - Manual Level | Value mapping `["1"="level1","2"="level2","3"="level3"]` | -| powertime | Number:duration | Others - Powertime | | +| powertime | Number:Time | Others - Powertime | | | country_code | Number | Others - Country Code | Value mapping `["91"="India","44"="UK","852"="Hong Kong","886"="Taiwan","82"="Korea"]` | ### Smartmi Air Purifier (zhimi.airpurifier.za1) Channels @@ -10759,7 +10759,7 @@ String cola "Others - Cola" (G_airpurifier) {channel="miio:basic:airpurifier:col String buttom_door "Others - Buttom Door" (G_airpurifier) {channel="miio:basic:airpurifier:buttom_door"} Number reboot_cause "Others - Reboot_cause" (G_airpurifier) {channel="miio:basic:airpurifier:reboot_cause"} Number manual_level "Others - Manual Level" (G_airpurifier) {channel="miio:basic:airpurifier:manual_level"} -Number:duration powertime "Others - Powertime" (G_airpurifier) {channel="miio:basic:airpurifier:powertime"} +Number:Time powertime "Others - Powertime" (G_airpurifier) {channel="miio:basic:airpurifier:powertime"} Number country_code "Others - Country Code" (G_airpurifier) {channel="miio:basic:airpurifier:country_code"} ``` diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.vb2-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.vb2-miot.json index 0c8fa644a648f..96a8543029070 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.vb2-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.vb2-miot.json @@ -1041,13 +1041,13 @@ "piid": 8, "friendlyName": "Others - Powertime", "channel": "powertime", - "type": "Number:duration", + "type": "Number:Time", "unit": "seconds", "stateDescription": { "minimum": 0, "maximum": 2147483647, "step": 1, - "pattern": "%.0f", + "pattern": "%.0f %unit%", "readOnly": true }, "refresh": true, From 173adb355d74cfacb64ee16dfd91271c73cbc535 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Tue, 7 Dec 2021 17:47:53 +0100 Subject: [PATCH 188/361] [pollytts] Add default translations properties file (#11728) Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/pollytts.properties | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 bundles/org.openhab.voice.pollytts/src/main/resources/OH-INF/i18n/pollytts.properties diff --git a/bundles/org.openhab.voice.pollytts/src/main/resources/OH-INF/i18n/pollytts.properties b/bundles/org.openhab.voice.pollytts/src/main/resources/OH-INF/i18n/pollytts.properties new file mode 100644 index 0000000000000..c995baca09528 --- /dev/null +++ b/bundles/org.openhab.voice.pollytts/src/main/resources/OH-INF/i18n/pollytts.properties @@ -0,0 +1,34 @@ +voice.config.pollytts.accessKey.label = Access Key +voice.config.pollytts.accessKey.description = The access key part of the AWS credentials. You need to register to get a key. +voice.config.pollytts.audioFormat.label = Audio Format +voice.config.pollytts.audioFormat.description = Allows for overriding the system default audio format. "MP3" and "OGG" are the only audio formats that are supported. +voice.config.pollytts.audioFormat.option.default = Use system default +voice.config.pollytts.audioFormat.option.MP3 = MP3 +voice.config.pollytts.audioFormat.option.OGG = OGG +voice.config.pollytts.cacheExpiration.label = Cache Expiration +voice.config.pollytts.cacheExpiration.description = Determines the age in days when unused cached files are purged. Use 0 to disable this functionality. +voice.config.pollytts.secretKey.label = Secret Key +voice.config.pollytts.secretKey.description = The secret key part of the AWS credentials. You need to register to get a key. +voice.config.pollytts.serviceRegion.label = Service Region +voice.config.pollytts.serviceRegion.description = The service region used for accessing Polly. To reduce latency select the region closest to you. +voice.config.pollytts.serviceRegion.option.ap-south-1 = Asia Pacific (Mumbai) +voice.config.pollytts.serviceRegion.option.ap-northeast-2 = Asia Pacific (Seoul) +voice.config.pollytts.serviceRegion.option.ap-southeast-1 = Asia Pacific (Singapore) +voice.config.pollytts.serviceRegion.option.ap-southeast-2 = Asia Pacific (Sydney) +voice.config.pollytts.serviceRegion.option.ap-northeast-1 = Asia Pacific (Tokyo) +voice.config.pollytts.serviceRegion.option.us-gov-west-1 = AWS GovCloud (US) +voice.config.pollytts.serviceRegion.option.ca-central-1 = Canada (Central) +voice.config.pollytts.serviceRegion.option.cn-northwest-1 = China (Ningxia) +voice.config.pollytts.serviceRegion.option.eu-central-1 = EU (Frankfurt) +voice.config.pollytts.serviceRegion.option.eu-west-1 = EU (Ireland) +voice.config.pollytts.serviceRegion.option.eu-west-2 = EU (London) +voice.config.pollytts.serviceRegion.option.eu-west-3 = EU (Paris) +voice.config.pollytts.serviceRegion.option.sa-east-1 = South America (São Paulo) +voice.config.pollytts.serviceRegion.option.us-east-1 = US East (N. Virginia) +voice.config.pollytts.serviceRegion.option.us-east-2 = US East (Ohio) +voice.config.pollytts.serviceRegion.option.us-west-1 = US West (N. California) +voice.config.pollytts.serviceRegion.option.us-west-2 = US West (Oregon) + +# service + +service.voice.pollytts.label = Polly Text-to-Speech From 83a73443c994437bac1f971d592a4e2752282ce9 Mon Sep 17 00:00:00 2001 From: Bob A Date: Tue, 7 Dec 2021 15:17:11 -0500 Subject: [PATCH 189/361] [lutron] Explicitly enable proper monitoring types for HomeWorks connections (#11726) * [lutron] Set default monitoring types for HomeWorks Signed-off-by: Bob Adair Signed-off-by: Michael Schmidt --- .../internal/handler/IPBridgeHandler.java | 20 +++--- .../internal/protocol/lip/Monitoring.java | 62 +++++++++++++++++++ 2 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/lip/Monitoring.java diff --git a/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/IPBridgeHandler.java b/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/IPBridgeHandler.java index 61c6cf4e9bae7..d5fb1b9c16c97 100644 --- a/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/IPBridgeHandler.java +++ b/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/handler/IPBridgeHandler.java @@ -33,6 +33,7 @@ import org.openhab.binding.lutron.internal.protocol.LutronCommandNew; import org.openhab.binding.lutron.internal.protocol.lip.LutronCommandType; import org.openhab.binding.lutron.internal.protocol.lip.LutronOperation; +import org.openhab.binding.lutron.internal.protocol.lip.Monitoring; import org.openhab.binding.lutron.internal.protocol.lip.TargetType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; @@ -57,11 +58,6 @@ public class IPBridgeHandler extends LutronBridgeHandler { private static final String DB_UPDATE_DATE_FORMAT = "MM/dd/yyyy HH:mm:ss"; - private static final Integer MONITOR_PROMPT = 12; - private static final Integer MONITOR_SYSVAR = 10; - private static final Integer MONITOR_ENABLE = 1; - private static final Integer MONITOR_DISABLE = 2; - private static final Integer SYSTEM_DBEXPORTDATETIME = 10; private static final int MAX_LOGIN_ATTEMPTS = 2; @@ -208,8 +204,9 @@ private synchronized void connect() { // Disable prompts sendCommand(new LIPCommand(TargetType.BRIDGE, LutronOperation.EXECUTE, LutronCommandType.MONITORING, null, - MONITOR_PROMPT, MONITOR_DISABLE)); + Monitoring.PROMPT, Monitoring.ACTION_DISABLE)); + initMonitoring(); if (requireSysvarMonitoring.get()) { setSysvarMonitoring(true); } @@ -457,10 +454,17 @@ private void scanForDevices() { } } + private void initMonitoring() { + for (Integer monitorType : Monitoring.REQUIRED_SET) { + sendCommand(new LIPCommand(TargetType.BRIDGE, LutronOperation.EXECUTE, LutronCommandType.MONITORING, null, + monitorType, Monitoring.ACTION_ENABLE)); + } + } + private void setSysvarMonitoring(boolean enable) { - Integer setting = (enable) ? MONITOR_ENABLE : MONITOR_DISABLE; + Integer setting = (enable) ? Monitoring.ACTION_ENABLE : Monitoring.ACTION_DISABLE; sendCommand(new LIPCommand(TargetType.BRIDGE, LutronOperation.EXECUTE, LutronCommandType.MONITORING, null, - MONITOR_SYSVAR, setting)); + Monitoring.SYSVAR, setting)); } @Override diff --git a/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/lip/Monitoring.java b/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/lip/Monitoring.java new file mode 100644 index 0000000000000..948e9fc66745f --- /dev/null +++ b/bundles/org.openhab.binding.lutron/src/main/java/org/openhab/binding/lutron/internal/protocol/lip/Monitoring.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.lutron.internal.protocol.lip; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link Monitoring} class defines constants for LIP Monitoring types + * + * @author Bob Adair - Initial contribution + */ +@NonNullByDefault +public class Monitoring { + // Monitoring Actions + public static final Integer ACTION_ENABLE = 1; + public static final Integer ACTION_DISABLE = 2; + + // Monitoring Types + public static final Integer DIAG = 1; + public static final Integer EVENT = 2; + public static final Integer BUTTON = 3; + public static final Integer LED = 4; + public static final Integer ZONE = 5; + public static final Integer OCCUPANCY = 6; + public static final Integer PHOTOSENSOR = 7; + public static final Integer SCENE = 8; + public static final Integer TIMECLOCK = 9; + public static final Integer SYSVAR = 10; + public static final Integer REPLY = 11; + public static final Integer PROMPT = 12; + public static final Integer DEVICE = 14; + public static final Integer ADDRESS = 15; + public static final Integer SEQUENCE = 16; + public static final Integer HVAC = 17; + public static final Integer MODE = 18; + public static final Integer PRESET = 19; + public static final Integer L1RUNTIME = 20; + public static final Integer L2RUNTIME = 21; + public static final Integer DIAGERROR = 22; + public static final Integer SHADEGRP = 23; + public static final Integer PARTITION = 24; + public static final Integer SYSTEM = 25; + public static final Integer SENSORGROUP = 26; + public static final Integer TEMPSENSOR = 27; + public static final Integer ALL = 255; + + /** Set of monitoring types which must be enabled */ + public static final Set REQUIRED_SET = Set.of(BUTTON, LED, ZONE, OCCUPANCY, SCENE, TIMECLOCK, REPLY, HVAC, + MODE); +} From 19ab0f989086a15c99e2243af8887f1b67714ebf Mon Sep 17 00:00:00 2001 From: Matthew Davies <84205523+raveydavies@users.noreply.github.com> Date: Tue, 7 Dec 2021 22:57:41 +0100 Subject: [PATCH 190/361] Update README.md (#11730) Changed FanState channel to Switch and corrected small typing error Signed-off-by: raveydavies Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.venstarthermostat/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.venstarthermostat/README.md b/bundles/org.openhab.binding.venstarthermostat/README.md index 751460a23bd5c..1c5fb1c0981f3 100644 --- a/bundles/org.openhab.binding.venstarthermostat/README.md +++ b/bundles/org.openhab.binding.venstarthermostat/README.md @@ -24,7 +24,7 @@ to enter them in the thermostat configuration in openHAB. ## Discovery -Once the binding is installed it will attempt to auto discovery Venstar thermostats located on the local network. +Once the binding is installed it will attempt to auto discover Venstar thermostats located on the local network. These will appear as Things in the system Inbox. After adding the Inbox item, enter the user name and password from the physical thermostat in the Thing's configuration. @@ -56,7 +56,7 @@ After adding the Inbox item, enter the user name and password from the physical | humidity | Number | Humidity | | | fanMode | String | Fan Mode | | | fanModeRaw | Number | Fan Mode Raw (Read Only) | 0 (Auto) 1 (On) | -| fanState | String | Fan State (Read Only) | | +| fanState | Switch | Fan State (Read Only) | | | fanStateRaw | Number | Fan State Raw (Read Only) | 0 (Off) 1 (On) | | scheduleMode | String | Current Schedule Mode | | | scheduleModeRaw | Number | Current Schedule mode Raw (Read Only) | 0(Disabled) 1(Enabled) | @@ -119,7 +119,7 @@ Number Guest_HVAC_Humidity "Humidity [%d %%]" {channel="ve String Guest_HVAC_State "State [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:systemState"} String Guest_Away_Mode "Away Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:awayMode"} String Guest_Fan_Mode "Fan Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:fanMode"} -String Guest_Fan_State "Fan State [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:fanState"} +Switch Guest_Fan_State "Fan State" {channel="venstarthermostat:colorTouchThermostat:001122334455:fanState"} String Guest_Schedule_Mode "Schedule Mode [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:scheduleMode"} String Guest_Schedule_Part "Schedule Part [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:schedulePart"} DateTime Guest_timestampDay0 "Date/Time Last Update [%s]" {channel="venstarthermostat:colorTouchThermostat:001122334455:timestampDay0"} @@ -144,7 +144,7 @@ sitemap demo label="Venstar Color Thermostat Demo" Switch item=Guest_Away_Mode mappings=[home=Home,away=Away] Text item=Guest_HVAC_State Switch item=Guest_Fan_Mode mappings=[auto=Auto, on=On] - Text item=Guest_Fan_State + Switch item=Guest_Fan_State mappings=[on=On,off=Off] Switch item=Guest_Schedule_Mode mappings=[enabled=Enabled,disabled=Disabled] Text item=Guest_Schedule_Part Text item=Guest_timestampDay0 From 06bff30ba550e58632655e61d2a0c5dfe9b58ef9 Mon Sep 17 00:00:00 2001 From: eugen Date: Wed, 8 Dec 2021 12:14:44 +0100 Subject: [PATCH 191/361] [homekit] add setting to block homekit user/pairing deletion (#11731) * add setting to block homekit user deletion and unpairing * add logging * remove . from settings label Signed-off-by: Eugen Freiter Signed-off-by: Michael Schmidt --- bundles/org.openhab.io.homekit/README.md | 2 ++ .../homekit/internal/HomekitAuthInfoImpl.java | 30 ++++++++++++------- .../io/homekit/internal/HomekitImpl.java | 2 +- .../io/homekit/internal/HomekitSettings.java | 3 ++ .../main/resources/OH-INF/config/config.xml | 5 ++++ 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.io.homekit/README.md b/bundles/org.openhab.io.homekit/README.md index 12a7069ae19ad..833f3f3b397d6 100644 --- a/bundles/org.openhab.io.homekit/README.md +++ b/bundles/org.openhab.io.homekit/README.md @@ -88,6 +88,7 @@ org.openhab.homekit:thermostatTargetModeAuto=Auto org.openhab.homekit:thermostatTargetModeOff=Off org.openhab.homekit:networkInterface=192.168.0.6 org.openhab.homekit:useOHmDNS=false +org.openhab.homekit:blockUserDeletion=false org.openhab.homekit:name=openHAB ``` @@ -98,6 +99,7 @@ org.openhab.homekit:name=openHAB | networkInterface | IP address or domain name under which the HomeKit bridge can be reached. If no value is configured, the add-on uses the first network adapter address configured for openHAB. | (none) | | port | Port under which the HomeKit bridge can be reached. | 9123 | | useOHmDNS | mDNS service is used to advertise openHAB as HomeKit bridge in the network so that HomeKit clients can find it. openHAB has already mDNS service running. This option defines whether the mDNS service of openHAB or a separate service should be used. | false | +| blockUserDeletion | Blocks HomeKit user deletion in openHAB and as result unpairing of devices. If you experience an issue with accessories becoming non-responsive after some time, try to enable this setting. You can also enable this setting if your HomeKit setup is done and you will not re-pair ios devices. | false | | pin | Pin code used for pairing with iOS devices. Apparently, pin codes are provided by Apple and represent specific device types, so they cannot be chosen freely. The pin code 031-45-154 is used in sample applications and known to work. | 031-45-154 | | startDelay | HomeKit start delay in seconds in case the number of accessories is lower than last time. This helps to avoid resetting home app in case not all items have been initialised properly before HomeKit integration start. | 30 | | useFahrenheitTemperature | Set to true to use Fahrenheit degrees, or false to use Celsius degrees. | false | diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitAuthInfoImpl.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitAuthInfoImpl.java index ae164900b5b03..f6da8fe2df309 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitAuthInfoImpl.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitAuthInfoImpl.java @@ -46,22 +46,24 @@ public class HomekitAuthInfoImpl implements HomekitAuthInfo { private byte[] privateKey; private String pin; private String setupId; + private boolean blockUserDeletion; - public HomekitAuthInfoImpl(Storage storage, String pin, String setupId) + public HomekitAuthInfoImpl(Storage storage, String pin, String setupId, boolean blockUserDeletion) throws InvalidAlgorithmParameterException { this.storage = storage; this.pin = pin; this.setupId = setupId; + this.blockUserDeletion = blockUserDeletion; initializeStorage(); } @Override public void createUser(String username, byte[] publicKey) { - logger.trace("Create user {}", username); + logger.trace("create user {}", username); final String userKey = createUserKey(username); final String encodedPublicKey = Base64.getEncoder().encodeToString(publicKey); storage.put(userKey, encodedPublicKey); - logger.trace("Stored user key {} with value {}", userKey, encodedPublicKey); + logger.trace("stored user key {} with value {}", userKey, encodedPublicKey); } @Override @@ -113,8 +115,12 @@ public byte[] getUserPublicKey(String username) { @Override public void removeUser(String username) { - logger.trace("Remove user {}", username); - storage.remove(createUserKey(username)); + logger.trace("remove user {}", username); + if (!this.blockUserDeletion) { + storage.remove(createUserKey(username)); + } else { + logger.debug("deletion of the user was blocked by binding settings"); + } } @Override @@ -124,11 +130,15 @@ public boolean hasUser() { } public void clear() { - logger.trace("Clear all users"); - for (String key : new HashSet<>(storage.getKeys())) { - if (isUserKey(key)) { - storage.remove(key); + logger.trace("clear all users"); + if (!this.blockUserDeletion) { + for (String key : new HashSet<>(storage.getKeys())) { + if (isUserKey(key)) { + storage.remove(key); + } } + } else { + logger.debug("deletion of users information was blocked by binding settings"); } } @@ -146,7 +156,7 @@ private void initializeStorage() throws InvalidAlgorithmParameterException { final @Nullable Object privateKeyConfig = storage.get(STORAGE_PRIVATE_KEY); if (mac == null) { logger.warn( - "Could not find existing MAC in {}. Generating new MAC. This will require re-pairing of iOS devices.", + "could not find existing MAC in {}. Generating new MAC. This will require re-pairing of iOS devices.", storage.getClass().getName()); mac = HomekitServer.generateMac(); storage.put(STORAGE_MAC, mac); diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java index f6a38905225f0..9e04d135280c4 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitImpl.java @@ -94,7 +94,7 @@ public HomekitImpl(@Reference StorageService storageService, @Reference ItemRegi this.changeListener = new HomekitChangeListener(itemRegistry, settings, metadataRegistry, storageService); try { authInfo = new HomekitAuthInfoImpl(storageService.getStorage(HomekitAuthInfoImpl.STORAGE_KEY), settings.pin, - settings.setupId); + settings.setupId, settings.blockUserDeletion); startHomekitServer(); } catch (IOException | InvalidAlgorithmParameterException e) { logger.warn("cannot activate HomeKit binding. {}", e.getMessage()); diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java index 5f040fa003f3b..fdeb303fd316e 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitSettings.java @@ -32,6 +32,7 @@ public class HomekitSettings { public int startDelay = 30; public boolean useFahrenheitTemperature = false; public boolean useOHmDNS = false; + public boolean blockUserDeletion = false; public String thermostatTargetModeHeat = "HeatOn"; public String thermostatTargetModeCool = "CoolOn"; public String thermostatTargetModeAuto = "Auto"; @@ -81,6 +82,8 @@ public boolean equals(Object obj) { } } else if (!useOHmDNS != other.useOHmDNS) { return false; + } else if (!blockUserDeletion != other.blockUserDeletion) { + return false; } else if (!pin.equals(other.pin)) { return false; } else if (!setupId.equals(other.setupId)) { diff --git a/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/config/config.xml index b13659889eb7a..16d0a6905e64c 100644 --- a/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/config/config.xml @@ -116,5 +116,10 @@ Defines whether mDNS service of openHAB or a separate instance of mDNS should be used. false + + + Block deletion of the HomeKit user information from openHAB and the unpairing of devices + false + From 8748a9f15add3a09d5e9632098729b43971f5d91 Mon Sep 17 00:00:00 2001 From: Stewart Cossey Date: Thu, 9 Dec 2021 21:00:18 +1300 Subject: [PATCH 192/361] Change status channel from hash map values to state description options. (#11739) Signed-off-by: Stewart Cossey Signed-off-by: Michael Schmidt --- .../internal/api/HPProductUsageFeatures.java | 2 +- .../hpprinter/internal/api/HPStatus.java | 21 +------------------ .../resources/OH-INF/thing/channel-types.xml | 14 ++++++++++++- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPProductUsageFeatures.java b/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPProductUsageFeatures.java index 41207f4598706..24ba4e77cd439 100644 --- a/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPProductUsageFeatures.java +++ b/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPProductUsageFeatures.java @@ -65,7 +65,7 @@ public HPProductUsageFeatures(final Document document) { final String inkName = currInk.getElementsByTagName("dd:MarkerColor").item(0).getTextContent(); final String consumeType = currInk.getElementsByTagName("dd:ConsumableTypeEnum").item(0).getTextContent(); - if (consumeType.equalsIgnoreCase("printhead")) { + if ("printhead".equalsIgnoreCase(consumeType)) { continue; } diff --git a/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPStatus.java b/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPStatus.java index 19773d6eba057..c9b9c8686b33a 100644 --- a/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPStatus.java +++ b/bundles/org.openhab.binding.hpprinter/src/main/java/org/openhab/binding/hpprinter/internal/api/HPStatus.java @@ -12,9 +12,6 @@ */ package org.openhab.binding.hpprinter.internal.api; -import java.util.HashMap; -import java.util.Map; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.w3c.dom.Document; @@ -30,8 +27,6 @@ public class HPStatus { public static final String ENDPOINT = "/DevMgmt/ProductStatusDyn.xml"; - private static final Map STATUS_MESSAGES = initializeStatus(); - private final String printerStatus; private final boolean trayEmptyOrOpen; @@ -44,7 +39,7 @@ public HPStatus(Document document) { Element element = (Element) nodes.item(i); String statusCategory = element.getElementsByTagName("pscat:StatusCategory").item(0).getTextContent(); if (!"genuineHP".equals(statusCategory) && !"trayEmpty".equals(statusCategory)) { - localPrinterStatus = STATUS_MESSAGES.getOrDefault(statusCategory, statusCategory); + localPrinterStatus = statusCategory; } if ("trayEmpty".equals(statusCategory)) { localTrayEmptyOrOpen = true; @@ -54,20 +49,6 @@ public HPStatus(Document document) { printerStatus = localPrinterStatus; } - private static Map initializeStatus() { - Map statusMap = new HashMap<>(); - - statusMap.put("processing", "Printing..."); - statusMap.put("scanProcessing", "Scanning..."); - statusMap.put("inPowerSave", "Power Save"); - statusMap.put("ready", "Idle"); - statusMap.put("initializing", "Initializing..."); - statusMap.put("closeDoorOrCover", "Door/Cover Open"); - statusMap.put("inkSystemInitializing", "Loading Ink..."); - statusMap.put("shuttingDown", "Shutting Down..."); - return statusMap; - } - public boolean getTrayEmptyOrOpen() { return trayEmptyOrOpen; } diff --git a/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/thing/channel-types.xml b/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/thing/channel-types.xml index 72054a69be92e..a628b51010b2e 100644 --- a/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/thing/channel-types.xml +++ b/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/thing/channel-types.xml @@ -35,7 +35,19 @@ String Printer Status - + + + + + + + + + + + + + From 2884d1ca67c781a8875f47d114707458905c2e4a Mon Sep 17 00:00:00 2001 From: Stewart Cossey Date: Fri, 10 Dec 2021 00:35:29 +1300 Subject: [PATCH 193/361] Fix smart water alert level. (#11734) Signed-off-by: Stewart Cossey Signed-off-by: Michael Schmidt --- .../binding/nzwateralerts/internal/api/SmartWater.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.nzwateralerts/src/main/java/org/openhab/binding/nzwateralerts/internal/api/SmartWater.java b/bundles/org.openhab.binding.nzwateralerts/src/main/java/org/openhab/binding/nzwateralerts/internal/api/SmartWater.java index 9d4b9c590d39c..4f09393fe6446 100644 --- a/bundles/org.openhab.binding.nzwateralerts/src/main/java/org/openhab/binding/nzwateralerts/internal/api/SmartWater.java +++ b/bundles/org.openhab.binding.nzwateralerts/src/main/java/org/openhab/binding/nzwateralerts/internal/api/SmartWater.java @@ -36,7 +36,7 @@ public class SmartWater implements WaterWebService { private static final String REGION_WAIKATO = "/alert-levels/waikato-district-council"; private static final String REGION_WAIPA = "/alert-levels/waipa-district-council"; - private static final String PATTERN = "/assets/Alert-Level-Images/water-alert-([1-4]|no)-large.svg.*?"; + private static final String PATTERN = "/assets/Alert-Level-Images/(?:water-alert-([1-4]|no)-large|(save)-wai-logo).svg.*?"; private static final Pattern REGEX = Pattern.compile(PATTERN, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); @@ -66,8 +66,10 @@ public int findWaterLevel(final String data, final String area) { while (matches.find()) { String level = matches.group(1); + final String altMsgs = matches.group(2); + logger.debug("Data Level {}", level); - if (level.equalsIgnoreCase("no")) { + if ("no".equalsIgnoreCase(level) || "save".equalsIgnoreCase(altMsgs)) { logger.debug("Convert Data Level to 0"); level = "0"; } From 7316182a6a5d802968ef7339736ed11cad2a3696 Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Thu, 9 Dec 2021 18:59:18 +0100 Subject: [PATCH 194/361] [nikohomecontrol] Fix dimmer control sequence (#11737) * Fix dimmer control sequence Signed-off-by: Mark Herwege Signed-off-by: Michael Schmidt --- .../nhc2/NikoHomeControlCommunication2.java | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java index 722346fcd74c5..61d407f29ba0e 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java @@ -395,7 +395,7 @@ private void addDevice(NhcDevice2 device) { break; default: actionType = ActionType.GENERIC; - logger.debug("device type {} not recognised, default to GENERIC action", device.type); + logger.debug("device model {} not recognised, default to GENERIC action", device.model); } NhcAction2 nhcAction = new NhcAction2(device.uuid, device.name, device.model, device.technology, @@ -480,23 +480,27 @@ private void updateLightState(NhcAction2 action, List devicePropert booleanState = basicStateProperty.get().basicState; } - if (booleanState != null) { - if (NHCON.equals(booleanState)) { - action.setBooleanState(true); - logger.debug("setting action {} internally to ON", action.getId()); - } else if (NHCOFF.equals(booleanState)) { - action.setBooleanState(false); - logger.debug("setting action {} internally to OFF", action.getId()); - } + if (NHCOFF.equals(booleanState)) { + action.setBooleanState(false); + logger.debug("setting action {} internally to OFF", action.getId()); } if (dimmerProperty.isPresent()) { String brightness = dimmerProperty.get().brightness; if (brightness != null) { - action.setState(Integer.parseInt(brightness)); - logger.debug("setting action {} internally to {}", action.getId(), dimmerProperty.get().brightness); + try { + action.setState(Integer.parseInt(brightness)); + logger.debug("setting action {} internally to {}", action.getId(), dimmerProperty.get().brightness); + } catch (NumberFormatException e) { + logger.debug("received invalid brightness value {} for dimmer {}", brightness, action.getId()); + } } } + + if (NHCON.equals(booleanState)) { + action.setBooleanState(true); + logger.debug("setting action {} internally to ON", action.getId()); + } } private void updateRollershutterState(NhcAction2 action, List deviceProperties) { @@ -505,7 +509,7 @@ private void updateRollershutterState(NhcAction2 action, List devic action.setState(Integer.parseInt(position)); logger.debug("setting action {} internally to {}", action.getId(), position); } catch (NumberFormatException e) { - logger.trace("received empty rollershutter {} position info", action.getId()); + logger.trace("received empty or invalid rollershutter {} position info {}", action.getId(), position); } }); } @@ -615,6 +619,10 @@ public void executeAction(String actionId, String value) { switch (action.getType()) { case GENERIC: case TRIGGER: + if (!NHCON.equals(value)) { + // Only trigger for ON + return; + } property.basicState = NHCTRIGGERED; break; case RELAY: @@ -627,6 +635,17 @@ public void executeAction(String actionId, String value) { } else if (NHCOFF.equals(value)) { property.status = value; } else { + try { + action.setState(Integer.parseInt(value)); // set cached state to new brightness value to avoid + // switching on with old brightness value before + // updating + // to new value + } catch (NumberFormatException e) { + logger.debug("internal error, trying to set invalid brightness value {} for dimmer {}", value, + action.getId()); + return; + } + // If the light is off, turn the light on before sending the brightness value, needs to happen // in 2 separate messages. if (!action.booleanState()) { @@ -643,8 +662,7 @@ public void executeAction(String actionId, String value) { } else if (NHCDOWN.equals(value)) { property.position = "0"; } else { - int position = Integer.parseInt(value); - property.position = String.valueOf(position); + property.position = value; } break; } From 7ecc9aa2b4e1c34dfb76f22603040e855974a9ab Mon Sep 17 00:00:00 2001 From: eugen Date: Fri, 10 Dec 2021 00:20:28 +0100 Subject: [PATCH 195/361] [homekit] make min/max values for Color Temperature configurable (#11717) * make min/max values for ColorTemprature configurable Signed-off-by: Eugen Freiter Signed-off-by: Michael Schmidt --- bundles/org.openhab.io.homekit/README.md | 9 +++- .../homekit/internal/HomekitTaggedItem.java | 11 +++++ .../HomekitCharacteristicFactory.java | 47 +++++++++++-------- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.io.homekit/README.md b/bundles/org.openhab.io.homekit/README.md index 833f3f3b397d6..fa09232265db6 100644 --- a/bundles/org.openhab.io.homekit/README.md +++ b/bundles/org.openhab.io.homekit/README.md @@ -587,7 +587,7 @@ or using UI | | | Hue | Dimmer, Color | Hue | | | | Saturation | Dimmer, Color | Saturation in % (1-100) | | | | Brightness | Dimmer, Color | Brightness in % (1-100). See "Usage of dimmer modes" for configuration details. | -| | | ColorTemperature | Number | NOT WORKING on iOS 14.x. Color temperature which is represented in reciprocal megaKelvin, values - 50 to 400. should not be used in combination with hue, saturation and brightness | +| | | ColorTemperature | Number | Color temperature represented in reciprocal megaKelvin. The default value range is from 50 to 400. Color temperature should not be used in combination with hue, saturation and brightness. It supports following configuration parameters: minValue, maxValue | | Fan | | | | Fan | | | ActiveStatus | | Switch | accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | | | CurrentFanState | Number | current fan state. values: 0=INACTIVE, 1=IDLE, 2=BLOWING AIR | @@ -747,6 +747,13 @@ openhab> log:set TRACE io.github.hapjava openhab> log:tail io.github.hapjava ``` +In order to enable detailed logs of openHAB HomeKit binding + +``` +openhab> log:set TRACE org.openhab.io.homekit.internal +openhab> log:tail org.openhab.io.homekit.internal +``` + ## Console commands `openhab:homekit list` - list all HomeKit accessories currently advertised to the HomeKit clients. diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitTaggedItem.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitTaggedItem.java index 52820f1c00d55..c52d8e481d082 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitTaggedItem.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitTaggedItem.java @@ -220,6 +220,17 @@ public boolean isInverted() { return invertedConfig.equalsIgnoreCase("yes") || invertedConfig.equalsIgnoreCase("true"); } + /** + * return configuration as int if exists otherwise return defaultValue + * + * @param key configuration key + * @param defaultValue default value + * @return value + */ + public int getConfigurationAsInt(String key, int defaultValue) { + return getConfiguration(key, BigDecimal.valueOf(defaultValue)).intValue(); + } + /** * return configuration as double if exists otherwise return defaultValue * diff --git a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java index 3c860c96a9541..1315cda84c10f 100644 --- a/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java +++ b/bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java @@ -209,15 +209,16 @@ private static void setValueFromEnum(HomekitTaggedItem taggedItem, Characteristi } } - private static int getIntFromItem(HomekitTaggedItem taggedItem) { - int value = 0; + private static int getIntFromItem(HomekitTaggedItem taggedItem, int defaultValue) { + int value = defaultValue; final State state = taggedItem.getItem().getState(); if (state instanceof PercentType) { value = ((PercentType) state).intValue(); } else if (state instanceof DecimalType) { value = ((DecimalType) state).intValue(); } else if (state instanceof UnDefType) { - logger.debug("Item state {} is UNDEF {}.", state, taggedItem.getName()); + logger.debug("Item state {} is UNDEF {}. Returning default value {}", state, taggedItem.getName(), + defaultValue); } else { logger.warn( "Item state {} is not supported for {}. Only PercentType and DecimalType (0/100) are supported.", @@ -227,23 +228,24 @@ private static int getIntFromItem(HomekitTaggedItem taggedItem) { } /** special method for tilts. it converts percentage to angle */ - private static int getAngleFromItem(HomekitTaggedItem taggedItem) { - int value = 0; + private static int getAngleFromItem(HomekitTaggedItem taggedItem, int defaultValue) { + int value = defaultValue; final State state = taggedItem.getItem().getState(); if (state instanceof PercentType) { value = (int) ((((PercentType) state).intValue() * 90.0) / 50.0 - 90.0); } else { - value = getIntFromItem(taggedItem); + value = getIntFromItem(taggedItem, defaultValue); } return value; } - private static Supplier> getAngleSupplier(HomekitTaggedItem taggedItem) { - return () -> CompletableFuture.completedFuture(getAngleFromItem(taggedItem)); + private static Supplier> getAngleSupplier(HomekitTaggedItem taggedItem, + int defaultValue) { + return () -> CompletableFuture.completedFuture(getAngleFromItem(taggedItem, defaultValue)); } - private static Supplier> getIntSupplier(HomekitTaggedItem taggedItem) { - return () -> CompletableFuture.completedFuture(getIntFromItem(taggedItem)); + private static Supplier> getIntSupplier(HomekitTaggedItem taggedItem, int defaultValue) { + return () -> CompletableFuture.completedFuture(getIntFromItem(taggedItem, defaultValue)); } private static ExceptionalConsumer setIntConsumer(HomekitTaggedItem taggedItem) { @@ -399,28 +401,28 @@ private static CarbonDioxidePeakLevelCharacteristic createCarbonDioxidePeakLevel private static CurrentHorizontalTiltAngleCharacteristic createCurrentHorizontalTiltAngleCharacteristic( HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new CurrentHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem), + return new CurrentHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), getSubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater), getUnsubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater)); } private static CurrentVerticalTiltAngleCharacteristic createCurrentVerticalTiltAngleCharacteristic( HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new CurrentVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem), + return new CurrentVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), getSubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater), getUnsubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater)); } private static TargetHorizontalTiltAngleCharacteristic createTargetHorizontalTiltAngleCharacteristic( HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new TargetHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem), setAngleConsumer(taggedItem), - getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater), + return new TargetHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), + setAngleConsumer(taggedItem), getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater), getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater)); } private static TargetVerticalTiltAngleCharacteristic createTargetVerticalTiltAngleCharacteristic( HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new TargetVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem), setAngleConsumer(taggedItem), + return new TargetVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem), getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater), getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater)); } @@ -490,7 +492,12 @@ private static SaturationCharacteristic createSaturationCharacteristic(HomekitTa private static ColorTemperatureCharacteristic createColorTemperatureCharacteristic(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new ColorTemperatureCharacteristic(getIntSupplier(taggedItem), setIntConsumer(taggedItem), + int minValue = taggedItem.getConfigurationAsInt(HomekitTaggedItem.MIN_VALUE, + ColorTemperatureCharacteristic.DEFAULT_MIN_VALUE); + return new ColorTemperatureCharacteristic(minValue, + taggedItem.getConfigurationAsInt(HomekitTaggedItem.MAX_VALUE, + ColorTemperatureCharacteristic.DEFAULT_MAX_VALUE), + getIntSupplier(taggedItem, minValue), setIntConsumer(taggedItem), getSubscriber(taggedItem, COLOR_TEMPERATURE, updater), getUnsubscriber(taggedItem, COLOR_TEMPERATURE, updater)); } @@ -565,14 +572,14 @@ private static LockPhysicalControlsCharacteristic createLockPhysicalControlsChar private static RotationSpeedCharacteristic createRotationSpeedCharacteristic(HomekitTaggedItem item, HomekitAccessoryUpdater updater) { - return new RotationSpeedCharacteristic(getIntSupplier(item), setPercentConsumer(item), + return new RotationSpeedCharacteristic(getIntSupplier(item, 0), setPercentConsumer(item), getSubscriber(item, ROTATION_SPEED, updater), getUnsubscriber(item, ROTATION_SPEED, updater)); } private static SetDurationCharacteristic createDurationCharacteristic(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { return new SetDurationCharacteristic(() -> { - int value = getIntFromItem(taggedItem); + int value = getIntFromItem(taggedItem, 0); final @Nullable Map itemConfiguration = taggedItem.getConfiguration(); if ((value == 0) && (itemConfiguration != null)) { // check for default duration final Object duration = itemConfiguration.get(HomekitValveImpl.CONFIG_DEFAULT_DURATION); @@ -590,14 +597,14 @@ private static SetDurationCharacteristic createDurationCharacteristic(HomekitTag private static RemainingDurationCharacteristic createRemainingDurationCharacteristic(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new RemainingDurationCharacteristic(getIntSupplier(taggedItem), + return new RemainingDurationCharacteristic(getIntSupplier(taggedItem, 0), getSubscriber(taggedItem, REMAINING_DURATION, updater), getUnsubscriber(taggedItem, REMAINING_DURATION, updater)); } private static VolumeCharacteristic createVolumeCharacteristic(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) { - return new VolumeCharacteristic(getIntSupplier(taggedItem), + return new VolumeCharacteristic(getIntSupplier(taggedItem, 0), (volume) -> ((NumberItem) taggedItem.getItem()).send(new DecimalType(volume)), getSubscriber(taggedItem, DURATION, updater), getUnsubscriber(taggedItem, DURATION, updater)); } From c8a4ccf04c086ca3e8dfe45817c9d04db98d19fe Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 10 Dec 2021 15:46:03 +0100 Subject: [PATCH 196/361] Fix link to JN-UG-3091.pdf #11736 (#11743) Signed-off-by: prsnbrg Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.hue/README.md | 2 +- bundles/org.openhab.binding.tradfri/README.md | 2 +- .../src/main/resources/OH-INF/thing/thing-types.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.hue/README.md b/bundles/org.openhab.binding.hue/README.md index fee9426e00874..b50629a1ec648 100644 --- a/bundles/org.openhab.binding.hue/README.md +++ b/bundles/org.openhab.binding.hue/README.md @@ -19,7 +19,7 @@ Additionally, it is possible to use OSRAM Lightify devices as well as other ZigB Beside bulbs and luminaires the Hue binding also supports some ZigBee sensors. Currently only Hue specific sensors are tested successfully (Hue Motion Sensor and Hue Dimmer Switch). Please note that the devices need to be registered with the Hue bridge before it is possible for this binding to use them. -The Hue binding supports all seven types of lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/documents/user_manual/JN-UG-3091.pdf). +The Hue binding supports all seven types of lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/docs/en/user-guide/JN-UG-3091.pdf). These are: | Device type | ZigBee Device ID | Thing type | diff --git a/bundles/org.openhab.binding.tradfri/README.md b/bundles/org.openhab.binding.tradfri/README.md index b1f37c926eca8..fda1384e6b580 100644 --- a/bundles/org.openhab.binding.tradfri/README.md +++ b/bundles/org.openhab.binding.tradfri/README.md @@ -10,7 +10,7 @@ The TRÅDFRI controller and sensor devices currently cannot be observed right aw This makes it nearly impossible to trigger events for pressed buttons. We only can access some static data like the present status or battery level. -The thing type ids are defined according to the lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/documents/user_manual/JN-UG-3091.pdf)). +The thing type ids are defined according to the lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/docs/en/user-guide/JN-UG-3091.pdf)). These are: | Device type | ZigBee Device ID | Thing type | diff --git a/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/thing/thing-types.xml index 7d989ea2865e8..445c01f52f882 100644 --- a/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.tradfri/src/main/resources/OH-INF/thing/thing-types.xml @@ -14,7 +14,7 @@ - + From a8bab264373d801c2ae46db13921416a91231cfc Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 11 Dec 2021 10:01:40 +0100 Subject: [PATCH 197/361] Resolve runbundles for Whiteboard downgrade (#11744) Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- itests/org.openhab.binding.nest.tests/itest.bndrun | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/itests/org.openhab.binding.nest.tests/itest.bndrun b/itests/org.openhab.binding.nest.tests/itest.bndrun index 721fca207740f..880e5865b7302 100644 --- a/itests/org.openhab.binding.nest.tests/itest.bndrun +++ b/itests/org.openhab.binding.nest.tests/itest.bndrun @@ -85,7 +85,6 @@ Fragment-Host: org.openhab.binding.nest org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ com.fasterxml.woodstox.woodstox-core;version='[6.2.6,6.2.7)',\ - org.apache.aries.jax.rs.whiteboard;version='[2.0.1,2.0.2)',\ org.apache.cxf.cxf-core;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-frontend-jaxrs;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-rs-client;version='[3.4.5,3.4.6)',\ @@ -104,4 +103,5 @@ Fragment-Host: org.openhab.binding.nest org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.aries.jax.rs.whiteboard;version='[2.0.0,2.0.1)' From c8af87ee0e1ad6fcdff1954c2e2c27dfe26b5d61 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 11 Dec 2021 10:56:48 +0100 Subject: [PATCH 198/361] [plugwise] Fix 'power' channel not correctly updated with power production (#11746) This fixes the issue that the 'power' channel would not update with the correct state because the number of pulses in the PowerInformationResponseMessage is signed instead of unsigned. When the binding detected these strange readings it would normally log: "Circle (...) is in a kind of error state ...". Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../protocol/PowerInformationResponseMessage.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/protocol/PowerInformationResponseMessage.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/protocol/PowerInformationResponseMessage.java index d53379ebbfa6c..91d66e5125d81 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/protocol/PowerInformationResponseMessage.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/protocol/PowerInformationResponseMessage.java @@ -33,6 +33,7 @@ public class PowerInformationResponseMessage extends Message { private static final Pattern PAYLOAD_PATTERN = Pattern.compile("(\\w{16})(\\w{4})(\\w{4})(\\w{8})(\\w{8})(\\w{4})"); private static final double NANOSECONDS_CORRECTION_DIVISOR = 0.000046875; // 46875 divided by nanos per second + private static final Duration ONE_HOUR = Duration.ofHours(1); private Energy oneSecond; private Energy eightSecond; @@ -67,12 +68,12 @@ protected void parsePayload() { ZonedDateTime utcNow = ZonedDateTime.now(UTC); macAddress = new MACAddress(matcher.group(1)); nanosCorrection = Math.round(Integer.parseInt(matcher.group(6), 16) / NANOSECONDS_CORRECTION_DIVISOR); - oneSecond = new Energy(utcNow, Integer.parseInt(matcher.group(2), 16), + oneSecond = new Energy(utcNow, (short) Integer.parseInt(matcher.group(2), 16), Duration.ofSeconds(1, nanosCorrection)); - eightSecond = new Energy(utcNow, Integer.parseInt(matcher.group(3), 16), + eightSecond = new Energy(utcNow, (short) Integer.parseInt(matcher.group(3), 16), Duration.ofSeconds(8, nanosCorrection)); - oneHourConsumed = new Energy(utcNow, Long.parseLong(matcher.group(4), 16), Duration.ofHours(1)); - oneHourProduced = new Energy(utcNow, Long.parseLong(matcher.group(5), 16), Duration.ofHours(1)); + oneHourConsumed = new Energy(utcNow, Long.parseLong(matcher.group(4), 16), ONE_HOUR); + oneHourProduced = new Energy(utcNow, Long.parseLong(matcher.group(5), 16), ONE_HOUR); } else { throw new PlugwisePayloadMismatchException(POWER_INFORMATION_RESPONSE, PAYLOAD_PATTERN, payload); } From 8d4ca6a1fab9798a0d12da7a065bc188e0b6ab87 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Sat, 11 Dec 2021 10:13:55 +0000 Subject: [PATCH 199/361] Added simple Shared Cache into scope (#11693) Signed-off-by: Jonathan Gilbert Signed-off-by: Michael Schmidt --- .../internal/scope/SharedCache.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/SharedCache.java diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/SharedCache.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/SharedCache.java new file mode 100644 index 0000000000000..225e5fddf20f3 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/SharedCache.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.scope; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.automation.module.script.ScriptExtensionProvider; +import org.osgi.service.component.annotations.Component; + +/** + * Shared Cache implementation for JS scripting. + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true) +@NonNullByDefault +public class SharedCache implements ScriptExtensionProvider { + + private static final String PRESET_NAME = "cache"; + private static final String OBJECT_NAME = "sharedcache"; + + private JSCache cache = new JSCache(); + + @Override + public Collection getDefaultPresets() { + return Set.of(PRESET_NAME); + } + + @Override + public Collection getPresets() { + return Set.of(PRESET_NAME); + } + + @Override + public Collection getTypes() { + return Set.of(OBJECT_NAME); + } + + @Override + public @Nullable Object get(String scriptIdentifier, String type) throws IllegalArgumentException { + if (OBJECT_NAME.equals(type)) { + return cache; + } + + return null; + } + + @Override + public Map importPreset(String scriptIdentifier, String preset) { + if (PRESET_NAME.equals(preset)) { + final Object requestedType = get(scriptIdentifier, OBJECT_NAME); + if (requestedType != null) { + return Map.of(OBJECT_NAME, requestedType); + } + } + + return Collections.emptyMap(); + } + + @Override + public void unload(String scriptIdentifier) { + // ignore for now + } + + public static class JSCache { + private Map backingMap = new HashMap<>(); + + public void put(String k, Object v) { + backingMap.put(k, v); + } + + public @Nullable Object remove(String k) { + return backingMap.remove(k); + } + + public @Nullable Object get(String k) { + return backingMap.get(k); + } + + public @Nullable Object get(String k, Supplier supplier) { + return backingMap.computeIfAbsent(k, (unused_key) -> supplier.get()); + } + } +} From 81efb40f71d0023cd123bddb7d24335c0f7a2b40 Mon Sep 17 00:00:00 2001 From: Flole998 Date: Sat, 11 Dec 2021 11:35:33 +0100 Subject: [PATCH 200/361] [Hueemulation] Fix xy change response (#10692) Signed-off-by: Flole Signed-off-by: Michael Schmidt --- .../dto/response/HueSuccessResponseStateChanged.java | 5 +++++ .../io/hueemulation/internal/rest/LightsAndGroupsTests.java | 1 + 2 files changed, 6 insertions(+) diff --git a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/response/HueSuccessResponseStateChanged.java b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/response/HueSuccessResponseStateChanged.java index 06ef0d4516fbb..f921dded31682 100644 --- a/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/response/HueSuccessResponseStateChanged.java +++ b/bundles/org.openhab.io.hueemulation/src/main/java/org/openhab/io/hueemulation/internal/dto/response/HueSuccessResponseStateChanged.java @@ -13,7 +13,9 @@ package org.openhab.io.hueemulation.internal.dto.response; import java.lang.reflect.Type; +import java.util.List; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; @@ -65,6 +67,9 @@ public JsonElement serialize(HueSuccessResponseStateChanged product, Type type, if (product.value instanceof String) { jObj.addProperty(product.relURI, (String) product.value); } + if (product.value instanceof List) { + jObj.add(product.relURI, new Gson().toJsonTree(product.value)); + } return jObj; } } diff --git a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java index 5a86a0fe5123e..2d23689800a6b 100644 --- a/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java +++ b/bundles/org.openhab.io.hueemulation/src/test/java/org/openhab/io/hueemulation/internal/rest/LightsAndGroupsTests.java @@ -306,6 +306,7 @@ public void switchOnWithXY() { .put(Entity.json(body)); assertEquals(200, response.getStatus()); assertThat(response.readEntity(String.class), containsString("success")); + assertThat(response.readEntity(String.class), containsString("xy")); assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).on, is(true)); assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).bri, is(200)); assertThat(((HueStateColorBulb) cs.ds.lights.get("2").state).xy[0], is(0.5119)); From 909a40bd1e2762847e8d798f11333c46c2e9af3f Mon Sep 17 00:00:00 2001 From: Frieso Aeschbacher Date: Sat, 11 Dec 2021 13:05:41 +0100 Subject: [PATCH 201/361] [dominoswiss] Initial contribution (#11585) * Added Dominoswiss to CODEOWNERS and POMs Signed-off-by: Frieso Aeschbacher * Intitial contribution of Dominoswiss Binding Signed-off-by: Frieso Aeschbacher * Typo in pom.xml Signed-off-by: Frieso Aeschbacher * Fixed inputs from fwolter Signed-off-by: Frieso Aeschbacher * Fixed inputs from fwolter Signed-off-by: Frieso Aeschbacher * Fixed localWriter Issue Signed-off-by: Frieso Aeschbacher * Update bom/openhab-addons/pom.xml Signed-off-by: Fabian Wolter Co-authored-by: Fabian Wolter Signed-off-by: Michael Schmidt --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../org.openhab.binding.dominoswiss/NOTICE | 13 + .../org.openhab.binding.dominoswiss/README.md | 100 ++++++ .../org.openhab.binding.dominoswiss/pom.xml | 15 + .../src/main/feature/feature.xml | 9 + .../dominoswiss/internal/BlindConfig.java | 29 ++ .../dominoswiss/internal/BlindHandler.java | 186 +++++++++++ .../internal/DominoswissBindingConstants.java | 49 +++ .../internal/DominoswissConfiguration.java | 38 +++ .../internal/DominoswissHandlerFactory.java | 60 ++++ .../dominoswiss/internal/EGateHandler.java | 316 ++++++++++++++++++ .../main/resources/OH-INF/binding/binding.xml | 8 + .../OH-INF/i18n/dominoswiss_de_DE.properties | 3 + .../resources/OH-INF/thing/thing-types.xml | 114 +++++++ bundles/pom.xml | 1 + 16 files changed, 947 insertions(+) create mode 100644 bundles/org.openhab.binding.dominoswiss/NOTICE create mode 100644 bundles/org.openhab.binding.dominoswiss/README.md create mode 100644 bundles/org.openhab.binding.dominoswiss/pom.xml create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindConfig.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindHandler.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissBindingConstants.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissConfiguration.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissHandlerFactory.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/EGateHandler.java create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss_de_DE.properties create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/CODEOWNERS b/CODEOWNERS index aefb2968aea4b..85a2c178a0bbe 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -70,6 +70,7 @@ /bundles/org.openhab.binding.digitalstrom/ @MichaelOchel @msiegele /bundles/org.openhab.binding.dlinksmarthome/ @MikeJMajor /bundles/org.openhab.binding.dmx/ @openhab/add-ons-maintainers +/bundles/org.openhab.binding.dominoswiss/ @Friesoch /bundles/org.openhab.binding.doorbird/ @mhilbush /bundles/org.openhab.binding.draytonwiser/ @andrew-schofield /bundles/org.openhab.binding.dscalarm/ @RSStephens diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 79751a4f01223..5ce8d23a023d9 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -341,6 +341,11 @@ org.openhab.binding.dmx ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.dominoswiss + ${project.version} + org.openhab.addons.bundles org.openhab.binding.doorbird diff --git a/bundles/org.openhab.binding.dominoswiss/NOTICE b/bundles/org.openhab.binding.dominoswiss/NOTICE new file mode 100644 index 0000000000000..38d625e349232 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/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/openhab-addons diff --git a/bundles/org.openhab.binding.dominoswiss/README.md b/bundles/org.openhab.binding.dominoswiss/README.md new file mode 100644 index 0000000000000..fb2363d09ff33 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/README.md @@ -0,0 +1,100 @@ +# Dominoswiss Binding + +This binding allows the control of rollershutters, using an eGate as gateway and Dominoswiss radio receivers. +The eGate-gateway is connected via ethernet to openHAB and sends its commands via radio to all rollershutters. +See https://www.brelag.com/ for more information. + + +## Supported Things + +eGate: Dominoswiss eGate Server. The eGate is the gateway which sends the commands to the connected rollershutters. The bridge-type ID is egate. +Blind: represents one rollershutter, that can be controlled via eGate. The thing-type ID is blind. + + +## Discovery + +Unfortunately no automatic discovery is possible due to protocol restrictions. +Every rollershutter must be known by eGate and can be called by it's number of storage-place on eGate gateway. + + + +## Thing Configuration + +The bridge "eGate" has one channel "getconfig" which returns the config of this bridge. +The eGate is configured with both an `ipAddress` and a port. + +|Property|Default|Required|Description| +|--------|-------|--------|-----------| +|ipAddress|none|Yes|The IP or host name of the Dominoswiss EGate Serve| +|port|1318|Yes|Port interface of the Dominoswiss EGate Server| + +``` +Bridge dominoswiss:egate:myeGate "My eGate Server" @ "Home" [ ipAddres="localhost", port=5700 ] +``` + + +The thing blind represents one blind on the eGate. Each blind is represented by an id set on your eGate. + +``` +Thing blind officeBlind "Office" @ "1stFloor" [ id="1"] +``` + +The blind-Thing has the following channels: + +|Channel Type ID|Item Type|Description| +|---------------|---------|-----------| +|pulseUp|Rollershutter|sends one pulse up to this blind.| +|pulseDown|Rollershutter|sends one pulse down to this blind| +|continuousUp|Rollershutter|sends a continuous up to this blind. The blind will automatically stop as it is fully up.| +|continuousDown|Rollershutter|send a continous down to this blind. The blind will automatically stop as it is fully down.| +|stop|Rollershutter|stop the action of the blind. The command will be imadiatly sent to the blind.| +|shutter|Rollershutter|this is used to bind the channel to the shutter item. There are no further rules needed this channel will handel the up/down/stop commands. See example for usage.| +|tilt|Rollershutter|same as shutter, this will handel all up/down/stop - tilt commands to be used with the shutter-item.| +|tiltUp|Rollershutter|sends 3 pulse-up commands to this blind to tilt the blind. If your blind needs more than 3 pulse-up, create a rule yourself with three pluse-up commands. Between each pulse-up you should wait 150ms to let the command be processed. +|tiltDown|Rollershutter|sends 3 pulse-down commands to this blind to tilt the blind. If your blind needs more than 3 pulse-down, create a rule yourself with three pluse-down commands. Between each pulse-down you should wait 150ms to let the command be processed. | + +## Full Example + +Sample things file: + +``` +Bridge dominoswiss:egate:myeGate "My eGate Server" @ "Home" [ ipAddres="localhost", port="5500" ] +{ + Thing blind officeBlind "Office" @ "1stFloor" [ id="1"] + Thing blind diningRoomBlind "Dining Room" @ "EG" [id="2"] + Thing blind kitchenBlind "Kitchen" @ "EG" [id="12"] +} +``` + +Sample items file: + +``` +Rollershutter OfficeBlindShutter "Office blind" (g_blinds) { channel="dominoswiss:blind:myeGate:officeBlind:shutter"} + +Rollershutter OfficeBlindShutterTilt "Tilt Office" (g_blinds_tilt) { channel="dominoswiss:blind:meGgate:bueroBlind:tilt"} + +``` + +Sample sitemap file + +``` +Switch item=OfficeBlindShutter +Switch item=OfficeBlindShutterTilt +``` + +Sample rule file + +This example moves the blind of the office up as the sun passed 110 azimuth (so the sun is no longer shining directly into the office). + +``` +rule "OneSide up" +when + Item Azimuth changed +then + val azimuth = Math::round((Azimuth.state as DecimalType).intValue) + if (azimuth == 110) + { + OfficeBlindShutter.sendCommand(UP) + } +end +``` diff --git a/bundles/org.openhab.binding.dominoswiss/pom.xml b/bundles/org.openhab.binding.dominoswiss/pom.xml new file mode 100644 index 0000000000000..b5c5b3cd2e0fd --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/pom.xml @@ -0,0 +1,15 @@ + + + + 4.0.0 + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.2.0-SNAPSHOT + + org.openhab.binding.dominoswiss + + openHAB Add-ons :: Bundles :: Dominoswiss Binding + + diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/feature/feature.xml b/bundles/org.openhab.binding.dominoswiss/src/main/feature/feature.xml new file mode 100644 index 0000000000000..61f2c28b1fe76 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.dominoswiss/${project.version} + + diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindConfig.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindConfig.java new file mode 100644 index 0000000000000..0deb53a1866ac --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindConfig.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Configuration of a blind. + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +public class BlindConfig { + + /* + * The ID of that blind + */ + public String id = ""; +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindHandler.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindHandler.java new file mode 100644 index 0000000000000..a2a1a140311f4 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/BlindHandler.java @@ -0,0 +1,186 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link BlindHandler} is responsible for handling commands, which are + * sent to one of the channels.The class defines common constants, which are + * used across the whole binding + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +public class BlindHandler extends BaseThingHandler { + + private Logger logger = LoggerFactory.getLogger(BlindHandler.class); + + private @Nullable EGateHandler dominoswissHandler; + + private String id = ""; + + public BlindHandler(Thing thing) { + super(thing); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + logger.debug("Blind got command: {} and ChannelUID: {} ", command.toFullString(), + channelUID.getIdWithoutGroup()); + Bridge bridge = getBridge(); + EGateHandler localDominoswissHandler = dominoswissHandler; + if (bridge != null) { + localDominoswissHandler = (EGateHandler) bridge.getHandler(); + } + if (localDominoswissHandler == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, "EGate not available"); + logger.debug("Blind thing {} has no server configured, ignoring command: {}", getThing().getUID(), command); + return; + } + + // Some of the code below is not designed to handle REFRESH + if (command == RefreshType.REFRESH) { + return; + } + switch (channelUID.getIdWithoutGroup()) { + case CHANNEL_PULSEUP: + if (command instanceof Number) { + localDominoswissHandler.pulseUp(id); + } + break; + case CHANNEL_PULSEDOWN: + if (command instanceof Number) { + localDominoswissHandler.pulseDown(id); + } + break; + case CHANNEL_CONTINOUSUP: + if (command instanceof Number) { + localDominoswissHandler.continuousUp(id); + } + break; + case CHANNEL_CONTINOUSDOWN: + if (command instanceof Number) { + localDominoswissHandler.continuousDown(id); + } + break; + case CHANNEL_STOP: + if (command instanceof Number) { + localDominoswissHandler.stop(id); + } + break; + case UP: + if (command instanceof Number) { + localDominoswissHandler.continuousUp(id); + } + break; + case DOWN: + if (command instanceof Number) { + localDominoswissHandler.continuousDown(id); + } + break; + case SHUTTER: + if (command.toFullString() == DOWN) { + localDominoswissHandler.continuousDown(id); + } else if (command.toFullString() == UP) { + localDominoswissHandler.continuousUp(id); + } else if (command.toFullString() == CHANNEL_STOP) { + localDominoswissHandler.stop(id); + } else { + logger.debug("Blind got command but nothing executed: {} and ChannelUID: {}", + command.toFullString(), channelUID.getIdWithoutGroup()); + } + + case TILTDOWN: + if (command instanceof Number) { + try { + localDominoswissHandler.tiltDown(id); + } catch (InterruptedException e) { + logger.debug("EGate tiltDown error: {} ", e.toString()); + } + } + break; + + case TILTUP: + if (command instanceof Number) { + try { + localDominoswissHandler.tiltUp(id); + } catch (InterruptedException e) { + logger.debug("EGate tiltUP error: {} ", e.toString()); + } + } + break; + + case SHUTTERTILT: + if (command.toFullString() == UP) { + localDominoswissHandler.pulseUp(id); + } else if (command.toFullString() == DOWN) { + localDominoswissHandler.pulseDown(id); + } else if (command.toFullString() == CHANNEL_STOP) { + localDominoswissHandler.stop(id); + } else { + logger.debug("Blind got command but nothing executed: {} and ChannelUID: {}", + command.toFullString(), channelUID.getIdWithoutGroup()); + } + + default: + break; + } + } + + @Override + public void initialize() { + this.id = getConfig().as(BlindConfig.class).id; + Bridge bridge = getBridge(); + if (bridge != null) { + dominoswissHandler = (EGateHandler) bridge.getHandler(); + EGateHandler localDominoswissHandler = dominoswissHandler; + if (localDominoswissHandler != null) { + localDominoswissHandler.registerBlind(this.id, getThing().getUID()); + try { + ThingStatus bridgeStatus = bridge.getStatus(); + if (bridgeStatus == ThingStatus.ONLINE && getThing().getStatus() != ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE); + localDominoswissHandler = (EGateHandler) bridge.getHandler(); + } else if (bridgeStatus == ThingStatus.OFFLINE) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + } + } catch (Exception e) { + logger.debug("Could not update ThingStatus ", e); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.toString()); + + } + } + } + } + + /* + * Gets the ID of this Blind + */ + public String getID() { + return this.id; + } +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissBindingConstants.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissBindingConstants.java new file mode 100644 index 0000000000000..4c3d51373c5f2 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissBindingConstants.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link DominoswissBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +public class DominoswissBindingConstants { + + private static final String BINDING_ID = "dominoswiss"; + + // List of all Thing Type UIDs + public static final ThingTypeUID DOMINOSWISSBLINDS_THING_TYPE = new ThingTypeUID(BINDING_ID, "blind"); + public static final ThingTypeUID DOMINOSWISSEGATE_THING_TYPE = new ThingTypeUID(BINDING_ID, "egate"); + + // List of all Channel ids + public static final String CHANNEL_PULSEUP = "pulseUp"; + public static final String CHANNEL_PULSEDOWN = "pulseDown"; + public static final String CHANNEL_CONTINOUSUP = "continousUp"; + public static final String CHANNEL_CONTINOUSDOWN = "continousDown"; + public static final String CHANNEL_STOP = "STOP"; + public static final String UP = "UP"; + public static final String DOWN = "DOWN"; + public static final String SHUTTER = "shutter"; + public static final String TILTUP = "tiltUp"; + public static final String TILTDOWN = "tiltDown"; + public static final String SHUTTERTILT = "shutterTilt"; + + public static final String GETCONFIG = "getConfig"; + + public static final String CR = "\r"; +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissConfiguration.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissConfiguration.java new file mode 100644 index 0000000000000..6ab19edbb8875 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissConfiguration.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link DominoswissConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +public class DominoswissConfiguration { + + /** + * Server ip address + */ + public String ipAddress = "localhost"; + /** + * Server web port for REST calls + */ + public int port = 1318; + + /** + * Language for TTS has to be fix to EN as only English commands are allowed + */ + public final String language = "EN"; +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissHandlerFactory.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissHandlerFactory.java new file mode 100644 index 0000000000000..5b38d1904e7f7 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/DominoswissHandlerFactory.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*; + +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Component; + +/** + * The {@link DominoswissHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.dominoswiss", service = ThingHandlerFactory.class) +public class DominoswissHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(DOMINOSWISSEGATE_THING_TYPE, + DOMINOSWISSBLINDS_THING_TYPE); + + @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 (thingTypeUID.equals(DOMINOSWISSEGATE_THING_TYPE)) { + return new EGateHandler((Bridge) thing); + } + + if (thingTypeUID.equals(DOMINOSWISSBLINDS_THING_TYPE)) { + return new BlindHandler(thing); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/EGateHandler.java b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/EGateHandler.java new file mode 100644 index 0000000000000..7cbc66b2484da --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/java/org/openhab/binding/dominoswiss/internal/EGateHandler.java @@ -0,0 +1,316 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dominoswiss.internal; + +import static org.openhab.binding.dominoswiss.internal.DominoswissBindingConstants.*; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link EgateHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Frieso Aeschbacher - Initial contribution + */ +@NonNullByDefault +public class EGateHandler extends BaseBridgeHandler { + + private final Logger logger = LoggerFactory.getLogger(EGateHandler.class); + private @Nullable Socket egateSocket; + + private int port; + private @Nullable String host; + private static final int SOCKET_TIMEOUT_SEC = 250; + private final Object lock = new Object(); + private @Nullable BufferedWriter writer; + private @Nullable BufferedReader reader; + private @Nullable Future refreshJob; + private Map registeredBlinds; + private @Nullable ScheduledFuture pollingJob; + + public EGateHandler(Bridge thing) { + super(thing); + registeredBlinds = new HashMap(); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + if (channelUID.getId().equals(GETCONFIG)) { + sendCommand("EthernetGet;\r"); + } + } + + @Override + public void initialize() { + DominoswissConfiguration config; + config = this.getConfigAs(DominoswissConfiguration.class); + host = config.ipAddress; + port = config.port; + + if (host != null && port > 0) { + // Create a socket to eGate + try (Socket localEgateSocket = new Socket(host, port)) { + writer = new BufferedWriter(new OutputStreamWriter(localEgateSocket.getOutputStream())); + egateSocket = localEgateSocket; + } catch (IOException e) { + logger.debug("IOException in initialize: {} host {} port {}", e.toString(), host, port); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString()); + egateSocket = null; + } + pollingJob = scheduler.scheduleWithFixedDelay(this::pollingConfig, 0, 30, TimeUnit.SECONDS); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "Cannot connect to dominoswiss eGate gateway. host IP address or port are not set."); + } + } + + @Override + public void dispose() { + try { + Socket localEgateSocket = egateSocket; + if (localEgateSocket != null) { + localEgateSocket.close(); + } + Future localRefreshJob = refreshJob; + if (localRefreshJob != null) { + localRefreshJob.cancel(true); + } + BufferedReader localReader = reader; + if (localReader != null) { + localReader.close(); + } + + BufferedWriter localWriter = writer; + if (localWriter != null) { + localWriter.close(); + } + ScheduledFuture localPollingJob = pollingJob; + if (localPollingJob != null) { + localPollingJob.cancel(true); + localPollingJob = null; + } + logger.debug("EGate Handler connection closed, disposing"); + } catch (IOException e) { + logger.debug("EGate Handler Error on dispose: {} ", e.toString()); + } + } + + public synchronized boolean isConnected() { + Socket localEGateSocket = egateSocket; + if (localEGateSocket == null) { + return false; + } + + // NOTE: isConnected() returns true once a connection is made and will + // always return true even after the socket is closed + // http://stackoverflow.com/questions/10163358/ + return localEGateSocket.isConnected() && !localEGateSocket.isClosed(); + } + + /** + * Possible Instructions are: + * FssTransmit 1 Kommandoabsetzung (Controller > eGate > Dominoswiss) + * FssReceive 2 Empfangenes Funkpaket (Dominoswiss > eGate > Controller) + * + * @throws InterruptedException + * + */ + + public void tiltUp(String id) throws InterruptedException { + for (int i = 0; i < 3; i++) { + pulseUp(id); + Thread.sleep(150); // sleep to not confuse the blinds + + } + } + + public void tiltDown(String id) throws InterruptedException { + for (int i = 0; i < 3; i++) { + pulseDown(id); + Thread.sleep(150);// sleep to not confuse the blinds + } + } + + public void pulseUp(String id) { + sendCommand("Instruction=1;ID=" + id + ";Command=1;Priority=1;CheckNr=3415347;" + CR); + } + + public void pulseDown(String id) { + sendCommand("Instruction=1;ID=" + id + ";Command=2;Priority=1;CheckNr=2764516;" + CR); + } + + public void continuousUp(String id) { + sendCommand("Instruction=1;ID=" + id + ";Command=3;Priority=1;CheckNr=2867016;" + CR, 20000); + } + + public void continuousDown(String id) { + sendCommand("Instruction=1;ID=" + id + ";Command=4;Priority=1;CheckNr=973898;" + CR, 20000); + } + + public void stop(String id) { + sendCommand("Instruction=1;ID=" + id + ";Command=5;Priority=1;CheckNr=5408219;" + CR); + } + + public void registerBlind(String id, ThingUID uid) { + logger.debug("Registring Blind id {} with thingUID {}", id, uid); + registeredBlinds.put(id, uid); + } + + /** + * Send a command to the eGate Server. + */ + + private void sendCommand(String command) { + sendCommand(command, SOCKET_TIMEOUT_SEC); + } + + private synchronized void sendCommand(String command, int timeout) { + logger.debug("EGate got command: {}", command); + Socket localEGateSocket = egateSocket; + BufferedWriter localWriter = writer; + if (localEGateSocket == null || localWriter == null) { + return; + } + if (!isConnected()) { + logger.debug("no connection to Dominoswiss eGate server when trying to send command, returning..."); + return; + } + + // Send plain string to eGate Server, + try { + localEGateSocket.setSoTimeout(SOCKET_TIMEOUT_SEC); + localWriter.write(command); + localWriter.flush(); + } catch (IOException e) { + logger.debug("Error while sending command {} to Dominoswiss eGate Server {} ", command, e.toString()); + } + } + + private void pollingConfig() { + if (!isConnected()) { + Socket localEGateSocket = egateSocket; + BufferedWriter localWriter = writer; + if (localEGateSocket == null || localWriter == null) { + return; + } + synchronized (lock) { + try { + localEGateSocket.connect(new InetSocketAddress(host, port)); + localEGateSocket.setSoTimeout(SOCKET_TIMEOUT_SEC); + localWriter.write("SilenceModeSet;Value=0;" + CR); + localWriter.flush(); + } catch (IOException e) { + logger.debug("IOException in pollingConfig: {} host {} port {}", e.toString(), host, port); + try { + localEGateSocket.close(); + egateSocket = null; + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString()); + } catch (IOException e1) { + logger.debug("EGate Socket not closed {}", e1.toString()); + } + egateSocket = null; + } + if (egateSocket != null) { + updateStatus(ThingStatus.ONLINE); + startAutomaticRefresh(); + logger.debug("EGate Handler started automatic refresh, status: {} ", + getThing().getStatus().toString()); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); + } + } + } + } + + private void startAutomaticRefresh() { + Runnable runnable = () -> { + try { + + Socket localSocket = egateSocket; + if (localSocket == null) { + return; + } + BufferedReader localReader = reader; + if (localReader == null) { + reader = new BufferedReader(new InputStreamReader(localSocket.getInputStream())); + } + if (localReader != null && localReader.ready()) { + String input = localReader.readLine(); + logger.debug("Reader got from EGATE: {}", input); + onData(input); + } + } catch (IOException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, + "Error while reading command from Dominoswiss eGate Server " + e.toString()); + } + }; + refreshJob = scheduler.submit(runnable); + } + + /** + * Finds and returns a child thing for a given UID of this bridge. + * + * @param uid uid of the child thing + * @return child thing with the given uid or null if thing was not found + */ + public @Nullable Thing getThingByUID(ThingUID uid) { + Bridge bridge = getThing(); + + List things = bridge.getThings(); + + for (Thing thing : things) { + if (thing.getUID().equals(uid)) { + return thing; + } + } + + return null; + } + + protected void onData(String input) { + // Instruction=2;ID=19;Command=1;Value=0;Priority=0; + Map map = new HashMap(); + // split on ; + String[] parts = input.split(";"); + if (parts.length >= 2) { + for (int i = 0; i < parts.length; i += 2) { + map.put(parts[i], parts[i + 1]); + } + } + } +} diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000000000..0c9d588efd6fe --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,8 @@ + + + + Dominoswiss Binding + The Dominoswiss Binding interacts with the Dominoswiss eGate G1 Gateway to control blinds + diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss_de_DE.properties b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss_de_DE.properties new file mode 100644 index 0000000000000..73b2a40d902d8 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss_de_DE.properties @@ -0,0 +1,3 @@ +# binding +binding.dominoswiss.name = Dominoswiss +binding.dominoswiss.description = Dominoswiss Binding zur Kontrolle der Jalousien diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000000000..2b06be3d50ad2 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,114 @@ + + + + + This is a Dominoswiss EGate Server instance. + + + + network-address + The IP or host name of the Dominoswiss EGate Server (192.168.1.100, localhost) + + + + Port interface of the Dominoswiss EGate Server, default 1318 + 1318 + + + + + + + + + + Provides various control commands for Dominoswiss receivers + + + + + + + + + + + + + Dominoswiss + + + + + Blinds are identified by their ID address + + + + + + Rollershutter + + Send one pulse up + + + + + Rollershutter + + Send one pulse down + + + + + Rollershutter + + Send continuous up command to blind + + + + + Rollershutter + + Send continuous down command to blind + + + + + Rollershutter + + Send stop impulse to stop the blinds + + + + + Rollershutter + + Handle the commands up/down/stop + + + + + Rollershutter + + Handle the commands tiltUp/tiltDown/stop + + + + + Rollershutter + + Handle the command for 3 tilts up + + + + + Rollershutter + + Handle the command for 3 tilts down + + + + diff --git a/bundles/pom.xml b/bundles/pom.xml index c09a0a2c50950..63b09b249007f 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -102,6 +102,7 @@ org.openhab.binding.digitalstrom org.openhab.binding.dlinksmarthome org.openhab.binding.dmx + org.openhab.binding.dominoswiss org.openhab.binding.doorbird org.openhab.binding.draytonwiser org.openhab.binding.dscalarm From e5fb5c6c62272b7fa7caf6dde13c7cdd6d501950 Mon Sep 17 00:00:00 2001 From: dalgwen Date: Sat, 11 Dec 2021 13:08:03 +0100 Subject: [PATCH 202/361] [pulseaudio] Add reencoding to play more audio formats (#11630) (#11631) Add a pass to reencode PCM sound in 16 bit, 44100 hz, 2 channels, before sending it to the pulseaudio audio sink. Signed-off-by: Gwendal Roulleau Co-authored-by: Gwendal Roulleau Signed-off-by: Michael Schmidt --- .../internal/ConvertedInputStream.java | 257 ++++++++++++++++++ .../internal/PulseAudioAudioSink.java | 118 +------- 2 files changed, 267 insertions(+), 108 deletions(-) create mode 100644 bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/ConvertedInputStream.java diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/ConvertedInputStream.java b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/ConvertedInputStream.java new file mode 100644 index 0000000000000..66b902bc9cfcb --- /dev/null +++ b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/ConvertedInputStream.java @@ -0,0 +1,257 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.pulseaudio.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider; +import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.audio.AudioFormat; +import org.openhab.core.audio.AudioStream; +import org.openhab.core.audio.FixedLengthAudioStream; +import org.openhab.core.audio.UnsupportedAudioFormatException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tritonus.share.sampled.file.TAudioFileFormat; + +/** + * This class convert a stream to the normalized pcm + * format wanted by the pulseaudio sink + * + * @author Gwendal Roulleau - Initial contribution + */ +@NonNullByDefault +public class ConvertedInputStream extends InputStream { + + private final Logger logger = LoggerFactory.getLogger(ConvertedInputStream.class); + + private static final javax.sound.sampled.AudioFormat TARGET_FORMAT = new javax.sound.sampled.AudioFormat( + javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false); + + private final AudioFormat audioFormat; + private AudioInputStream pcmNormalizedInputStream; + + private long duration = -1; + private long length = -1; + + public ConvertedInputStream(AudioStream innerInputStream) + throws UnsupportedAudioFormatException, UnsupportedAudioFileException, IOException { + + this.audioFormat = innerInputStream.getFormat(); + + if (innerInputStream instanceof FixedLengthAudioStream) { + length = ((FixedLengthAudioStream) innerInputStream).length(); + } + + pcmNormalizedInputStream = getPCMStreamNormalized(getPCMStream(new ResetableInputStream(innerInputStream))); + } + + @Override + public int read(byte @Nullable [] b) throws IOException { + return pcmNormalizedInputStream.read(b); + } + + @Override + public int read(byte @Nullable [] b, int off, int len) throws IOException { + return pcmNormalizedInputStream.read(b, off, len); + } + + @Override + public byte[] readAllBytes() throws IOException { + return pcmNormalizedInputStream.readAllBytes(); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + return pcmNormalizedInputStream.readNBytes(len); + } + + @Override + public int readNBytes(byte @Nullable [] b, int off, int len) throws IOException { + return pcmNormalizedInputStream.readNBytes(b, off, len); + } + + @Override + public int read() throws IOException { + return pcmNormalizedInputStream.read(); + } + + @Override + public void close() throws IOException { + pcmNormalizedInputStream.close(); + } + + /** + * Ensure right PCM format by converting if needed (sample rate, channel) + * + * @param pcmInputStream + * + * @return A PCM normalized stream (2 channel, 44100hz, 16 bit signed) + */ + private AudioInputStream getPCMStreamNormalized(AudioInputStream pcmInputStream) { + + javax.sound.sampled.AudioFormat format = pcmInputStream.getFormat(); + if (format.getChannels() != 2 + || !format.getEncoding().equals(javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED) + || Math.abs(format.getFrameRate() - 44100) > 1000) { + logger.debug("Sound is not in the target format. Trying to reencode it"); + return AudioSystem.getAudioInputStream(TARGET_FORMAT, pcmInputStream); + } else { + return pcmInputStream; + } + } + + public long getDuration() { + return duration; + } + + /** + * If necessary, this method convert MP3 to PCM, and try to + * extract duration information. + * + * @param resetableInnerInputStream A stream supporting reset operation + * (reset is mandatory to parse formation without loosing data) + * + * @return PCM stream + * @throws UnsupportedAudioFileException + * @throws IOException + * @throws UnsupportedAudioFormatException + */ + private AudioInputStream getPCMStream(InputStream resetableInnerInputStream) + throws UnsupportedAudioFileException, IOException, UnsupportedAudioFormatException { + + if (AudioFormat.MP3.isCompatible(audioFormat)) { + MpegAudioFileReader mpegAudioFileReader = new MpegAudioFileReader(); + + if (length > 0) { // compute duration if possible + AudioFileFormat audioFileFormat = mpegAudioFileReader.getAudioFileFormat(resetableInnerInputStream); + if (audioFileFormat instanceof TAudioFileFormat) { + Map taudioFileFormatProperties = ((TAudioFileFormat) audioFileFormat).properties(); + if (taudioFileFormatProperties.containsKey("mp3.framesize.bytes") + && taudioFileFormatProperties.containsKey("mp3.framerate.fps")) { + Integer frameSize = (Integer) taudioFileFormatProperties.get("mp3.framesize.bytes"); + Float frameRate = (Float) taudioFileFormatProperties.get("mp3.framerate.fps"); + if (frameSize != null && frameRate != null) { + duration = Math.round((length / (frameSize * frameRate)) * 1000); + logger.debug("Duration of input stream : {}", duration); + } + } + } + resetableInnerInputStream.reset(); + } + + logger.debug("Sound is a MP3. Trying to reencode it"); + // convert MP3 to PCM : + AudioInputStream sourceAIS = mpegAudioFileReader.getAudioInputStream(resetableInnerInputStream); + javax.sound.sampled.AudioFormat sourceFormat = sourceAIS.getFormat(); + + MpegFormatConversionProvider mpegconverter = new MpegFormatConversionProvider(); + javax.sound.sampled.AudioFormat convertFormat = new javax.sound.sampled.AudioFormat( + javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), 16, + sourceFormat.getChannels(), sourceFormat.getChannels() * 2, sourceFormat.getSampleRate(), false); + + return mpegconverter.getAudioInputStream(convertFormat, sourceAIS); + + } else if (AudioFormat.WAV.isCompatible(audioFormat)) { + // return the same input stream, but try to compute the duration first + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(resetableInnerInputStream); + if (length > 0) { + int frameSize = audioInputStream.getFormat().getFrameSize(); + float frameRate = audioInputStream.getFormat().getFrameRate(); + float durationInSeconds = (length / (frameSize * frameRate)); + duration = Math.round(durationInSeconds * 1000); + logger.debug("Duration of input stream : {}", duration); + } + return audioInputStream; + } else { + throw new UnsupportedAudioFormatException("Pulseaudio audio sink can only play pcm or mp3 stream", + audioFormat); + } + } + + /** + * This class add reset capability (on the first bytes only) + * to an AudioStream. This is necessary for the parsing / format detection. + * + */ + public static class ResetableInputStream extends InputStream { + + private static final int BUFFER_LENGTH = 10000; + + private final InputStream originalInputStream; + + private int position = -1; + private int markPosition = -1; + private int maxPreviousPosition = -2; + + private byte[] startingBuffer = new byte[BUFFER_LENGTH + 1]; + + public ResetableInputStream(InputStream originalInputStream) { + this.originalInputStream = originalInputStream; + } + + @Override + public void close() throws IOException { + originalInputStream.close(); + } + + @Override + public int read() throws IOException { + if (position >= BUFFER_LENGTH || originalInputStream.markSupported()) { + return originalInputStream.read(); + } else { + position++; + if (position <= maxPreviousPosition) { + return Byte.toUnsignedInt(startingBuffer[position]); + } else { + int currentByte = originalInputStream.read(); + startingBuffer[position] = (byte) currentByte; + maxPreviousPosition = position; + return currentByte; + } + } + } + + @Override + public synchronized void mark(int readlimit) { + if (originalInputStream.markSupported()) { + originalInputStream.mark(readlimit); + } + markPosition = position; + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public synchronized void reset() throws IOException { + if (originalInputStream.markSupported()) { + originalInputStream.reset(); + } else if (position >= BUFFER_LENGTH) { + throw new IOException("mark/reset not supported above " + BUFFER_LENGTH + " bytes"); + } + position = markPosition; + } + } +} diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java index 9de4d3cc7ccc7..dee60aaf9a134 100644 --- a/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java +++ b/bundles/org.openhab.binding.pulseaudio/src/main/java/org/openhab/binding/pulseaudio/internal/PulseAudioAudioSink.java @@ -13,23 +13,16 @@ package org.openhab.binding.pulseaudio.internal; import java.io.IOException; -import java.io.InputStream; import java.net.Socket; import java.time.Duration; import java.time.Instant; import java.util.HashSet; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider; -import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader; -import javax.sound.sampled.AudioFileFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -44,7 +37,6 @@ import org.openhab.core.library.types.PercentType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.tritonus.share.sampled.file.TAudioFileFormat; /** * The audio sink for openhab, implemented by a connection to a pulseaudio sink @@ -90,52 +82,6 @@ public String getId() { return pulseaudioHandler.getThing().getLabel(); } - /** - * Convert MP3 to PCM, as this is the only possible format - * - * @param input - * @return - */ - private @Nullable AudioStreamAndDuration getPCMStreamFromMp3Stream(InputStream input) { - try { - - MpegAudioFileReader mpegAudioFileReader = new MpegAudioFileReader(); - - int duration = -1; - if (input instanceof FixedLengthAudioStream) { - final Long audioFileLength = ((FixedLengthAudioStream) input).length(); - AudioFileFormat audioFileFormat = mpegAudioFileReader.getAudioFileFormat(input); - if (audioFileFormat instanceof TAudioFileFormat) { - Map taudioFileFormatProperties = ((TAudioFileFormat) audioFileFormat).properties(); - if (taudioFileFormatProperties.containsKey("mp3.framesize.bytes") - && taudioFileFormatProperties.containsKey("mp3.framerate.fps")) { - Integer frameSize = (Integer) taudioFileFormatProperties.get("mp3.framesize.bytes"); - Float frameRate = (Float) taudioFileFormatProperties.get("mp3.framerate.fps"); - if (frameSize != null && frameRate != null) { - duration = Math.round((audioFileLength / (frameSize * frameRate)) * 1000); - } - } - } - input.reset(); - } - - AudioInputStream sourceAIS = mpegAudioFileReader.getAudioInputStream(input); - javax.sound.sampled.AudioFormat sourceFormat = sourceAIS.getFormat(); - - MpegFormatConversionProvider mpegconverter = new MpegFormatConversionProvider(); - javax.sound.sampled.AudioFormat convertFormat = new javax.sound.sampled.AudioFormat( - javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), 16, - sourceFormat.getChannels(), sourceFormat.getChannels() * 2, sourceFormat.getSampleRate(), false); - - AudioInputStream audioInputStreamConverted = mpegconverter.getAudioInputStream(convertFormat, sourceAIS); - return new AudioStreamAndDuration(audioInputStreamConverted, duration); - - } catch (IOException | UnsupportedAudioFileException e) { - logger.warn("Cannot convert this mp3 stream to pcm stream: {}", e.getMessage()); - } - return null; - } - /** * Connect to pulseaudio with the simple protocol * @@ -168,23 +114,6 @@ public void disconnect() { } } - private AudioStreamAndDuration getWavAudioAndDuration(AudioStream audioStream) { - int duration = -1; - if (audioStream instanceof FixedLengthAudioStream) { - final Long audioFileLength = ((FixedLengthAudioStream) audioStream).length(); - try { - AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(audioStream); - int frameSize = audioInputStream.getFormat().getFrameSize(); - float frameRate = audioInputStream.getFormat().getFrameRate(); - float durationInSeconds = (audioFileLength / (frameSize * frameRate)); - duration = Math.round(durationInSeconds * 1000); - } catch (UnsupportedAudioFileException | IOException e) { - logger.warn("Error when getting duration information from AudioFile"); - } - } - return new AudioStreamAndDuration(audioStream, duration); - } - @Override public void process(@Nullable AudioStream audioStream) throws UnsupportedAudioFormatException, UnsupportedAudioStreamException { @@ -193,34 +122,22 @@ public void process(@Nullable AudioStream audioStream) return; } - AudioStreamAndDuration audioInputStreamAndDuration = null; - try { - - if (AudioFormat.MP3.isCompatible(audioStream.getFormat())) { - audioInputStreamAndDuration = getPCMStreamFromMp3Stream(audioStream); - } else if (AudioFormat.WAV.isCompatible(audioStream.getFormat())) { - audioInputStreamAndDuration = getWavAudioAndDuration(audioStream); - } else { - throw new UnsupportedAudioFormatException("pulseaudio audio sink can only play pcm or mp3 stream", - audioStream.getFormat()); - } - + try (ConvertedInputStream normalizedPCMStream = new ConvertedInputStream(audioStream)) { for (int countAttempt = 1; countAttempt <= 2; countAttempt++) { // two attempts allowed try { connectIfNeeded(); final Socket clientSocketLocal = clientSocket; - if (audioInputStreamAndDuration != null && clientSocketLocal != null) { + if (clientSocketLocal != null) { // send raw audio to the socket and to pulse audio isIdle = false; Instant start = Instant.now(); - audioInputStreamAndDuration.inputStream.transferTo(clientSocketLocal.getOutputStream()); - if (audioInputStreamAndDuration.duration != -1) { // ensure, if the sound has a duration + normalizedPCMStream.transferTo(clientSocketLocal.getOutputStream()); + if (normalizedPCMStream.getDuration() != -1) { // ensure, if the sound has a duration // that we let at least this time for the system to play Instant end = Instant.now(); long millisSecondTimedToSendAudioData = Duration.between(start, end).toMillis(); - if (millisSecondTimedToSendAudioData < audioInputStreamAndDuration.duration) { - long timeToSleep = audioInputStreamAndDuration.duration - - millisSecondTimedToSendAudioData; + if (millisSecondTimedToSendAudioData < normalizedPCMStream.getDuration()) { + long timeToSleep = normalizedPCMStream.getDuration() - millisSecondTimedToSendAudioData; logger.debug("Sleep time to let the system play sound : {}", timeToSleep); Thread.sleep(timeToSleep); } @@ -243,15 +160,11 @@ public void process(@Nullable AudioStream audioStream) break; } } + } catch (UnsupportedAudioFileException | IOException e) { + throw new UnsupportedAudioFormatException("Cannot send sound to the pulseaudio sink", + audioStream.getFormat(), e); } finally { - try { - if (audioInputStreamAndDuration != null) { - audioInputStreamAndDuration.inputStream.close(); - } - audioStream.close(); - scheduleDisconnect(); - } catch (IOException e) { - } + scheduleDisconnect(); } isIdle = true; } @@ -286,15 +199,4 @@ public PercentType getVolume() { public void setVolume(PercentType volume) { pulseaudioHandler.setVolume(volume.intValue()); } - - private static class AudioStreamAndDuration { - private InputStream inputStream; - private int duration; - - public AudioStreamAndDuration(InputStream inputStream, int duration) { - super(); - this.inputStream = inputStream; - this.duration = duration + 200; // introduce some delay - } - } } From c0bc19bcf9af3e42c9269eca4c202b80fd806973 Mon Sep 17 00:00:00 2001 From: Flole998 Date: Sat, 11 Dec 2021 17:02:27 +0100 Subject: [PATCH 203/361] [Homematic] Fix "Channel not found for Datapoint"-Errors (#11493) Signed-off-by: Flole Signed-off-by: Michael Schmidt --- .../handler/HomematicThingHandler.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/handler/HomematicThingHandler.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/handler/HomematicThingHandler.java index 204e29dc458fc..a8313e1b7df04 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/handler/HomematicThingHandler.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/handler/HomematicThingHandler.java @@ -147,10 +147,52 @@ private void doInitializeInBackground() throws GatewayNotAvailableException, Hom } updateConfiguration(config); + boolean channelsChanged = false; + // update thing channel list for reconfigurable channels (relies on the new value of the // CHANNEL_FUNCTION datapoint fetched during configuration update) List thingChannels = new ArrayList<>(getThing().getChannels()); + + if (thingChannels.isEmpty()) { + for (HmChannel channel : device.getChannels()) { + for (HmDatapoint dp : channel.getDatapoints()) { + if (HomematicTypeGeneratorImpl.isIgnoredDatapoint(dp) + || dp.getParamsetType() != HmParamsetType.VALUES) { + continue; + } + ChannelUID channelUID = UidUtils.generateChannelUID(dp, getThing().getUID()); + if (containsChannel(thingChannels, channelUID)) { + // Channel is already present + continue; + } + + ChannelTypeUID channelTypeUID = UidUtils.generateChannelTypeUID(dp); + ChannelType channelType = channelTypeProvider.getInternalChannelType(channelTypeUID); + if (channelType == null) { + channelType = HomematicTypeGeneratorImpl.createChannelType(dp, channelTypeUID); + channelTypeProvider.addChannelType(channelType); + } + + Channel thingChannel = ChannelBuilder.create(channelUID, MetadataUtils.getItemType(dp)) + .withLabel(MetadataUtils.getLabel(dp)) + .withDescription(MetadataUtils.getDatapointDescription(dp)).withType(channelType.getUID()) + .build(); + thingChannels.add(thingChannel); + + logger.debug( + "Updated value datapoints for channel {} of device '{}' (function {}), now has {} datapoints", + channel, channel.getDevice().getAddress(), channel.getCurrentFunction(), + channel.getDatapoints().size()); + } + } + channelsChanged = true; + } + if (updateDynamicChannelList(device, thingChannels)) { + channelsChanged = true; + } + + if (channelsChanged) { updateThing(editThing().withChannels(thingChannels).build()); } From 784e902f23de4d57327970c29ff6673626223bb0 Mon Sep 17 00:00:00 2001 From: jlaur Date: Sat, 11 Dec 2021 17:20:11 +0100 Subject: [PATCH 204/361] [hdpowerview] Add support for enabling/disabling automations (#11637) * Add support for enabling/disabling automations. Fixes #11516 Signed-off-by: Jacob Laursen * Fix class description. Signed-off-by: Jacob Laursen * Document automation channel and channel groups. Signed-off-by: Jacob Laursen * Update scene example in documentation. Signed-off-by: Jacob Laursen * Consolidate method for getting channel map. Signed-off-by: Jacob Laursen * Extract channel updating from data fetching methods. Signed-off-by: Jacob Laursen * Draft implementation of better automation description. Signed-off-by: Jacob Laursen * Simplify and optimize building weekday string. Signed-off-by: Jacob Laursen * Further simplify building weekday string. Signed-off-by: Jacob Laursen * Update scheduled event channels when modified. Signed-off-by: Jacob Laursen * Update scene channels when modified. Signed-off-by: Jacob Laursen * Update scene group channels when modified. Signed-off-by: Jacob Laursen * Fix cache synchronization during initialization. Signed-off-by: Jacob Laursen * Reduced code duplication. Signed-off-by: Jacob Laursen * Shorten time formatting. Signed-off-by: Jacob Laursen * Danish translations for dynamic channels. Signed-off-by: Jacob Laursen * Simplify, optimize and fix dynamic channel creation. Channel order is now preserved when updating an existing channel. Scenes and scene collection are sorted correctly. Signed-off-by: Jacob Laursen * Provide backwards compatibility for deprecated channels. Signed-off-by: Jacob Laursen * Document purpose of createDeprecatedSceneChannels. Signed-off-by: Jacob Laursen * Cleaned up poll method for improved readability. Signed-off-by: Jacob Laursen * Fix potential race condition when initialize() is called while updating channels. Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- .../org.openhab.binding.hdpowerview/README.md | 14 +- .../internal/HDPowerViewBindingConstants.java | 7 +- .../HDPowerViewTranslationProvider.java | 6 + .../internal/HDPowerViewWebTargets.java | 42 +- .../api/responses/SceneCollections.java | 36 +- .../internal/api/responses/Scenes.java | 35 +- .../api/responses/ScheduledEvents.java | 132 ++++++ .../handler/HDPowerViewHubHandler.java | 397 ++++++++++++++---- .../OH-INF/i18n/hdpowerview.properties | 15 + .../OH-INF/i18n/hdpowerview_da.properties | 19 + .../resources/OH-INF/thing/thing-types.xml | 23 + 11 files changed, 629 insertions(+), 97 deletions(-) create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/ScheduledEvents.java create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties diff --git a/bundles/org.openhab.binding.hdpowerview/README.md b/bundles/org.openhab.binding.hdpowerview/README.md index 60601cf6c2ec6..023e621399116 100644 --- a/bundles/org.openhab.binding.hdpowerview/README.md +++ b/bundles/org.openhab.binding.hdpowerview/README.md @@ -60,13 +60,15 @@ However, the configuration parameters are described below: ### Channels for PowerView Hub -Scene and scene group channels will be added dynamically to the binding as they are discovered in the hub. -Each scene/scene group channel will have an entry in the hub as shown below, whereby different scenes/scene groups +Scene, scene group and automation channels will be added dynamically to the binding as they are discovered in the hub. +Each will have an entry in the hub as shown below, whereby different scenes, scene groups and automations have different `id` values: -| Channel | Item Type | Description | -|----------|-----------| ------------| -| id | Switch | Turning this to ON will activate the scene/scene group. Scenes/scene groups are stateless in the PowerView hub; they have no on/off state. Note: include `{autoupdate="false"}` in the item configuration to avoid having to reset it to off after use. | +| Channel Group | Channel | Item Type | Description | +|---------------|---------|-----------|-------------| +| scenes | id | Switch | Setting this to ON will activate the scene. Scenes are stateless in the PowerView hub; they have no on/off state. Note: include `{autoupdate="false"}` in the item configuration to avoid having to reset it to off after use. | +| sceneGroups | id | Switch | Setting this to ON will activate the scene group. Scene groups are stateless in the PowerView hub; they have no on/off state. Note: include `{autoupdate="false"}` in the item configuration to avoid having to reset it to off after use. | +| automations | id | Switch | Setting this to ON will enable the automation, while OFF will disable it. | ### Channels for PowerView Shade @@ -181,7 +183,7 @@ Switch Living_Room_Shade_Battery_Low_Alarm "Living Room Shade Battery Low Alarm Scene items: ``` -Switch Living_Room_Shades_Scene_Heart "Living Room Shades Scene Heart" (g_Shades_Scene_Trigger) {channel="hdpowerview:hub:g24:22663", autoupdate="false"} +Switch Living_Room_Shades_Scene_Heart "Living Room Shades Scene Heart" (g_Shades_Scene_Trigger) {channel="hdpowerview:hub:g24:scenes#22663", autoupdate="false"} ``` ### `demo.sitemap` File diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java index 6eb621157351e..e4352e6a7b098 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java @@ -26,7 +26,7 @@ * * @author Andy Lintner - Initial contribution * @author Andrew Fiddian-Green - Added support for secondary rail positions - * @author Jacob Laursen - Add support for scene groups + * @author Jacob Laursen - Add support for scene groups and automations */ @NonNullByDefault public class HDPowerViewBindingConstants { @@ -46,8 +46,13 @@ public class HDPowerViewBindingConstants { public static final String CHANNEL_SHADE_BATTERY_VOLTAGE = "batteryVoltage"; public static final String CHANNEL_SHADE_SIGNAL_STRENGTH = "signalStrength"; + public static final String CHANNEL_GROUP_SCENES = "scenes"; + public static final String CHANNEL_GROUP_SCENE_GROUPS = "sceneGroups"; + public static final String CHANNEL_GROUP_AUTOMATIONS = "automations"; + public static final String CHANNELTYPE_SCENE_ACTIVATE = "scene-activate"; public static final String CHANNELTYPE_SCENE_GROUP_ACTIVATE = "scene-group-activate"; + public static final String CHANNELTYPE_AUTOMATION_ENABLED = "automation-enabled"; public static final List NETBIOS_NAMES = Arrays.asList("PDBU-Hub3.0", "PowerView-Hub"); diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewTranslationProvider.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewTranslationProvider.java index adf16057a153a..5f7e42d2d308c 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewTranslationProvider.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewTranslationProvider.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.hdpowerview.internal; +import java.util.Locale; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.i18n.LocaleProvider; @@ -44,4 +46,8 @@ public String getText(String key, @Nullable Object... arguments) { } return key; } + + public Locale getLocale() { + return localeProvider.getLocale(); + } } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java index 0afa08478341a..8fee72166c96a 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java @@ -30,20 +30,23 @@ import org.openhab.binding.hdpowerview.internal.api.requests.ShadeStop; import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections; import org.openhab.binding.hdpowerview.internal.api.responses.Scenes; +import org.openhab.binding.hdpowerview.internal.api.responses.ScheduledEvents; import org.openhab.binding.hdpowerview.internal.api.responses.Shade; import org.openhab.binding.hdpowerview.internal.api.responses.Shades; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; +import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; /** * JAX-RS targets for communicating with an HD PowerView hub * * @author Andy Lintner - Initial contribution * @author Andrew Fiddian-Green - Added support for secondary rail positions - * @author Jacob Laursen - Add support for scene groups + * @author Jacob Laursen - Add support for scene groups and automations */ @NonNullByDefault public class HDPowerViewWebTargets { @@ -65,6 +68,7 @@ public class HDPowerViewWebTargets { private final String scenes; private final String sceneCollectionActivate; private final String sceneCollections; + private final String scheduledEvents; private final Gson gson = new Gson(); private final HttpClient httpClient; @@ -107,6 +111,7 @@ public HDPowerViewWebTargets(HttpClient httpClient, String ipAddress) { scenes = base + "scenes/"; sceneCollectionActivate = base + "sceneCollections"; sceneCollections = base + "sceneCollections/"; + scheduledEvents = base + "scheduledevents"; this.httpClient = httpClient; } @@ -189,6 +194,41 @@ public void activateSceneCollection(int sceneCollectionId) throws HubProcessingE Query.of("sceneCollectionId", Integer.toString(sceneCollectionId)), null); } + /** + * Fetches a JSON package that describes all scheduled events in the hub, and wraps it in + * a ScheduledEvents class instance + * + * @return ScheduledEvents class instance + * @throws JsonParseException if there is a JSON parsing error + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public @Nullable ScheduledEvents getScheduledEvents() + throws JsonParseException, HubProcessingException, HubMaintenanceException { + String json = invoke(HttpMethod.GET, scheduledEvents, null, null); + return gson.fromJson(json, ScheduledEvents.class); + } + + /** + * Enables or disables a scheduled event in the hub. + * + * @param scheduledEventId id of the scheduled event to be enabled or disabled + * @param enable true to enable scheduled event, false to disable + * @throws JsonParseException if there is a JSON parsing error + * @throws JsonSyntaxException if there is a JSON syntax error + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public void enableScheduledEvent(int scheduledEventId, boolean enable) + throws JsonParseException, HubProcessingException, HubMaintenanceException { + String uri = scheduledEvents + "/" + scheduledEventId; + String json = invoke(HttpMethod.GET, uri, null, null); + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); + JsonObject scheduledEventObject = jsonObject.get("scheduledEvent").getAsJsonObject(); + scheduledEventObject.addProperty("enabled", enable); + invoke(HttpMethod.PUT, uri, null, jsonObject.toString()); + } + /** * Invoke a call on the hub server to retrieve information or send a command * diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/SceneCollections.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/SceneCollections.java index f4822b0693c7c..7a4aea8d5d318 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/SceneCollections.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/SceneCollections.java @@ -20,7 +20,7 @@ import org.eclipse.jdt.annotation.Nullable; /** - * State of all Scenes in an HD PowerView hub + * State of all Scene Collections in an HD PowerView hub * * @author Jacob Laursen - Initial contribution */ @@ -38,13 +38,45 @@ public class SceneCollections { */ @SuppressWarnings("null") @NonNullByDefault - public static class SceneCollection { + public static class SceneCollection implements Comparable { public int id; public @Nullable String name; public int order; public int colorId; public int iconId; + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + if (!(o instanceof SceneCollection)) { + return false; + } + SceneCollection other = (SceneCollection) o; + + return this.id == other.id && this.name.equals(other.name) && this.order == other.order + && this.colorId == other.colorId && this.iconId == other.iconId; + } + + @Override + public final int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + (name == null ? 0 : name.hashCode()); + result = prime * result + order; + result = prime * result + colorId; + result = prime * result + iconId; + + return result; + } + + @Override + public int compareTo(SceneCollection other) { + return Integer.compare(order, other.order); + } + public String getName() { return new String(Base64.getDecoder().decode(name), StandardCharsets.UTF_8); } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Scenes.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Scenes.java index cf759e84fc389..c9372112a9a67 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Scenes.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Scenes.java @@ -38,7 +38,7 @@ public class Scenes { */ @SuppressWarnings("null") @NonNullByDefault - public static class Scene { + public static class Scene implements Comparable { public int id; public @Nullable String name; public int roomId; @@ -46,6 +46,39 @@ public static class Scene { public int colorId; public int iconId; + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Scene)) { + return false; + } + Scene other = (Scene) o; + + return this.id == other.id && this.name.equals(other.name) && this.roomId == other.roomId + && this.order == other.order && this.colorId == other.colorId && this.iconId == other.iconId; + } + + @Override + public final int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + (name == null ? 0 : name.hashCode()); + result = prime * result + roomId; + result = prime * result + order; + result = prime * result + colorId; + result = prime * result + iconId; + + return result; + } + + @Override + public int compareTo(Scene other) { + return Integer.compare(order, other.order); + } + public String getName() { return new String(Base64.getDecoder().decode(name), StandardCharsets.UTF_8); } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/ScheduledEvents.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/ScheduledEvents.java new file mode 100644 index 0000000000000..ec1fac312ba26 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/ScheduledEvents.java @@ -0,0 +1,132 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.hdpowerview.internal.api.responses; + +import java.time.DayOfWeek; +import java.util.EnumSet; +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * State of all Scheduled Events in an HD PowerView hub + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class ScheduledEvents { + + public static final EnumSet WEEKDAYS = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, + DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY); + + public static final EnumSet WEEKENDS = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY); + + public static final int SCHEDULED_EVENT_TYPE_TIME = 0; + public static final int SCHEDULED_EVENT_TYPE_SUNRISE = 1; + public static final int SCHEDULED_EVENT_TYPE_SUNSET = 2; + + public @Nullable List scheduledEventData; + public @Nullable List scheduledEventIds; + + /* + * the following SuppressWarnings annotation is because the Eclipse compiler + * does NOT expect a NonNullByDefault annotation on the inner class, since it is + * implicitly inherited from the outer class, whereas the Maven compiler always + * requires an explicit NonNullByDefault annotation on all classes + */ + @SuppressWarnings("null") + @NonNullByDefault + public static class ScheduledEvent { + public int id; + public boolean enabled; + public int sceneId; + public int sceneCollectionId; + public boolean daySunday; + public boolean dayMonday; + public boolean dayTuesday; + public boolean dayWednesday; + public boolean dayThursday; + public boolean dayFriday; + public boolean daySaturday; + public int eventType; + public int hour; + public int minute; + + @Override + public boolean equals(@Nullable Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ScheduledEvent)) { + return false; + } + ScheduledEvent other = (ScheduledEvent) o; + + return this.id == other.id && this.enabled == other.enabled && this.sceneId == other.sceneId + && this.sceneCollectionId == other.sceneCollectionId && this.daySunday == other.daySunday + && this.dayMonday == other.dayMonday && this.dayTuesday == other.dayTuesday + && this.dayWednesday == other.dayWednesday && this.dayThursday == other.dayThursday + && this.dayFriday == other.dayFriday && this.daySaturday == other.daySaturday + && this.eventType == other.eventType && this.hour == other.hour && this.minute == other.minute; + } + + @Override + public final int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + result = prime * result + (enabled ? 1 : 0); + result = prime * result + sceneId; + result = prime * result + sceneCollectionId; + result = prime * result + (daySunday ? 1 : 0); + result = prime * result + (dayMonday ? 1 : 0); + result = prime * result + (dayTuesday ? 1 : 0); + result = prime * result + (dayWednesday ? 1 : 0); + result = prime * result + (dayThursday ? 1 : 0); + result = prime * result + (dayFriday ? 1 : 0); + result = prime * result + (daySaturday ? 1 : 0); + result = prime * result + eventType; + result = prime * result + hour; + result = prime * result + minute; + + return result; + } + + public EnumSet getDays() { + EnumSet days = EnumSet.noneOf(DayOfWeek.class); + if (daySunday) { + days.add(DayOfWeek.SUNDAY); + } + if (dayMonday) { + days.add(DayOfWeek.MONDAY); + } + if (dayTuesday) { + days.add(DayOfWeek.TUESDAY); + } + if (dayWednesday) { + days.add(DayOfWeek.WEDNESDAY); + } + if (dayThursday) { + days.add(DayOfWeek.THURSDAY); + } + if (dayFriday) { + days.add(DayOfWeek.FRIDAY); + } + if (daySaturday) { + days.add(DayOfWeek.SATURDAY); + } + return days; + } + } +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index 2eda6b8b23598..3b3579a363e7f 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -12,11 +12,17 @@ */ package org.openhab.binding.hdpowerview.internal.handler; +import java.time.DayOfWeek; +import java.time.LocalTime; +import java.time.format.TextStyle; import java.util.ArrayList; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.StringJoiner; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -34,13 +40,17 @@ import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections.SceneCollection; import org.openhab.binding.hdpowerview.internal.api.responses.Scenes; import org.openhab.binding.hdpowerview.internal.api.responses.Scenes.Scene; +import org.openhab.binding.hdpowerview.internal.api.responses.ScheduledEvents; +import org.openhab.binding.hdpowerview.internal.api.responses.ScheduledEvents.ScheduledEvent; import org.openhab.binding.hdpowerview.internal.api.responses.Shades; import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData; import org.openhab.binding.hdpowerview.internal.config.HDPowerViewHubConfiguration; import org.openhab.binding.hdpowerview.internal.config.HDPowerViewShadeConfiguration; +import org.openhab.core.library.CoreItemFactory; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelGroupUID; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -62,7 +72,7 @@ * * @author Andy Lintner - Initial contribution * @author Andrew Fiddian-Green - Added support for secondary rail positions - * @author Jacob Laursen - Add support for scene groups + * @author Jacob Laursen - Add support for scene groups and automations */ @NonNullByDefault public class HDPowerViewHubHandler extends BaseBridgeHandler { @@ -80,11 +90,19 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler { private @Nullable ScheduledFuture hardRefreshPositionFuture; private @Nullable ScheduledFuture hardRefreshBatteryLevelFuture; + private List sceneCache = new CopyOnWriteArrayList<>(); + private List sceneCollectionCache = new CopyOnWriteArrayList<>(); + private List scheduledEventCache = new CopyOnWriteArrayList<>(); + private Boolean deprecatedChannelsCreated = false; + private final ChannelTypeUID sceneChannelTypeUID = new ChannelTypeUID(HDPowerViewBindingConstants.BINDING_ID, HDPowerViewBindingConstants.CHANNELTYPE_SCENE_ACTIVATE); - private final ChannelTypeUID sceneCollectionChannelTypeUID = new ChannelTypeUID( - HDPowerViewBindingConstants.BINDING_ID, HDPowerViewBindingConstants.CHANNELTYPE_SCENE_GROUP_ACTIVATE); + private final ChannelTypeUID sceneGroupChannelTypeUID = new ChannelTypeUID(HDPowerViewBindingConstants.BINDING_ID, + HDPowerViewBindingConstants.CHANNELTYPE_SCENE_GROUP_ACTIVATE); + + private final ChannelTypeUID automationChannelTypeUID = new ChannelTypeUID(HDPowerViewBindingConstants.BINDING_ID, + HDPowerViewBindingConstants.CHANNELTYPE_AUTOMATION_ENABLED); public HDPowerViewHubHandler(Bridge bridge, HttpClient httpClient, HDPowerViewTranslationProvider translationProvider) { @@ -100,10 +118,6 @@ public void handleCommand(ChannelUID channelUID, Command command) { return; } - if (!OnOffType.ON.equals(command)) { - return; - } - Channel channel = getThing().getChannel(channelUID.getId()); if (channel == null) { return; @@ -114,11 +128,13 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (webTargets == null) { throw new ProcessingException("Web targets not initialized"); } - int id = Integer.parseInt(channelUID.getId()); - if (sceneChannelTypeUID.equals(channel.getChannelTypeUID())) { + int id = Integer.parseInt(channelUID.getIdWithoutGroup()); + if (sceneChannelTypeUID.equals(channel.getChannelTypeUID()) && OnOffType.ON.equals(command)) { webTargets.activateScene(id); - } else if (sceneCollectionChannelTypeUID.equals(channel.getChannelTypeUID())) { + } else if (sceneGroupChannelTypeUID.equals(channel.getChannelTypeUID()) && OnOffType.ON.equals(command)) { webTargets.activateSceneCollection(id); + } else if (automationChannelTypeUID.equals(channel.getChannelTypeUID())) { + webTargets.enableScheduledEvent(id, OnOffType.ON.equals(command)); } } catch (HubMaintenanceException e) { // exceptions are logged in HDPowerViewWebTargets @@ -143,9 +159,18 @@ public void initialize() { refreshInterval = config.refresh; hardRefreshPositionInterval = config.hardRefresh; hardRefreshBatteryLevelInterval = config.hardRefreshBatteryLevel; + initializeChannels(); schedulePoll(); } + private void initializeChannels() { + // Rebuild dynamic channels and synchronize with cache. + updateThing(editThing().withChannels(new ArrayList()).build()); + sceneCache.clear(); + sceneCollectionCache.clear(); + scheduledEventCache.clear(); + } + public @Nullable HDPowerViewWebTargets getWebTargets() { return webTargets; } @@ -215,8 +240,14 @@ private synchronized void poll() { try { logger.debug("Polling for state"); pollShades(); - pollScenes(); - pollSceneCollections(); + + List scenes = updateSceneChannels(); + List sceneCollections = updateSceneCollectionChannels(); + List scheduledEvents = updateScheduledEventChannels(scenes, sceneCollections); + + // Scheduled events should also have their current state updated if event has been + // enabled or disabled through app or other integration. + updateScheduledEventStates(scheduledEvents); } catch (JsonParseException e) { logger.warn("Bridge returned a bad JSON response: {}", e.getMessage()); } catch (HubProcessingException e) { @@ -270,7 +301,7 @@ private void updateShadeThing(String shadeId, Thing thing, @Nullable ShadeData s thingHandler.onReceiveUpdate(shadeData); } - private void pollScenes() throws JsonParseException, HubProcessingException, HubMaintenanceException { + private List fetchScenes() throws JsonParseException, HubProcessingException, HubMaintenanceException { HDPowerViewWebTargets webTargets = this.webTargets; if (webTargets == null) { throw new ProcessingException("Web targets not initialized"); @@ -287,41 +318,86 @@ private void pollScenes() throws JsonParseException, HubProcessingException, Hub } logger.debug("Received data for {} scenes", sceneData.size()); - Map idChannelMap = getIdSceneChannelMap(); - List allChannels = new ArrayList<>(getThing().getChannels()); - boolean isChannelListChanged = false; - for (Scene scene : sceneData) { - // remove existing scene channel from the map - String sceneId = Integer.toString(scene.id); - if (idChannelMap.containsKey(sceneId)) { - idChannelMap.remove(sceneId); - logger.debug("Keeping channel for existing scene '{}'", sceneId); - } else { - // create a new scene channel - ChannelUID channelUID = new ChannelUID(getThing().getUID(), sceneId); - String description = translationProvider.getText("dynamic-channel.scene-activate.description", - scene.getName()); - Channel channel = ChannelBuilder.create(channelUID, "Switch").withType(sceneChannelTypeUID) - .withLabel(scene.getName()).withDescription(description).build(); - allChannels.add(channel); - isChannelListChanged = true; - logger.debug("Creating new channel for scene '{}'", sceneId); - } - } + return sceneData; + } + + private List updateSceneChannels() + throws JsonParseException, HubProcessingException, HubMaintenanceException { + List scenes = fetchScenes(); - // remove any previously created channels that no longer exist - if (!idChannelMap.isEmpty()) { - logger.debug("Removing {} orphan scene channels", idChannelMap.size()); - allChannels.removeAll(idChannelMap.values()); - isChannelListChanged = true; + if (scenes.size() == sceneCache.size() && sceneCache.containsAll(scenes)) { + // Duplicates are not allowed. Reordering is not supported. + logger.debug("Preserving scene channels, no changes detected"); + return scenes; } - if (isChannelListChanged) { - updateThing(editThing().withChannels(allChannels).build()); + logger.debug("Updating all scene channels, changes detected"); + sceneCache = new CopyOnWriteArrayList(scenes); + + List allChannels = new ArrayList<>(getThing().getChannels()); + allChannels.removeIf(c -> HDPowerViewBindingConstants.CHANNEL_GROUP_SCENES.equals(c.getUID().getGroupId())); + scenes.stream().sorted().forEach(scene -> allChannels.add(createSceneChannel(scene))); + updateThing(editThing().withChannels(allChannels).build()); + + createDeprecatedSceneChannels(scenes); + + return scenes; + } + + private Channel createSceneChannel(Scene scene) { + ChannelGroupUID channelGroupUid = new ChannelGroupUID(thing.getUID(), + HDPowerViewBindingConstants.CHANNEL_GROUP_SCENES); + ChannelUID channelUid = new ChannelUID(channelGroupUid, Integer.toString(scene.id)); + String description = translationProvider.getText("dynamic-channel.scene-activate.description", scene.getName()); + Channel channel = ChannelBuilder.create(channelUid, CoreItemFactory.SWITCH).withType(sceneChannelTypeUID) + .withLabel(scene.getName()).withDescription(description).build(); + + return channel; + } + + /** + * Create backwards compatible scene channels if any items configured before release 3.2 + * are still linked. Users should have a reasonable amount of time to migrate to the new + * scene channels that are connected to a channel group. + */ + private void createDeprecatedSceneChannels(List scenes) { + if (deprecatedChannelsCreated) { + // Only do this once. + return; } + ChannelGroupUID channelGroupUid = new ChannelGroupUID(thing.getUID(), + HDPowerViewBindingConstants.CHANNEL_GROUP_SCENES); + for (Scene scene : scenes) { + String channelId = Integer.toString(scene.id); + ChannelUID newChannelUid = new ChannelUID(channelGroupUid, channelId); + ChannelUID deprecatedChannelUid = new ChannelUID(getThing().getUID(), channelId); + String description = translationProvider.getText("dynamic-channel.scene-activate.deprecated.description", + scene.getName()); + Channel channel = ChannelBuilder.create(deprecatedChannelUid, CoreItemFactory.SWITCH) + .withType(sceneChannelTypeUID).withLabel(scene.getName()).withDescription(description).build(); + logger.debug("Creating deprecated channel '{}' ('{}') to probe for linked items", deprecatedChannelUid, + scene.getName()); + updateThing(editThing().withChannel(channel).build()); + if (this.isLinked(deprecatedChannelUid) && !this.isLinked(newChannelUid)) { + logger.warn("Created deprecated channel '{}' ('{}'), please link items to '{}' instead", + deprecatedChannelUid, scene.getName(), newChannelUid); + } else { + if (this.isLinked(newChannelUid)) { + logger.debug("Removing deprecated channel '{}' ('{}') since new channel '{}' is linked", + deprecatedChannelUid, scene.getName(), newChannelUid); + + } else { + logger.debug("Removing deprecated channel '{}' ('{}') since it has no linked items", + deprecatedChannelUid, scene.getName()); + } + updateThing(editThing().withoutChannel(deprecatedChannelUid).build()); + } + } + deprecatedChannelsCreated = true; } - private void pollSceneCollections() throws JsonParseException, HubProcessingException, HubMaintenanceException { + private List fetchSceneCollections() + throws JsonParseException, HubProcessingException, HubMaintenanceException { HDPowerViewWebTargets webTargets = this.webTargets; if (webTargets == null) { throw new ProcessingException("Web targets not initialized"); @@ -338,37 +414,206 @@ private void pollSceneCollections() throws JsonParseException, HubProcessingExce } logger.debug("Received data for {} sceneCollections", sceneCollectionData.size()); - Map idChannelMap = getIdSceneCollectionChannelMap(); + return sceneCollectionData; + } + + private List updateSceneCollectionChannels() + throws JsonParseException, HubProcessingException, HubMaintenanceException { + List sceneCollections = fetchSceneCollections(); + + if (sceneCollections.size() == sceneCollectionCache.size() + && sceneCollectionCache.containsAll(sceneCollections)) { + // Duplicates are not allowed. Reordering is not supported. + logger.debug("Preserving scene collection channels, no changes detected"); + return sceneCollections; + } + + logger.debug("Updating all scene collection channels, changes detected"); + sceneCollectionCache = new CopyOnWriteArrayList(sceneCollections); + List allChannels = new ArrayList<>(getThing().getChannels()); - boolean isChannelListChanged = false; - for (SceneCollection sceneCollection : sceneCollectionData) { - // remove existing scene collection channel from the map - String sceneCollectionId = Integer.toString(sceneCollection.id); - if (idChannelMap.containsKey(sceneCollectionId)) { - idChannelMap.remove(sceneCollectionId); - logger.debug("Keeping channel for existing scene collection '{}'", sceneCollectionId); - } else { - // create a new scene collection channel - ChannelUID channelUID = new ChannelUID(getThing().getUID(), sceneCollectionId); - String description = translationProvider.getText("dynamic-channel.scene-group-activate.description", - sceneCollection.getName()); - Channel channel = ChannelBuilder.create(channelUID, "Switch").withType(sceneCollectionChannelTypeUID) - .withLabel(sceneCollection.getName()).withDescription(description).build(); + allChannels + .removeIf(c -> HDPowerViewBindingConstants.CHANNEL_GROUP_SCENE_GROUPS.equals(c.getUID().getGroupId())); + sceneCollections.stream().sorted() + .forEach(sceneCollection -> allChannels.add(createSceneCollectionChannel(sceneCollection))); + updateThing(editThing().withChannels(allChannels).build()); + + return sceneCollections; + } + + private Channel createSceneCollectionChannel(SceneCollection sceneCollection) { + ChannelGroupUID channelGroupUid = new ChannelGroupUID(thing.getUID(), + HDPowerViewBindingConstants.CHANNEL_GROUP_SCENE_GROUPS); + ChannelUID channelUid = new ChannelUID(channelGroupUid, Integer.toString(sceneCollection.id)); + String description = translationProvider.getText("dynamic-channel.scene-group-activate.description", + sceneCollection.getName()); + Channel channel = ChannelBuilder.create(channelUid, CoreItemFactory.SWITCH).withType(sceneGroupChannelTypeUID) + .withLabel(sceneCollection.getName()).withDescription(description).build(); + + return channel; + } + + private List fetchScheduledEvents() + throws JsonParseException, HubProcessingException, HubMaintenanceException { + HDPowerViewWebTargets webTargets = this.webTargets; + if (webTargets == null) { + throw new ProcessingException("Web targets not initialized"); + } + + ScheduledEvents scheduledEvents = webTargets.getScheduledEvents(); + if (scheduledEvents == null) { + throw new JsonParseException("Missing 'scheduledEvents' element"); + } + + List scheduledEventData = scheduledEvents.scheduledEventData; + if (scheduledEventData == null) { + throw new JsonParseException("Missing 'scheduledEvents.scheduledEventData' element"); + } + logger.debug("Received data for {} scheduledEvents", scheduledEventData.size()); + + return scheduledEventData; + } + + private List updateScheduledEventChannels(List scenes, + List sceneCollections) + throws JsonParseException, HubProcessingException, HubMaintenanceException { + List scheduledEvents = fetchScheduledEvents(); + + if (scheduledEvents.size() == scheduledEventCache.size() && scheduledEventCache.containsAll(scheduledEvents)) { + // Duplicates are not allowed. Reordering is not supported. + logger.debug("Preserving scheduled event channels, no changes detected"); + return scheduledEvents; + } + + logger.debug("Updating all scheduled event channels, changes detected"); + scheduledEventCache = new CopyOnWriteArrayList(scheduledEvents); + + List allChannels = new ArrayList<>(getThing().getChannels()); + allChannels + .removeIf(c -> HDPowerViewBindingConstants.CHANNEL_GROUP_AUTOMATIONS.equals(c.getUID().getGroupId())); + scheduledEvents.stream().forEach(scheduledEvent -> { + Channel channel = createScheduledEventChannel(scheduledEvent, scenes, sceneCollections); + if (channel != null) { allChannels.add(channel); - isChannelListChanged = true; - logger.debug("Creating new channel for scene collection '{}'", sceneCollectionId); } + }); + updateThing(editThing().withChannels(allChannels).build()); + + return scheduledEvents; + } + + private @Nullable Channel createScheduledEventChannel(ScheduledEvent scheduledEvent, List scenes, + List sceneCollections) { + String referencedName = getReferencedSceneOrSceneCollectionName(scheduledEvent, scenes, sceneCollections); + if (referencedName == null) { + return null; + } + ChannelGroupUID channelGroupUid = new ChannelGroupUID(thing.getUID(), + HDPowerViewBindingConstants.CHANNEL_GROUP_AUTOMATIONS); + ChannelUID channelUid = new ChannelUID(channelGroupUid, Integer.toString(scheduledEvent.id)); + String label = getScheduledEventName(referencedName, scheduledEvent); + String description = translationProvider.getText("dynamic-channel.automation-enabled.description", + referencedName); + Channel channel = ChannelBuilder.create(channelUid, CoreItemFactory.SWITCH).withType(automationChannelTypeUID) + .withLabel(label).withDescription(description).build(); + + return channel; + } + + private @Nullable String getReferencedSceneOrSceneCollectionName(ScheduledEvent scheduledEvent, List scenes, + List sceneCollections) { + if (scheduledEvent.sceneId > 0) { + for (Scene scene : scenes) { + if (scene.id == scheduledEvent.sceneId) { + return scene.getName(); + } + } + logger.error("Scene '{}' was not found for scheduled event '{}'", scheduledEvent.sceneId, + scheduledEvent.id); + return null; + } else if (scheduledEvent.sceneCollectionId > 0) { + for (SceneCollection sceneCollection : sceneCollections) { + if (sceneCollection.id == scheduledEvent.sceneCollectionId) { + return sceneCollection.getName(); + } + } + logger.error("Scene collection '{}' was not found for scheduled event '{}'", + scheduledEvent.sceneCollectionId, scheduledEvent.id); + return null; + } else { + logger.error("Scheduled event '{}'' not related to any scene or scene collection", scheduledEvent.id); + return null; } + } - // remove any previously created channels that no longer exist - if (!idChannelMap.isEmpty()) { - logger.debug("Removing {} orphan scene collection channels", idChannelMap.size()); - allChannels.removeAll(idChannelMap.values()); - isChannelListChanged = true; + private String getScheduledEventName(String sceneName, ScheduledEvent scheduledEvent) { + String timeString, daysString; + + switch (scheduledEvent.eventType) { + case ScheduledEvents.SCHEDULED_EVENT_TYPE_TIME: + timeString = LocalTime.of(scheduledEvent.hour, scheduledEvent.minute).toString(); + break; + case ScheduledEvents.SCHEDULED_EVENT_TYPE_SUNRISE: + if (scheduledEvent.minute == 0) { + timeString = translationProvider.getText("dynamic-channel.automation.at_sunrise"); + } else if (scheduledEvent.minute < 0) { + timeString = translationProvider.getText("dynamic-channel.automation.before_sunrise", + getFormattedTimeOffset(-scheduledEvent.minute)); + } else { + timeString = translationProvider.getText("dynamic-channel.automation.after_sunrise", + getFormattedTimeOffset(scheduledEvent.minute)); + } + break; + case ScheduledEvents.SCHEDULED_EVENT_TYPE_SUNSET: + if (scheduledEvent.minute == 0) { + timeString = translationProvider.getText("dynamic-channel.automation.at_sunset"); + } else if (scheduledEvent.minute < 0) { + timeString = translationProvider.getText("dynamic-channel.automation.before_sunset", + getFormattedTimeOffset(-scheduledEvent.minute)); + } else { + timeString = translationProvider.getText("dynamic-channel.automation.after_sunset", + getFormattedTimeOffset(scheduledEvent.minute)); + } + break; + default: + return sceneName; + } + + EnumSet days = scheduledEvent.getDays(); + if (EnumSet.allOf(DayOfWeek.class).equals(days)) { + daysString = translationProvider.getText("dynamic-channel.automation.all-days"); + } else if (ScheduledEvents.WEEKDAYS.equals(days)) { + daysString = translationProvider.getText("dynamic-channel.automation.weekdays"); + } else if (ScheduledEvents.WEEKENDS.equals(days)) { + daysString = translationProvider.getText("dynamic-channel.automation.weekends"); + } else { + StringJoiner joiner = new StringJoiner(", "); + days.forEach(day -> joiner.add(day.getDisplayName(TextStyle.SHORT, translationProvider.getLocale()))); + daysString = joiner.toString(); } - if (isChannelListChanged) { - updateThing(editThing().withChannels(allChannels).build()); + return translationProvider.getText("dynamic-channel.automation-enabled.label", sceneName, timeString, + daysString); + } + + private String getFormattedTimeOffset(int minutes) { + if (minutes >= 60) { + int remainder = minutes % 60; + if (remainder == 0) { + return translationProvider.getText("dynamic-channel.automation.hour", minutes / 60); + } + return translationProvider.getText("dynamic-channel.automation.hour-minute", minutes / 60, remainder); + } + return translationProvider.getText("dynamic-channel.automation.minute", minutes); + } + + private void updateScheduledEventStates(List scheduledEvents) { + ChannelGroupUID channelGroupUid = new ChannelGroupUID(thing.getUID(), + HDPowerViewBindingConstants.CHANNEL_GROUP_AUTOMATIONS); + for (ScheduledEvent scheduledEvent : scheduledEvents) { + String scheduledEventId = Integer.toString(scheduledEvent.id); + ChannelUID channelUid = new ChannelUID(channelGroupUid, scheduledEventId); + updateState(channelUid, scheduledEvent.enabled ? OnOffType.ON : OnOffType.OFF); } } @@ -393,26 +638,6 @@ private Map getIdShadeDataMap(List shadeData) { return ret; } - private Map getIdSceneChannelMap() { - Map ret = new HashMap<>(); - for (Channel channel : getThing().getChannels()) { - if (sceneChannelTypeUID.equals(channel.getChannelTypeUID())) { - ret.put(channel.getUID().getId(), channel); - } - } - return ret; - } - - private Map getIdSceneCollectionChannelMap() { - Map ret = new HashMap<>(); - for (Channel channel : getThing().getChannels()) { - if (sceneCollectionChannelTypeUID.equals(channel.getChannelTypeUID())) { - ret.put(channel.getUID().getId(), channel); - } - } - return ret; - } - private void requestRefreshShadePositions() { Map thingIdMap = getThingIdMap(); for (Entry item : thingIdMap.entrySet()) { diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties index 9e8e94cd18179..8c0876b6366dd 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties @@ -43,4 +43,19 @@ offline.conf-error.invalid-bridge-handler = Invalid bridge handler # dynamic channels dynamic-channel.scene-activate.description = Activates the scene ''{0}'' +dynamic-channel.scene-activate.deprecated.description = DEPRECATED: Activates the scene ''{0}'' dynamic-channel.scene-group-activate.description = Activates the scene group ''{0}'' +dynamic-channel.automation-enabled.description = Enables/disables the automation ''{0}'' +dynamic-channel.automation-enabled.label = {0}, {1}, {2} +dynamic-channel.automation.hour = {0}hr +dynamic-channel.automation.minute = {0}m +dynamic-channel.automation.hour-minute = {0}hr {1}m +dynamic-channel.automation.at_sunrise = At sunrise +dynamic-channel.automation.before_sunrise = {0} before sunrise +dynamic-channel.automation.after_sunrise = {0} after sunrise +dynamic-channel.automation.at_sunset = At sunset +dynamic-channel.automation.before_sunset = {0} before sunset +dynamic-channel.automation.after_sunset = {0} after sunset +dynamic-channel.automation.weekdays = Weekdays +dynamic-channel.automation.weekends = Weekends +dynamic-channel.automation.all-days = All days diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties new file mode 100644 index 0000000000000..6b4483f261e17 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties @@ -0,0 +1,19 @@ +# dynamic channels + +dynamic-channel.scene-activate.description = Aktiverer scenen ''{0}'' +dynamic-channel.scene-activate.deprecated.description = UDFASET: Aktiverer scenen ''{0}'' +dynamic-channel.scene-group-activate.description = Aktiverer scenegruppen ''{0}'' +dynamic-channel.automation-enabled.description = Aktiverer/deaktiverer automatiseringen ''{0}'' +dynamic-channel.automation-enabled.label = {0}, {1}, {2} +dynamic-channel.automation.hour = {0}t +dynamic-channel.automation.minute = {0}m +dynamic-channel.automation.hour-minute = {0}t {1}m +dynamic-channel.automation.at_sunrise = Ved solopgang +dynamic-channel.automation.before_sunrise = {0} før solopgang +dynamic-channel.automation.after_sunrise = {0} efter solopgang +dynamic-channel.automation.at_sunset = Ved solnedgang +dynamic-channel.automation.before_sunset = {0} før solnedgang +dynamic-channel.automation.after_sunset = {0} efter solnedgang +dynamic-channel.automation.weekdays = Ugedage +dynamic-channel.automation.weekends = Weekend +dynamic-channel.automation.all-days = Alle dage diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml index 22954d4097f20..6769c07c9a005 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml @@ -8,6 +8,12 @@ Hunter Douglas (Luxaflex) PowerView Hub + + + + + + Hunter Douglas (Luxaflex) PowerView Hub @@ -96,6 +102,11 @@ + + Switch + + + Number:ElectricPotential @@ -103,4 +114,16 @@ + + + + + + + + + + + + From e0bc38ada56bddc006ea22ebf2de342eb95063e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20K=C3=BCper?= Date: Sat, 11 Dec 2021 17:21:42 +0100 Subject: [PATCH 205/361] Updated jsoup to 1.14.3 and adjusted some addons to use the provided version instaed of compile time dependency. (#11643) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sönke Küper Co-authored-by: Sönke Küper Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.ahawastecollection/pom.xml | 2 +- .../src/main/feature/feature.xml | 2 +- bundles/org.openhab.binding.ipobserver/pom.xml | 2 +- .../src/main/feature/feature.xml | 2 +- bundles/org.openhab.binding.kostalinverter/pom.xml | 4 ++-- .../src/main/feature/feature.xml | 1 + bundles/org.openhab.binding.linky/pom.xml | 4 ++-- .../org.openhab.binding.linky/src/main/feature/feature.xml | 2 +- bundles/org.openhab.binding.myq/pom.xml | 2 +- bundles/org.openhab.binding.myq/src/main/feature/feature.xml | 2 +- bundles/org.openhab.binding.tesla/pom.xml | 4 ++-- .../org.openhab.binding.tesla/src/main/feature/feature.xml | 1 + bundles/org.openhab.binding.verisure/pom.xml | 4 ++-- .../org.openhab.binding.verisure/src/main/feature/feature.xml | 2 +- bundles/org.openhab.transform.jinja/pom.xml | 4 ++-- .../org.openhab.transform.jinja/src/main/feature/feature.xml | 2 +- 16 files changed, 21 insertions(+), 19 deletions(-) diff --git a/bundles/org.openhab.binding.ahawastecollection/pom.xml b/bundles/org.openhab.binding.ahawastecollection/pom.xml index a3128510b2599..e4069b04f72bc 100644 --- a/bundles/org.openhab.binding.ahawastecollection/pom.xml +++ b/bundles/org.openhab.binding.ahawastecollection/pom.xml @@ -18,7 +18,7 @@ org.jsoup jsoup - 1.8.3 + 1.14.3 provided diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml index b09d4bcd0b694..e5cc73fe9d07f 100644 --- a/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/feature/feature.xml @@ -4,7 +4,7 @@ openhab-runtime-base - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.ahawastecollection/${project.version} diff --git a/bundles/org.openhab.binding.ipobserver/pom.xml b/bundles/org.openhab.binding.ipobserver/pom.xml index e7bc2b3865891..8ccc812a05502 100644 --- a/bundles/org.openhab.binding.ipobserver/pom.xml +++ b/bundles/org.openhab.binding.ipobserver/pom.xml @@ -17,7 +17,7 @@ org.jsoup jsoup - 1.8.3 + 1.14.3 provided diff --git a/bundles/org.openhab.binding.ipobserver/src/main/feature/feature.xml b/bundles/org.openhab.binding.ipobserver/src/main/feature/feature.xml index f9d25835deffb..e76edfe60c480 100644 --- a/bundles/org.openhab.binding.ipobserver/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.ipobserver/src/main/feature/feature.xml @@ -3,7 +3,7 @@ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features openhab-runtime-base - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.ipobserver/${project.version} diff --git a/bundles/org.openhab.binding.kostalinverter/pom.xml b/bundles/org.openhab.binding.kostalinverter/pom.xml index 74374c8af8ef8..f123404d37da5 100644 --- a/bundles/org.openhab.binding.kostalinverter/pom.xml +++ b/bundles/org.openhab.binding.kostalinverter/pom.xml @@ -18,8 +18,8 @@ org.jsoup jsoup - 1.8.3 - compile + 1.14.3 + provided diff --git a/bundles/org.openhab.binding.kostalinverter/src/main/feature/feature.xml b/bundles/org.openhab.binding.kostalinverter/src/main/feature/feature.xml index a4d722ce5b4b3..66c7d23c4ba97 100644 --- a/bundles/org.openhab.binding.kostalinverter/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.kostalinverter/src/main/feature/feature.xml @@ -4,6 +4,7 @@ openhab-runtime-base + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.kostalinverter/${project.version} diff --git a/bundles/org.openhab.binding.linky/pom.xml b/bundles/org.openhab.binding.linky/pom.xml index 482013c9e9c1b..91f453971211a 100644 --- a/bundles/org.openhab.binding.linky/pom.xml +++ b/bundles/org.openhab.binding.linky/pom.xml @@ -18,8 +18,8 @@ org.jsoup jsoup - 1.8.3 - compile + 1.14.3 + provided diff --git a/bundles/org.openhab.binding.linky/src/main/feature/feature.xml b/bundles/org.openhab.binding.linky/src/main/feature/feature.xml index 20b9446d27af5..41dad92544024 100644 --- a/bundles/org.openhab.binding.linky/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.linky/src/main/feature/feature.xml @@ -4,7 +4,7 @@ openhab-runtime-base - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.linky/${project.version} diff --git a/bundles/org.openhab.binding.myq/pom.xml b/bundles/org.openhab.binding.myq/pom.xml index a94ba5262dcb1..2ecc9a29d340d 100644 --- a/bundles/org.openhab.binding.myq/pom.xml +++ b/bundles/org.openhab.binding.myq/pom.xml @@ -18,7 +18,7 @@ org.jsoup jsoup - 1.8.3 + 1.14.3 provided diff --git a/bundles/org.openhab.binding.myq/src/main/feature/feature.xml b/bundles/org.openhab.binding.myq/src/main/feature/feature.xml index c5fabb87e6b12..0c938aa7afec7 100644 --- a/bundles/org.openhab.binding.myq/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.myq/src/main/feature/feature.xml @@ -4,7 +4,7 @@ openhab-runtime-base - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.myq/${project.version} diff --git a/bundles/org.openhab.binding.tesla/pom.xml b/bundles/org.openhab.binding.tesla/pom.xml index 91106068fe46c..e4e27ffe3d579 100644 --- a/bundles/org.openhab.binding.tesla/pom.xml +++ b/bundles/org.openhab.binding.tesla/pom.xml @@ -18,8 +18,8 @@ org.jsoup jsoup - 1.8.3 - compile + 1.14.3 + provided diff --git a/bundles/org.openhab.binding.tesla/src/main/feature/feature.xml b/bundles/org.openhab.binding.tesla/src/main/feature/feature.xml index a6a257ccb6632..f5e392ff90c79 100644 --- a/bundles/org.openhab.binding.tesla/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.tesla/src/main/feature/feature.xml @@ -4,6 +4,7 @@ openhab-runtime-base + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.tesla/${project.version} diff --git a/bundles/org.openhab.binding.verisure/pom.xml b/bundles/org.openhab.binding.verisure/pom.xml index 91f19daa5616c..8b11e0093a535 100644 --- a/bundles/org.openhab.binding.verisure/pom.xml +++ b/bundles/org.openhab.binding.verisure/pom.xml @@ -18,8 +18,8 @@ org.jsoup jsoup - 1.8.3 - compile + 1.14.3 + provided diff --git a/bundles/org.openhab.binding.verisure/src/main/feature/feature.xml b/bundles/org.openhab.binding.verisure/src/main/feature/feature.xml index 64a788f07f1d5..0812bcf36af0e 100644 --- a/bundles/org.openhab.binding.verisure/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.verisure/src/main/feature/feature.xml @@ -4,7 +4,7 @@ openhab-runtime-base openhab-transport-serial - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.openhab.addons.bundles/org.openhab.binding.verisure/${project.version} diff --git a/bundles/org.openhab.transform.jinja/pom.xml b/bundles/org.openhab.transform.jinja/pom.xml index 09e8ea3ca548c..0b916b2aecc98 100644 --- a/bundles/org.openhab.transform.jinja/pom.xml +++ b/bundles/org.openhab.transform.jinja/pom.xml @@ -74,8 +74,8 @@ org.jsoup jsoup - 1.8.3 - compile + 1.14.3 + provided org.apache.commons diff --git a/bundles/org.openhab.transform.jinja/src/main/feature/feature.xml b/bundles/org.openhab.transform.jinja/src/main/feature/feature.xml index 1a33c8df18c7f..5eb290e338559 100644 --- a/bundles/org.openhab.transform.jinja/src/main/feature/feature.xml +++ b/bundles/org.openhab.transform.jinja/src/main/feature/feature.xml @@ -5,7 +5,7 @@ openhab-runtime-base openhab.tp-jackson - mvn:org.jsoup/jsoup/1.8.3 + mvn:org.jsoup/jsoup/1.14.3 mvn:org.apache.commons/commons-lang3/3.4 mvn:commons-net/commons-net/3.6 mvn:org.openhab.addons.bundles/org.openhab.transform.jinja/${project.version} From 8092232d3a92a6e3ee38d69e99d9514bfea108e5 Mon Sep 17 00:00:00 2001 From: nimric <55734294+nimric@users.noreply.github.com> Date: Sat, 11 Dec 2021 17:50:40 +0100 Subject: [PATCH 206/361] [jdbc] Add support for TimescaleDB (#11090) (#11091) Signed-off-by: Riccardo Nimser-Joseph Co-authored-by: Riccardo Nimser-Joseph Signed-off-by: Michael Schmidt --- .../org.openhab.persistence.jdbc/README.md | 1 + .../persistence/jdbc/db/JdbcBaseDAO.java | 4 ++ .../jdbc/db/JdbcTimescaledbDAO.java | 71 +++++++++++++++++++ .../jdbc/internal/JdbcConfiguration.java | 4 +- 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcTimescaledbDAO.java diff --git a/bundles/org.openhab.persistence.jdbc/README.md b/bundles/org.openhab.persistence.jdbc/README.md index c6d2da2d3dd1a..45b1c6110b88c 100644 --- a/bundles/org.openhab.persistence.jdbc/README.md +++ b/bundles/org.openhab.persistence.jdbc/README.md @@ -16,6 +16,7 @@ The following databases are currently supported and tested: | [MySQL](https://www.mysql.com/) | [mysql-connector-java-5.1.39.jar](https://mvnrepository.com/artifact/mysql/mysql-connector-java) | | [PostgreSQL](https://www.postgresql.org/) | [postgresql-9.4.1209.jre7.jar](https://mvnrepository.com/artifact/org.postgresql/postgresql) | | [SQLite](https://www.sqlite.org/) | [sqlite-jdbc-3.16.1.jar](https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc) | +| [TimescaleDB](https://www.timescale.com/) | [postgresql-9.4.1209.jre7.jar](https://mvnrepository.com/artifact/org.postgresql/postgresql) | ## Table of Contents diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java index 72f8407b72dde..3025eef1b7b8f 100644 --- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java +++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcBaseDAO.java @@ -248,6 +248,10 @@ public void initAfterFirstDbConnection() { dbMeta = new DbMetaData();// get DB information } + public Properties getConnectionProperties() { + return new Properties(this.databaseProps); + } + /************** * ITEMS DAOs * **************/ diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcTimescaledbDAO.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcTimescaledbDAO.java new file mode 100644 index 0000000000000..b6e157f166fda --- /dev/null +++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/db/JdbcTimescaledbDAO.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.persistence.jdbc.db; + +import java.util.Properties; + +import org.knowm.yank.Yank; +import org.openhab.persistence.jdbc.dto.ItemVO; +import org.openhab.persistence.jdbc.utils.StringUtilsExt; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Extended Database Configuration class. Class represents the extended database-specific configuration. Overrides and + * supplements the default settings from JdbcBaseDAO and JdbcPostgresqlDAO. + * + * @author Riccardo Nimser-Joseph - Initial contribution + */ +public class JdbcTimescaledbDAO extends JdbcPostgresqlDAO { + private final Logger logger = LoggerFactory.getLogger(JdbcTimescaledbDAO.class); + + protected String sqlCreateHypertable; + + public JdbcTimescaledbDAO() { + super(); + + initSqlQueries(); + } + + public Properties getDatabaseProperties() { + Properties properties = new Properties(this.databaseProps); + + // Adjust the jdbc url since the service name 'timescaledb' is only used to differentiate the DAOs + if (properties.containsKey("jdbcUrl")) { + properties.put("jdbcUrl", properties.getProperty("jdbcUrl").replace("timescaledb", "postgresql")); + } + + return properties; + } + + public void doCreateItemTable(ItemVO vo) { + String sql; + + sql = StringUtilsExt.replaceArrayMerge(this.sqlCreateItemTable, + new String[] { "#tableName#", "#dbType#", "#tablePrimaryKey#" }, + new String[] { vo.getTableName(), vo.getDbType(), sqlTypes.get("tablePrimaryKey") }); + this.logger.debug("JDBC::doCreateItemTable sql={}", sql); + Yank.execute(sql, null); + + sql = StringUtilsExt.replaceArrayMerge(this.sqlCreateHypertable, new String[] { "#tableName#" }, + new String[] { vo.getTableName() }); + this.logger.debug("JDBC::doCreateItemTable sql={}", sql); + Yank.execute(sql, null); + } + + private void initSqlQueries() { + this.logger.debug("JDBC::initSqlQueries: '{}'", this.getClass().getSimpleName()); + + this.sqlCreateHypertable = "SELECT create_hypertable('#tableName#', 'time')"; + } +} diff --git a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java index 2e6f878949027..8e0fb1355c04b 100644 --- a/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java +++ b/bundles/org.openhab.persistence.jdbc/src/main/java/org/openhab/persistence/jdbc/internal/JdbcConfiguration.java @@ -122,7 +122,7 @@ private boolean updateConfig(Map config) { // set database type and database type class setDBDAOClass(parsedURL.getProperty("dbShortcut")); // derby, h2, hsqldb, mariadb, mysql, postgresql, - // sqlite + // sqlite, timescaledb // set user if (user != null && !user.isBlank()) { dBDAO.databaseProps.setProperty("dataSource.user", user); @@ -322,7 +322,7 @@ private void testJDBCDriver(String driver) { } public Properties getHikariConfiguration() { - return dBDAO.databaseProps; + return dBDAO.getConnectionProperties(); } public String getName() { From 5abb0e7f3352c74ab5b57570c4741c1da3cf6be4 Mon Sep 17 00:00:00 2001 From: Florian Albrecht <11006895+albrechtf@users.noreply.github.com> Date: Sat, 11 Dec 2021 17:57:13 +0100 Subject: [PATCH 207/361] [mqtt] Fix avail topics subscription after Brige Restart (#9851) Fixes #9850 Signed-off-by: Florian Albrecht Signed-off-by: Michael Schmidt --- .../generic/AbstractMQTTThingHandler.java | 17 +------------ .../handler/GenericMQTTThingHandler.java | 25 ++++++++++++------- .../handler/GenericThingHandlerTests.java | 12 +++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java index 1c11e462857a2..14ecdc8510dd2 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/AbstractMQTTThingHandler.java @@ -12,7 +12,6 @@ */ package org.openhab.binding.mqtt.generic; -import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Optional; @@ -23,12 +22,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.mqtt.generic.utils.FutureCollector; import org.openhab.binding.mqtt.generic.values.OnOffValue; import org.openhab.binding.mqtt.generic.values.Value; import org.openhab.binding.mqtt.handler.AbstractBrokerHandler; @@ -195,19 +192,7 @@ public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { // We do not set the thing to ONLINE here in the AbstractBase, that is the responsibility of a derived // class. try { - Collection> futures = availabilityStates.values().stream().map(s -> { - if (s != null) { - return s.start(connection, scheduler, 0); - } - return CompletableFuture.allOf(); - }).collect(Collectors.toList()); - - futures.add(start(connection)); - - futures.stream().collect(FutureCollector.allOf()).exceptionally(e -> { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getLocalizedMessage()); - return null; - }).get(subscribeTimeout, TimeUnit.MILLISECONDS); + start(connection).get(subscribeTimeout, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException ignored) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Did not receive all required topics"); diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java index 8cc05429ec1b6..c157506fb8b52 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/internal/handler/GenericMQTTThingHandler.java @@ -85,6 +85,9 @@ public GenericMQTTThingHandler(Thing thing, MqttChannelStateDescriptionProvider */ @Override protected CompletableFuture<@Nullable Void> start(MqttBrokerConnection connection) { + // availability topics are also started asynchronously, so no problem here + clearAllAvailabilityTopics(); + initializeAvailabilityTopicsFromConfig(); return channelStateByChannelUID.values().stream().map(c -> c.start(connection, scheduler, 0)) .collect(FutureCollector.allOf()).thenRun(this::calculateThingStatus); } @@ -142,15 +145,7 @@ protected ChannelState createChannelState(ChannelConfig channelConfig, ChannelUI @Override public void initialize() { - GenericThingConfiguration config = getConfigAs(GenericThingConfiguration.class); - - String availabilityTopic = config.availabilityTopic; - - if (availabilityTopic != null) { - addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable); - } else { - clearAllAvailabilityTopics(); - } + initializeAvailabilityTopicsFromConfig(); List configErrors = new ArrayList<>(); for (Channel channel : thing.getChannels()) { @@ -193,4 +188,16 @@ protected void updateThingStatus(boolean messageReceived, Optional avai updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE); } } + + private void initializeAvailabilityTopicsFromConfig() { + GenericThingConfiguration config = getConfigAs(GenericThingConfiguration.class); + + String availabilityTopic = config.availabilityTopic; + + if (availabilityTopic != null) { + addAvailabilityTopic(availabilityTopic, config.payloadAvailable, config.payloadNotAvailable); + } else { + clearAllAvailabilityTopics(); + } + } } diff --git a/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingHandlerTests.java b/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingHandlerTests.java index 13cf9946e686c..d9f41464ae229 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingHandlerTests.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/internal/handler/GenericThingHandlerTests.java @@ -192,4 +192,16 @@ public void processMessage() { verify(callback).stateUpdated(eq(textChannelUID), argThat(arg -> "UPDATE".equals(arg.toString()))); assertThat(textValue.getChannelState().toString(), is("UPDATE")); } + + @Test + public void handleBridgeStatusChange() { + Configuration config = new Configuration(); + config.put("availabilityTopic", "test/LWT"); + when(thing.getConfiguration()).thenReturn(config); + thingHandler.initialize(); + thingHandler + .bridgeStatusChanged(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, null)); + thingHandler.bridgeStatusChanged(new ThingStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null)); + verify(connection, times(2)).subscribe(eq("test/LWT"), any()); + } } From cbb6b513c324d8e2a8f352cd267be31754df63d3 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 11 Dec 2021 18:01:29 +0100 Subject: [PATCH 208/361] Add default translations for transform add-ons (#11755) This makes the texts used by these add-ons translatable with Crowdin. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/config/execProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/exec.properties | 8 ++++++++ .../main/resources/OH-INF/config/javascriptProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/js.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/jinjaProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/jinja.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/jsonpathProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/jsonpath.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/regexProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/regex.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/scaleProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/scale.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/xpathProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/xpath.properties | 8 ++++++++ .../src/main/resources/OH-INF/config/xsltProfile.xml | 2 +- .../src/main/resources/OH-INF/i18n/xslt.properties | 8 ++++++++ 16 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec.properties create mode 100644 bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js.properties create mode 100644 bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja.properties create mode 100644 bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath.properties create mode 100644 bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex.properties create mode 100644 bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale.properties create mode 100644 bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath.properties create mode 100644 bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt.properties diff --git a/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/config/execProfile.xml b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/config/execProfile.xml index 23c64ab60a91e..a40e833ab209a 100644 --- a/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/config/execProfile.xml +++ b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/config/execProfile.xml @@ -12,7 +12,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec.properties b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec.properties new file mode 100644 index 0000000000000..b19f613f1ffa2 --- /dev/null +++ b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec.properties @@ -0,0 +1,8 @@ +profile.config.transform.EXEC.function.label = Command +profile.config.transform.EXEC.function.description = Command to be executed on the command line. It should contain %s which will be substituted with the state. +profile.config.transform.EXEC.sourceFormat.label = State Formatter +profile.config.transform.EXEC.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.EXEC.label = EXEC diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml index a921594ef8582..9bae0c235c660 100644 --- a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml @@ -13,7 +13,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js.properties b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js.properties new file mode 100644 index 0000000000000..1cd7aa67f38fc --- /dev/null +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js.properties @@ -0,0 +1,8 @@ +profile.config.transform.JS.function.label = JavaScript Filename +profile.config.transform.JS.function.description = Filename of the JavaScript in the transform folder. The state will be available in the variable \"input\". +profile.config.transform.JS.sourceFormat.label = State Formatter +profile.config.transform.JS.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.JS.label = JS diff --git a/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/config/jinjaProfile.xml b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/config/jinjaProfile.xml index c100130ec3765..d8f09c74798df 100644 --- a/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/config/jinjaProfile.xml +++ b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/config/jinjaProfile.xml @@ -12,7 +12,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja.properties b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja.properties new file mode 100644 index 0000000000000..324ce074c6071 --- /dev/null +++ b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja.properties @@ -0,0 +1,8 @@ +profile.config.transform.JINJA.function.label = Jinja Template +profile.config.transform.JINJA.function.description = Template to be evaluated. For example: {{ value_json.device.status.temperature }} +profile.config.transform.JINJA.sourceFormat.label = State Formatter +profile.config.transform.JINJA.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.JINJA.label = JINJA diff --git a/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/config/jsonpathProfile.xml b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/config/jsonpathProfile.xml index 5dd71031d589b..d4d2183fa7c7b 100644 --- a/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/config/jsonpathProfile.xml +++ b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/config/jsonpathProfile.xml @@ -11,7 +11,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath.properties b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath.properties new file mode 100644 index 0000000000000..6bcfc1fbc76c7 --- /dev/null +++ b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath.properties @@ -0,0 +1,8 @@ +profile.config.transform.JSONPATH.function.label = JSONPath Expression +profile.config.transform.JSONPATH.function.description = Expression to be applied on the state. For example: $.device.status.temperature +profile.config.transform.JSONPATH.sourceFormat.label = State Formatter +profile.config.transform.JSONPATH.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.JSONPATH.label = JSONPATH diff --git a/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/config/regexProfile.xml b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/config/regexProfile.xml index aecf47d4560ca..dd0e03876c2c7 100644 --- a/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/config/regexProfile.xml +++ b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/config/regexProfile.xml @@ -12,7 +12,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex.properties b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex.properties new file mode 100644 index 0000000000000..d0447e8d9cc4a --- /dev/null +++ b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex.properties @@ -0,0 +1,8 @@ +profile.config.transform.REGEX.function.label = Regular Expression +profile.config.transform.REGEX.function.description = Regular expression to be applied on the state. Should contain a capture group whose outcome will be the result. For example: .*=(\\d*.\\d*).* extracts the 23.5 from temp=23.5°C +profile.config.transform.REGEX.sourceFormat.label = State Formatter +profile.config.transform.REGEX.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.REGEX.label = REGEX diff --git a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/config/scaleProfile.xml b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/config/scaleProfile.xml index 00b5f16923517..206839a1f8247 100644 --- a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/config/scaleProfile.xml +++ b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/config/scaleProfile.xml @@ -12,7 +12,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale.properties b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale.properties new file mode 100644 index 0000000000000..b51115c8a6c1c --- /dev/null +++ b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale.properties @@ -0,0 +1,8 @@ +profile.config.transform.SCALE.function.label = Filename +profile.config.transform.SCALE.function.description = Filename containing the scale mappings. +profile.config.transform.SCALE.sourceFormat.label = State Formatter +profile.config.transform.SCALE.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.SCALE.label = SCALE diff --git a/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/config/xpathProfile.xml b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/config/xpathProfile.xml index 1180fcb2bf8b3..0723a2ba44714 100644 --- a/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/config/xpathProfile.xml +++ b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/config/xpathProfile.xml @@ -12,7 +12,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath.properties b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath.properties new file mode 100644 index 0000000000000..8c64157344cc7 --- /dev/null +++ b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath.properties @@ -0,0 +1,8 @@ +profile.config.transform.XPATH.function.label = XPath Expression +profile.config.transform.XPATH.function.description = XPath expression to be applied on the state: For example: /*[name()='PTZStatus']/*[name()='AbsoluteHigh']/*[name()='azimuth']/ +profile.config.transform.XPATH.sourceFormat.label = State Formatter +profile.config.transform.XPATH.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.XPATH.label = XPATH diff --git a/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/config/xsltProfile.xml b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/config/xsltProfile.xml index 057ca970cd66d..d1624090cb299 100644 --- a/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/config/xsltProfile.xml +++ b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/config/xsltProfile.xml @@ -11,7 +11,7 @@ - How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s) + How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). true diff --git a/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt.properties b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt.properties new file mode 100644 index 0000000000000..8eb44f7094a48 --- /dev/null +++ b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt.properties @@ -0,0 +1,8 @@ +profile.config.transform.XSLT.function.label = XSL Filename +profile.config.transform.XSLT.function.description = XSL file name in transform folder, containing the transformation expression. +profile.config.transform.XSLT.sourceFormat.label = State Formatter +profile.config.transform.XSLT.sourceFormat.description = How to format the state on the channel before transforming it, i.e. %s or %.1f °C (default is %s). + +# profile type + +profile-type.transform.XSLT.label = XSLT From ea014a135a1ae09bb63d4ae6fd12052000ef2ce0 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 11 Dec 2021 18:02:00 +0100 Subject: [PATCH 209/361] Add default translations for persistence add-ons (#11754) This makes the texts used by these add-ons translatable with Crowdin. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/dynamodb.properties | 24 +++++++++ .../resources/OH-INF/i18n/influxdb.properties | 34 ++++++++++++ .../resources/OH-INF/i18n/jdbc.properties | 54 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 bundles/org.openhab.persistence.dynamodb/src/main/resources/OH-INF/i18n/dynamodb.properties create mode 100644 bundles/org.openhab.persistence.influxdb/src/main/resources/OH-INF/i18n/influxdb.properties create mode 100644 bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties diff --git a/bundles/org.openhab.persistence.dynamodb/src/main/resources/OH-INF/i18n/dynamodb.properties b/bundles/org.openhab.persistence.dynamodb/src/main/resources/OH-INF/i18n/dynamodb.properties new file mode 100644 index 0000000000000..a37d972a5bea1 --- /dev/null +++ b/bundles/org.openhab.persistence.dynamodb/src/main/resources/OH-INF/i18n/dynamodb.properties @@ -0,0 +1,24 @@ +persistence.config.dynamodb.accessKey.label = AWS access key +persistence.config.dynamodb.accessKey.description = AWS access key
Give either 1) access key and secret key, or 2) credentials file and profile name. +persistence.config.dynamodb.expireDays.label = Data Expiry, in Days +persistence.config.dynamodb.expireDays.description = Expire time for data.
Data older than this is automatically removed by DynamoDB Time to Live (TTL) feature. Use empty value to disable data expiration. +persistence.config.dynamodb.profile.label = Profile name +persistence.config.dynamodb.profile.description = Profile name in AWS credentials file.
Give either 1) access key and secret key, or 2) credentials file and profile name. +persistence.config.dynamodb.profilesConfigFile.label = AWS credentials file +persistence.config.dynamodb.profilesConfigFile.description = Path to the AWS credentials file.
For example, /etc/openhab/aws_creds. Please note that the user that runs openHAB must have approriate read rights to the credential file.
Give either 1) access key and secret key, or 2) credentials file and profile name. +persistence.config.dynamodb.readCapacityUnits.label = Read Capacity +persistence.config.dynamodb.readCapacityUnits.description = Provisioned read capacity.
Default is 1. +persistence.config.dynamodb.region.label = AWS region ID +persistence.config.dynamodb.region.description = AWS region ID
The region needs to match the region of the AWS user that will access Amazon DynamoDB.
For example, eu-west-1. +persistence.config.dynamodb.secretKey.label = AWS secret key +persistence.config.dynamodb.secretKey.description = AWS secret key
Give either 1) access key and secret key, or 2) credentials file and profile name. +persistence.config.dynamodb.table.label = Table +persistence.config.dynamodb.table.description = Table name.
Specify this parameter over Table Prefix to use the new optimized table format. +persistence.config.dynamodb.tablePrefix.label = Table Prefix +persistence.config.dynamodb.tablePrefix.description = Legacy: Table prefix used in the name of created tables.
Default is "openhab-" +persistence.config.dynamodb.writeCapacityUnits.label = Write Capacity +persistence.config.dynamodb.writeCapacityUnits.description = Provisioned write capacity.
Default is 1. + +# service + +service.persistence.dynamodb.label = DynamoDB Persistence Service diff --git a/bundles/org.openhab.persistence.influxdb/src/main/resources/OH-INF/i18n/influxdb.properties b/bundles/org.openhab.persistence.influxdb/src/main/resources/OH-INF/i18n/influxdb.properties new file mode 100644 index 0000000000000..c94e5d4c9ca43 --- /dev/null +++ b/bundles/org.openhab.persistence.influxdb/src/main/resources/OH-INF/i18n/influxdb.properties @@ -0,0 +1,34 @@ +persistence.config.influxdb.addCategoryTag.label = Add Category Tag +persistence.config.influxdb.addCategoryTag.description = Should the category of the item be included as tag "category"? If no category is set, "n/a" is used. +persistence.config.influxdb.addLabelTag.label = Add Label Tag +persistence.config.influxdb.addLabelTag.description = Should the item label be included as tag "label"? If no label is set, "n/a" is used. +persistence.config.influxdb.addTypeTag.label = Add Type Tag +persistence.config.influxdb.addTypeTag.description = Should the item type be included as tag "type"? +persistence.config.influxdb.db.label = Database/Organization +persistence.config.influxdb.db.description = The name of the database (InfluxDB 1.0) or Organization for (InfluxDB 2.0) +persistence.config.influxdb.group.connection.label = Connection +persistence.config.influxdb.group.connection.description = This group defines connection parameters. +persistence.config.influxdb.group.misc.label = Miscellaneous +persistence.config.influxdb.group.misc.description = This group defines miscellaneous parameters. +persistence.config.influxdb.group.tags.label = Additional Tags +persistence.config.influxdb.group.tags.description = This group defines additional tags which can be added to your measurements. +persistence.config.influxdb.password.label = Database Password +persistence.config.influxdb.password.description = Database password +persistence.config.influxdb.replaceUnderscore.label = Replace Underscore +persistence.config.influxdb.replaceUnderscore.description = Whether underscores "_" in item names should be replaced by a dot "." ("test_item" -> "test.item"). Only for measurement name, not for tags. Also applies to alias names. +persistence.config.influxdb.retentionPolicy.label = Retention Policy / Bucket +persistence.config.influxdb.retentionPolicy.description = The name of the retention policy (Influx DB 1.0) or bucket (InfluxDB 2.0) to write data +persistence.config.influxdb.token.label = Authentication Token +persistence.config.influxdb.token.description = The token to authenticate to database (alternative to username/password for InfluxDB 2.0) +persistence.config.influxdb.url.label = Database URL +persistence.config.influxdb.url.description = The database URL, e.g. http://127.0.0.1:8086 +persistence.config.influxdb.user.label = Username +persistence.config.influxdb.user.description = Database username +persistence.config.influxdb.version.label = Database Version +persistence.config.influxdb.version.description = InfluxDB version +persistence.config.influxdb.version.option.V1 = InfluxDB 1 +persistence.config.influxdb.version.option.V2 = InfluxDB 2 + +# service + +service.persistence.influxdb.label = InfluxDB Persistence Service diff --git a/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties new file mode 100644 index 0000000000000..110e4b8d9b9f6 --- /dev/null +++ b/bundles/org.openhab.persistence.jdbc/src/main/resources/OH-INF/i18n/jdbc.properties @@ -0,0 +1,54 @@ +persistence.config.jdbc.enableLogTime.label = Timekeeping Enable +persistence.config.jdbc.enableLogTime.description = Enables a time, performance measurement.
(optional, default: disabled) +persistence.config.jdbc.enableLogTime.option.true = Enable +persistence.config.jdbc.enableLogTime.option.false = Disable +persistence.config.jdbc.maximumPoolSize.label = Connections Max Pool Size +persistence.config.jdbc.maximumPoolSize.description = Overrides max pool size in database connection.
(optional, default: differs each Database)
https://github.com/brettwooldridge/HikariCP/issues/256 +persistence.config.jdbc.minimumIdle.label = Connections Min Idle +persistence.config.jdbc.minimumIdle.description = Overrides min idle database connections.
(optional, default: differs each Database)
https://github.com/brettwooldridge/HikariCP/issues/256 +persistence.config.jdbc.password.label = Database Password +persistence.config.jdbc.password.description = Defines the database password. +persistence.config.jdbc.rebuildTableNames.label = Tablename Rebuild +persistence.config.jdbc.rebuildTableNames.description = Rename existing tables using 'Tablename Realname Generation' and 'Tablename Suffix ID Count', (optional, default: disabled).
USE WITH CARE! Deactivate after renaming is done! +persistence.config.jdbc.rebuildTableNames.option.true = Enable +persistence.config.jdbc.rebuildTableNames.option.false = Disable +persistence.config.jdbc.sqltype.CALL.label = SqlType CALL +persistence.config.jdbc.sqltype.CALL.description = Overrides used JDBC/SQL datatype for CALL
(optional, default: "VARCHAR(200)").
General about JdbcTypes/SqlTypes see: https://mybatis.github.io/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html
see: http://www.h2database.com/html/datatypes.html
see: http://www.postgresql.org/docs/9.5/static/datatype.html +persistence.config.jdbc.sqltype.COLOR.label = SqlType COLOR +persistence.config.jdbc.sqltype.COLOR.description = Overrides used JDBC/SQL datatype for COLOR
(optional, default: "VARCHAR(70)"). +persistence.config.jdbc.sqltype.CONTACT.label = SqlType CONTACT +persistence.config.jdbc.sqltype.CONTACT.description = Overrides used JDBC/SQL datatype for CONTACT
(optional, default: "VARCHAR(6)"). +persistence.config.jdbc.sqltype.DATETIME.label = SqlType DATETIME +persistence.config.jdbc.sqltype.DATETIME.description = Overrides used JDBC/SQL datatype for DATETIME
(optional, default: "DATETIME"). +persistence.config.jdbc.sqltype.DIMMER.label = SqlType DIMMER +persistence.config.jdbc.sqltype.DIMMER.description = Overrides used JDBC/SQL datatype for DIMMER
(optional, default: "TINYINT"). +persistence.config.jdbc.sqltype.IMAGE.label = SqlType IMAGE +persistence.config.jdbc.sqltype.IMAGE.description = Overrides used JDBC/SQL datatype for IMAGE
(optional, default: "VARCHAR(65500)"). +persistence.config.jdbc.sqltype.LOCATION.label = SqlType LOCATION +persistence.config.jdbc.sqltype.LOCATION.description = Overrides used JDBC/SQL datatype for LOCATION
(optional, default: "VARCHAR(50)"). +persistence.config.jdbc.sqltype.NUMBER.label = SqlType NUMBER +persistence.config.jdbc.sqltype.NUMBER.description = Overrides used JDBC/SQL datatype for NUMBER
(optional, default: "DOUBLE"). +persistence.config.jdbc.sqltype.PLAYER.label = SqlType PLAYER +persistence.config.jdbc.sqltype.PLAYER.description = Overrides used JDBC/SQL datatype for PLAYER
(optional, default: "VARCHAR(20)"). +persistence.config.jdbc.sqltype.ROLLERSHUTTER.label = SqlType ROLLERSHUTTER +persistence.config.jdbc.sqltype.ROLLERSHUTTER.description = Overrides used JDBC/SQL datatype for ROLLERSHUTTER
(optional, default: "TINYINT"). +persistence.config.jdbc.sqltype.STRING.label = SqlType STRING +persistence.config.jdbc.sqltype.STRING.description = Overrides used JDBC/SQL datatype for STRING
(optional, default: "VARCHAR(65500)"). +persistence.config.jdbc.sqltype.SWITCH.label = SqlType SWITCH +persistence.config.jdbc.sqltype.SWITCH.description = Overrides used JDBC/SQL datatype for SWITCH
(optional, default: "VARCHAR(6)"). +persistence.config.jdbc.tableIdDigitCount.label = Tablename Suffix ID Count +persistence.config.jdbc.tableIdDigitCount.description = Tablename Suffix ID Count
(optional, default: 4 -> 0001-9999).
For migration from MYSQL-Bundle set to 0. +persistence.config.jdbc.tableNamePrefix.label = Tablename Prefix String +persistence.config.jdbc.tableNamePrefix.description = Tablename prefix string
(optional, default: "item").
For migration from MYSQL-Bundle set to 'Item'. +persistence.config.jdbc.tableUseRealItemNames.label = Tablename Realname Generation +persistence.config.jdbc.tableUseRealItemNames.description = Enables Tablename prefix generation per Items realname
(optional, default: disabled -> "Tablename Prefix String" is used).
If true, 'Tablename Prefix String' is ignored. +persistence.config.jdbc.tableUseRealItemNames.option.true = Enable +persistence.config.jdbc.tableUseRealItemNames.option.false = Disable +persistence.config.jdbc.url.label = Database URL +persistence.config.jdbc.url.description = Defines required database URL and optional path and parameters.
Required database url like 'jdbc::[:;]'
Parameter 'service' is used as identifier for the selected jdbc driver. URL-Examples:
jdbc:derby:./testDerby;create=true
jdbc:h2:./testH2
jdbc:hsqldb:./testHsqlDb
jdbc:mariadb://192.168.0.1:3306/testMariadb
jdbc:mysql://192.168.0.1:3306/testMysql
jdbc:postgresql://192.168.0.1:5432/testPostgresql
jdbc:sqlite:./testSqlite.db +persistence.config.jdbc.user.label = Database User +persistence.config.jdbc.user.description = Defines the database user. + +# service + +service.persistence.jdbc.label = JDBC Persistence Service From 22acabc3fa64ad8676ce10160c9e27c4822b9262 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Sat, 11 Dec 2021 18:03:51 +0100 Subject: [PATCH 210/361] New Crowdin updates (#11712) * New translations ambientweather.properties (Italian) * New translations amazondashbutton.properties (Italian) * New translations openwebnet.properties (Italian) * New translations lghombot.properties (Swedish) * New translations playstation.properties (Swedish) * New translations urtsi.properties (German) * New translations chromecast.properties (German) * New translations openhabcloud.properties (French) * New translations openhabcloud.properties (Hungarian) * New translations openhabcloud.properties (German) * New translations logreader.properties (German) * New translations googletts.properties (German) * New translations avmfritz.properties (German) * New translations thingstate.properties (French) * New translations sncf.properties (French) * New translations openweathermap.properties (German) * New translations twitter.properties (French) * New translations nikohomecontrol.properties (French) * New translations gce.properties (French) * New translations synopanalyzer.properties (French) * New translations vigicrues.properties (French) * New translations airquality.properties (French) * New translations meteoblue.properties (French) * New translations xmltv.properties (French) * New translations sncf.properties (French) Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/airquality_fr.properties | 2 +- .../i18n/amazondashbutton_it.properties | 15 + .../OH-INF/i18n/ambientweather_it.properties | 15 + .../OH-INF/i18n/avmfritz_de.properties | 4 + .../OH-INF/i18n/chromecast_de.properties | 3 + .../resources/OH-INF/i18n/gce_fr.properties | 2 +- .../OH-INF/i18n/lghombot_sv.properties | 1 - .../OH-INF/i18n/logreader_de.properties | 1 + .../OH-INF/i18n/meteoblue_fr.properties | 2 +- .../OH-INF/i18n/nikohomecontrol_fr.properties | 119 ++++ .../OH-INF/i18n/openweathermap_de.properties | 592 ++++++++---------- .../OH-INF/i18n/openwebnet_it.properties | 2 +- .../OH-INF/i18n/playstation_sv.properties | 2 +- .../resources/OH-INF/i18n/sncf_fr.properties | 36 ++ .../OH-INF/i18n/synopanalyzer_fr.properties | 2 +- .../OH-INF/i18n/twitter_fr.properties | 2 +- .../OH-INF/i18n/thingstate_fr.properties | 9 + .../resources/OH-INF/i18n/urtsi_de.properties | 4 +- .../OH-INF/i18n/vigicrues_fr.properties | 2 +- .../resources/OH-INF/i18n/xmltv_fr.properties | 2 +- .../OH-INF/i18n/openhabcloud_de.properties | 10 +- .../OH-INF/i18n/openhabcloud_fr.properties | 10 +- .../OH-INF/i18n/openhabcloud_hu.properties | 10 +- .../OH-INF/i18n/googletts_de.properties | 10 +- 24 files changed, 494 insertions(+), 363 deletions(-) create mode 100644 bundles/org.openhab.binding.amazondashbutton/src/main/resources/OH-INF/i18n/amazondashbutton_it.properties create mode 100644 bundles/org.openhab.binding.ambientweather/src/main/resources/OH-INF/i18n/ambientweather_it.properties create mode 100644 bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol_fr.properties create mode 100644 bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf_fr.properties create mode 100644 bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/thingstate_fr.properties diff --git a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties index 3dd0892af31d1..6463c5436087a 100644 --- a/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties +++ b/bundles/org.openhab.binding.airquality/src/main/resources/OH-INF/i18n/airquality_fr.properties @@ -1,6 +1,6 @@ # binding binding.airquality.name = Extension Air Quality -binding.airquality.description = Indice de qualité de l'air et informations sur la pollution aux particules pour un emplacement donné. +binding.airquality.description = Cette extension permet de récupérer l'indice de qualité de l'air et des informations sur la pollution aux particules pour un emplacement donné. # thing types thing-type.airquality.api.label = API Air Quality diff --git a/bundles/org.openhab.binding.amazondashbutton/src/main/resources/OH-INF/i18n/amazondashbutton_it.properties b/bundles/org.openhab.binding.amazondashbutton/src/main/resources/OH-INF/i18n/amazondashbutton_it.properties new file mode 100644 index 0000000000000..366ed8188ecdf --- /dev/null +++ b/bundles/org.openhab.binding.amazondashbutton/src/main/resources/OH-INF/i18n/amazondashbutton_it.properties @@ -0,0 +1,15 @@ +# binding +bindingDescription = Questo è il binding per il pulsante Amazon Dash. + +# thing types +dashButtonLabel = Pulsante Amazon Dash +dashButtonDescription = Questo è il pulsante Amazon Dash +dashButtonMacAddressLabel = Indirizzo MAC +dashButtonMacAddressDescription = L'indirizzo MAC del pulsante Amazon Dash +dashButtonNetworkInterfaceLabel = Interfaccia di rete +dashButtonNetworkInterfaceDescription = L'interfaccia di rete che riceve i pacchetti del pulsante Amazon Dash +dashButtonPacketIntervalLabel = Intervallo di elaborazione pacchetti (in ms) +dashButtonPacketIntervalDescription = Spesso il premere una volta il pulsante viene riconosciuto come pressione multipla. È possibile specificare per quanto tempo qualsiasi ulteriore pressione venga ignorato dopo la prima (in ms). + +dashButtonPressChannelLabel = Pressione pulsante Amazon Dash +dashButtonPressChannelDescription = Canale per riconoscere la pressione di un pulsante Amazon Dash diff --git a/bundles/org.openhab.binding.ambientweather/src/main/resources/OH-INF/i18n/ambientweather_it.properties b/bundles/org.openhab.binding.ambientweather/src/main/resources/OH-INF/i18n/ambientweather_it.properties new file mode 100644 index 0000000000000..7eb22b5a3da37 --- /dev/null +++ b/bundles/org.openhab.binding.ambientweather/src/main/resources/OH-INF/i18n/ambientweather_it.properties @@ -0,0 +1,15 @@ +# binding +binding.ambientweather.name = Ambient Weather Binding +binding.ambientweather.description = Binding che supporta le stazioni meteo da Ambient Weather + +# thing types +thing-type.ambientweather.bridge.label = Ambient Weather Bridge +thing-type.ambientweather.bridge.description = Ambient Weather Bridge +thing-type.ambientweather.ws1400ip.label = Ambient Weather WS-1400-IP +thing-type.ambientweather.ws1400ip.description = Stazione Metro Ambient Weather WS-1400-IP +thing-type.ambientweather.ws8482.label = Ambient Weather WS-8482 +thing-type.ambientweather.ws8482.description = Stazione Meteo Ambient Weather WS-8482 +thing-type.ambientweather.ws2902a.label = Ambient Weather WS-2902A +thing-type.ambientweather.ws2902a.description = Stazione Meteo Ambient Weather WS-2902A +thing-type.ambientweather.ws0900ip.label = Ambient Weather WS-0900-IP +thing-type.ambientweather.ws0900ip.description = Stazione Meteo Ambient Weather WS-0900-IP diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties index cc207a1500e90..54e43c5c4877b 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties @@ -39,8 +39,12 @@ thing-type.avmfritz.FRITZ_Powerline_546E_Solo.label = FRITZ\!Powerline 546E thing-type.avmfritz.FRITZ_Powerline_546E_Solo.description = FRITZ\!Powerline 546E schaltbare Steckdose im stand-alone Modus. Dient zur Steuerung der integrierten Steckdose und liefert Daten wie z.B. Temperatur. thing-type.avmfritz.HAN_FUN_BLINDS.label = HAN-FUN Rollladen thing-type.avmfritz.HAN_FUN_BLINDS.description = HAN-FUN Rollladen (z.B. Rollotron DECT 1213, Becker BoxCTRL). +thing-type.avmfritz.HAN_FUN_COLOR_BULB.label = HAN-FUN Farbige Lampe +thing-type.avmfritz.HAN_FUN_COLOR_BULB.description = HAN-FUN Farbige Lampe (z.B. SmartHome LED-Lampe E27 (farbig)). thing-type.avmfritz.HAN_FUN_CONTACT.label = HAN-FUN Kontakt thing-type.avmfritz.HAN_FUN_CONTACT.description = HAN-FUN Kontakt (z.B. SmartHome Tür-/Fensterkontakt, SmartHome Bewegungsmelder). +thing-type.avmfritz.HAN_FUN_DIMMABLE_BULB.label = HAN-FUN Dimmbare Lampe +thing-type.avmfritz.HAN_FUN_DIMMABLE_BULB.description = HAN-FUN Dimmbare Lampe (z.B. SmartHome LED-Lampe E27 (farbig)). thing-type.avmfritz.HAN_FUN_ON_OFF.label = HAN-FUN an-/ausschaltbares Gerät thing-type.avmfritz.HAN_FUN_ON_OFF.description = HAN-FUN an-/ausschaltbares Gerät (z.B. SmartHome Zwischenstecker innen, SmartHome Zwischenstecker außen). thing-type.avmfritz.HAN_FUN_SWITCH.label = HAN-FUN Schalter diff --git a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties index 961def6432163..00396e6b5929b 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties +++ b/bundles/org.openhab.binding.chromecast/src/main/resources/OH-INF/i18n/chromecast_de.properties @@ -38,10 +38,12 @@ channel-type.chromecast.appName.label = Anwendung channel-type.chromecast.appName.description = Zeigt den Namen der aktuellen Anwendung an. channel-type.chromecast.broadcastDate.label = Ausstrahlungsdatum channel-type.chromecast.broadcastDate.description = Zeigt das Ausstrahlungssdatum der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.broadcastDate.state.pattern = %1$td.%1$tm.%1$tY channel-type.chromecast.composer.label = Verfasser channel-type.chromecast.composer.description = Zeigt den Verfasser der (aktuell abgespielten) Video- oder Audiodatei an. channel-type.chromecast.creationDate.label = Erstellungsdatum channel-type.chromecast.creationDate.description = Zeigt das Erstellungsdatum der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.creationDate.state.pattern = %1$td.%1$tm.%1$tY channel-type.chromecast.currentTime.label = Laufzeit channel-type.chromecast.currentTime.description = Zeigt das Laufzeit der (aktuell abgespielten) Video- oder Audiodatei an. channel-type.chromecast.discNumber.label = Disk-Nummer @@ -64,6 +66,7 @@ channel-type.chromecast.playuri.label = URI abspielen channel-type.chromecast.playuri.description = Ermöglicht das Abspielen einer URI. channel-type.chromecast.releaseDate.label = Veröffentlichungsdatum channel-type.chromecast.releaseDate.description = Zeigt das Veröffentlichungsdatum der (aktuell abgespielten) Video- oder Audiodatei an. +channel-type.chromecast.releaseDate.state.pattern = %1$td.%1$tm.%1$tY channel-type.chromecast.seasonNumber.label = Staffelnummer channel-type.chromecast.seasonNumber.description = Zeigt die Staffelnummer der (aktuell abgespielten) Video- oder Audiodatei an. channel-type.chromecast.seriesTitle.label = Serientitel diff --git a/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties b/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties index 94f747e8981c2..42645d762be17 100644 --- a/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties +++ b/bundles/org.openhab.binding.gce/src/main/resources/OH-INF/i18n/gce_fr.properties @@ -1,7 +1,7 @@ # binding binding.gce.name = Extension GCE Electronics -binding.gce.description = Permet la communication avec l'IPX800 produite par GCE. +binding.gce.description = Cette extension permet de communiquer avec l'IPX800 produite par GCE. # thing types diff --git a/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_sv.properties b/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_sv.properties index ccf883ae420e2..77a08bab14fab 100644 --- a/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_sv.properties +++ b/bundles/org.openhab.binding.lghombot/src/main/resources/OH-INF/i18n/lghombot_sv.properties @@ -1,4 +1,3 @@ - # binding binding.lghombot.name = LG HomBot Binding binding.lghombot.description = LG HomBot binding tillåter kontrol och övervakning av din HomBot. diff --git a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties index 23096a95bb31d..0aea5a1038b96 100644 --- a/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties +++ b/bundles/org.openhab.binding.logreader/src/main/resources/OH-INF/i18n/logreader_de.properties @@ -41,6 +41,7 @@ channel-type.logreader.lastWarningEvent.label = Neueste Warnung channel-type.logreader.lastWarningEvent.description = Zeigt den neuesten Eintrag an, der mit dem Muster für Warnungen übereinstimmt. channel-type.logreader.logRotated.label = Letzte Rotation channel-type.logreader.logRotated.description = Zeigt die Zeit an, zu der die Logdatei zuletzt rotiert wurde. +channel-type.logreader.logRotated.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS channel-type.logreader.newCustomEvent.label = Neuer Benutzerdefinierter Eintrag channel-type.logreader.newCustomEvent.description = Dieser Channel wird bei einem neuen Eintrag ausgelöst, der mit dem benutzerdefinierten Muster übereinstimmt. channel-type.logreader.newErrorEvent.label = Neuer Fehler diff --git a/bundles/org.openhab.binding.meteoblue/src/main/resources/OH-INF/i18n/meteoblue_fr.properties b/bundles/org.openhab.binding.meteoblue/src/main/resources/OH-INF/i18n/meteoblue_fr.properties index 6b702995dd9df..8d8d411ef23a2 100644 --- a/bundles/org.openhab.binding.meteoblue/src/main/resources/OH-INF/i18n/meteoblue_fr.properties +++ b/bundles/org.openhab.binding.meteoblue/src/main/resources/OH-INF/i18n/meteoblue_fr.properties @@ -1,7 +1,7 @@ # binding binding.meteoblue.name = Extension meteoblue -binding.meteoblue.description = L'extension meteoblue interroge le service meteoblue pour récupérer les prévisions météorologiqes. +binding.meteoblue.description = L'extension meteoblue interroge le service meteoblue pour récupérer les prévisions météorologiques. # thing types diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol_fr.properties b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol_fr.properties new file mode 100644 index 0000000000000..cc473f544df7f --- /dev/null +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol_fr.properties @@ -0,0 +1,119 @@ +# binding +bindingName = Extension Niko Home Control +bindingDescription = Il s'agit de l'extension pour le système Niko Home Control. + +# bridge types +bridgeLabel = Pont Connexion Niko Home Control I +bridgeDescription = Ce pont de connexion représente une interface IP Niko Home Control I + +bridge2Label = Pont Connexion Niko Home Control II +bridge2Description = Ce pont de connexion représente une unité de contrôle connectée Niko Home Control II ou un hub intelligent sans fil + +bridgeConfigAddressLabel = Adresse IP ou nom d'hôte +bridgeConfigAddressDescription = Adresse IP de l'interface IP de Niko Home Control +bridge2ConfigAddressDescription = Adresse IP de l'unité de contrôle connectée ou du hub intelligent sans fil + +bridgeConfigPortLabel = Port du pont de connexion +bridgeConfigPortDescription = Port pour communiquer avec l'interface IP de Niko Home Control, par défaut 8000 +bridge2ConfigPortDescription = Port de communication sécurisée MQTT avec l'unité de contrôle connectée ou le hub intelligent sans fil, par défaut 8884 + +bridge2ConfigProfileLabel = Profil +bridge2ConfigProfileDescription = Profil utilisé dans Niko Home Control II pour l'API hobby + +bridge2ConfigPasswordLabel = Jeton API +bridge2ConfigPasswordDescription = Le jeton pour l'API hobby Niko Home Control II, ne doit pas être vide. Ce jeton devra être renouvelé après l'expiration (1 an après la création) + +bridgeConfigRefreshLabel = Fréquence de rafraîchissement +bridgeConfigRefreshDescription = Intervalle de rafraîchissement pour la connexion avec l'interface IP de Niko Home Control (minutes), par défaut 300. Si défini à 0 ou laissé vide, aucun rafraîchissement ne sera programmé +bridge2ConfigRefreshDescription = Intervalle de rafraîchissement pour la connexion avec l'unité de contrôle connectée ou le hub intelligent sans fil (minutes), par défaut 300. Si défini à 0 ou laissé vide, aucun rafraîchissement ne sera programmé + +# thing types +pushButtonLabel = Bouton Poussoir +pushButtonDescription = Action de type bouton-poussoir dans Niko Home Control + +onOffLabel = Interrupteur +onOffDescription = Action de type interrupteur dans Niko Home Control + +dimmerLabel = Variateur +dimmerDescription = Action de type variateur dans Niko Home Control + +blindLabel = Volet +blindDescription = Action de type volet roulant dans Niko Home Control + +thermostatLabel = Thermostat +thermostatDescription = Thermostat dans Niko Home Control + +energyMeterLabel = Compteur Énergie +energyMeterDescription = Compteur d'énergie dans Niko Home Control + +actionConfigActionIdLabel = ID de l'action +actionConfigActionIdDescription = ID de l'action Niko Home Control + +dimmerConfigStepLabel = Valeur de pas +dimmerConfigStepDescription = Valeur de pas utilisée pour augmenter/diminuer la luminosité, par défaut 10% + +blindConfigInvertLabel = Inverser la direction +blindConfigInvertDescription = Inverser la direction du volet roulant + +thermostatConfigThermostatIdLabel = ID du thermostat +thermostatConfigThermostatIdDescription = ID du thermostat Niko Home Control + +thermostatConfigOverruleTimeLabel = Durée de dérogation +thermostatConfigOverruleTimeDescription = Durée par défaut de dérogation en minutes quand une température de dérogation est réglée sans fournir de durée, 60 minutes par défaut + +energyMeterConfigEnergyMeterIdLabel = ID du compteur d'énergie +energyMeterConfigEnergyMeterIdDescription = ID du compteur d'énergie Niko Home Control + +#channel types +channelButtonLabel = Bouton +channelButtonDescription = Contrôle bouton-poussoir pour action dans Niko Home Control + +channelRollershutterLabel = Volet Roulant +channelRollershutterDescription = Contrôle du moteur de volet roulant dans Niko Home Control + +channelMeasuredLabel = Température Mesurée +channelMeasuredDescription = Température mesurée par le thermostat + +channelSetpointLabel = Température Souhaitée +channelSetpointDescription = Température de consigne du thermostat + +channelOverruletimeLabel = Durée Dérogation +channelOverruletimeDescription = Durée de dérogation de la température cible du thermostat en minutes. + +channelModeLabel = Mode +channelModeDescription = Mode de fonctionnement du thermostat +channelModeOption0 = jour +channelModeOption1 = nuit +channelModeOption2 = éco +channelModeOption3 = éteint +channelModeOption4 = frais +channelModeOption5 = prog 1 +channelModeOption6 = prog 2 +channelModeOption7 = prog 3 + +channelPowerLabel = Puissance +channelPowerDescription = Consommation / production d'énergie instantanée (consommation si positive) + +channelAlarmLabel = Alarme +channelAlarmDescription = Alarme de Niko Home Control + +channelNoticeLabel = Notification +channelNoticeDescription = Notification de Niko Home Control + +# thing status messages +offline.configuration-error.ip = Impossible de résoudre l'IP du pont de connexion avec le nom d'hôte donné +offline.configuration-error.tokenEmpty = Le jeton de l'API hobby est vide +offline.configuration-error.tokenExpired = Le jeton de l'API hobby a expiré + +offline.configuration-error.actionId = L'ID configuré ne correspond pas à une action dans l'unité de contrôle +offline.configuration-error.actionType = Type d'action non supporté +offline.configuration-error.actionRemoved = L'action a été retirée de l'unité de contrôle + +offline.configuration-error.energyMeterId = L'ID configuré ne correspond pas à un compteur d'énergie dans l'unité de contrôle +offline.configuration-error.energyMeterRemoved = Le compteur d'énergie a été retiré de l'unité de contrôle + +offline.configuration-error.thermostatId = L'ID configuré ne correspond pas à un thermostat dans l'unité de contrôle +offline.configuration-error.thermostatRemoved = Le thermostat a été retiré de l'unité de contrôle + +offline.communication-error = Erreur de communication avec l'unité de contrôle +offline.bridge-unitialized = Pont de connexion non initialisé diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties index 7002b89633fba..b82b5b5a9b919 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties @@ -1,40 +1,104 @@ # binding + binding.openweathermap.name = OpenWeatherMap Binding binding.openweathermap.description = OpenWeatherMap - Aktuelles Wetter und Prognosen in Ihrer Stadt. -# bridge types +# thing types + +thing-type.openweathermap.air-pollution.label = Luftqualität +thing-type.openweathermap.air-pollution.description = Ermöglicht die Anzeige der aktuellen Luftqualität. +thing-type.openweathermap.onecall-history.label = One Call API - Historische Wetterdaten +thing-type.openweathermap.onecall-history.description = Ermöglicht die Anzeige von historischen Wetterinformationen. +thing-type.openweathermap.onecall.label = One Call API - Wetterinformationen +thing-type.openweathermap.onecall.description = Ermöglicht die Anzeige der aktuellen Wetterinformationen und der Wettervorhersage. +thing-type.openweathermap.onecall.group.forecastDay2.label = Wettervorhersage für übermorgen +thing-type.openweathermap.onecall.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay3.label = Wettervorhersage für 3 Tage +thing-type.openweathermap.onecall.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay4.label = Wettervorhersage für 4 Tage +thing-type.openweathermap.onecall.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay5.label = Wettervorhersage für 5 Tage +thing-type.openweathermap.onecall.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay6.label = Wettervorhersage für 6 Tage +thing-type.openweathermap.onecall.group.forecastDay6.description = Fasst Daten der Wettervorhersage in sechs Tagen zusammen. +thing-type.openweathermap.onecall.group.forecastDay7.label = Wettervorhersage für 7 Tage +thing-type.openweathermap.onecall.group.forecastDay7.description = Fasst Daten der Wettervorhersage in sieben Tagen zusammen. +thing-type.openweathermap.onecall.group.forecastToday.label = Wettervorhersage für heute +thing-type.openweathermap.onecall.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastTomorrow.label = Wettervorhersage für morgen +thing-type.openweathermap.onecall.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.uvindex.label = UV-Index +thing-type.openweathermap.uvindex.description = Ermöglicht die Anzeige des aktuellen UV-Index. +thing-type.openweathermap.uvindex.group.forecastDay2.label = UV-Index für übermorgen +thing-type.openweathermap.uvindex.group.forecastDay2.description = Fasst Daten der übermorgigen UV-Index Vorhersage zusammen. +thing-type.openweathermap.uvindex.group.forecastDay3.label = UV-Index für 3 Tage +thing-type.openweathermap.uvindex.group.forecastDay3.description = Fasst Daten der UV-Index Vorhersage in drei Tagen zusammen. +thing-type.openweathermap.uvindex.group.forecastDay4.label = UV-Index für 4 Tage +thing-type.openweathermap.uvindex.group.forecastDay4.description = Fasst Daten der UV-Index Vorhersage in vier Tagen zusammen. +thing-type.openweathermap.uvindex.group.forecastDay5.label = UV-Index für 5 Tage +thing-type.openweathermap.uvindex.group.forecastDay5.description = Fasst Daten der UV-Index Vorhersage in fünf Tagen zusammen. +thing-type.openweathermap.uvindex.group.forecastTomorrow.label = UV-Index für morgen +thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Fasst Daten der morgigen UV-Index Vorhersage zusammen. +thing-type.openweathermap.weather-and-forecast.label = Wetterinformationen +thing-type.openweathermap.weather-and-forecast.description = Ermöglicht die Anzeige der aktuellen Wetterinformationen und der Wettervorhersage. +thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Wettervorhersage für übermorgen +thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Wettervorhersage für 3 Tage +thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Wettervorhersage für 4 Tage +thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Wettervorhersage für 5 Tage +thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Wettervorhersage für 3 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Fasst Daten der Wettervorhersage in den nächsten drei Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Wettervorhersage für 6 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Fasst Daten der Wettervorhersage in sechs Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Wettervorhersage für 9 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Fasst Daten der Wettervorhersage in neun Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Wettervorhersage für 12 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Fasst Daten der Wettervorhersage in zwölf Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Wettervorhersage für 15 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Fasst Daten der Wettervorhersage in 15 Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Wettervorhersage für 18 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Fasst Daten der Wettervorhersage in 18 Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Wettervorhersage für 21 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Fasst Daten der Wettervorhersage in 21 Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Wettervorhersage für 24 Stunden +thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Fasst Daten der Wettervorhersage in 24 Stunden zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Wettervorhersage für heute +thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage zusammen. +thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Wettervorhersage für morgen +thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage zusammen. thing-type.openweathermap.weather-api.label = OpenWeatherMap Konto thing-type.openweathermap.weather-api.description = Ermöglicht den Zugriff auf die OpenWeatherMap API. -# bridge types config +# thing types config + bridge-type.config.openweathermap.weather-api.apikey.label = API Schlüssel bridge-type.config.openweathermap.weather-api.apikey.description = API Schlüssel für den Zugriff auf die OpenWeatherMap API. - -bridge-type.config.openweathermap.weather-api.refreshInterval.label = Abfrageintervall -bridge-type.config.openweathermap.weather-api.refreshInterval.description = Intervall zur Abfrage der OpenWeatherMap API (in min). - bridge-type.config.openweathermap.weather-api.language.label = Sprache bridge-type.config.openweathermap.weather-api.language.description = Sprache zur Anzeige der Daten. bridge-type.config.openweathermap.weather-api.language.option.af = Afrikanisch bridge-type.config.openweathermap.weather-api.language.option.al = Albanisch bridge-type.config.openweathermap.weather-api.language.option.ar = Arabisch bridge-type.config.openweathermap.weather-api.language.option.az = Aserbaidschanisch +bridge-type.config.openweathermap.weather-api.language.option.eu = Baskisch bridge-type.config.openweathermap.weather-api.language.option.bg = Bulgarisch bridge-type.config.openweathermap.weather-api.language.option.ca = Katalanisch +bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinesisch - Simplified +bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinesisch - Traditional +bridge-type.config.openweathermap.weather-api.language.option.hr = Kroatisch bridge-type.config.openweathermap.weather-api.language.option.cz = Tschechisch bridge-type.config.openweathermap.weather-api.language.option.da = Dänisch -bridge-type.config.openweathermap.weather-api.language.option.de = Deutsch -bridge-type.config.openweathermap.weather-api.language.option.el = Griechisch +bridge-type.config.openweathermap.weather-api.language.option.nl = Holländisch bridge-type.config.openweathermap.weather-api.language.option.en = Englisch -bridge-type.config.openweathermap.weather-api.language.option.es = Spanisch -bridge-type.config.openweathermap.weather-api.language.option.eu = Baskisch -bridge-type.config.openweathermap.weather-api.language.option.fa = Persisch (Farsi) bridge-type.config.openweathermap.weather-api.language.option.fi = Finnisch bridge-type.config.openweathermap.weather-api.language.option.fr = Französisch bridge-type.config.openweathermap.weather-api.language.option.gl = Galizisch +bridge-type.config.openweathermap.weather-api.language.option.de = Deutsch +bridge-type.config.openweathermap.weather-api.language.option.el = Griechisch bridge-type.config.openweathermap.weather-api.language.option.he = Hebräisch bridge-type.config.openweathermap.weather-api.language.option.hi = Hindi -bridge-type.config.openweathermap.weather-api.language.option.hr = Kroatisch bridge-type.config.openweathermap.weather-api.language.option.hu = Ungarisch bridge-type.config.openweathermap.weather-api.language.option.id = Indonesisch bridge-type.config.openweathermap.weather-api.language.option.it = Italienisch @@ -43,286 +107,89 @@ bridge-type.config.openweathermap.weather-api.language.option.kr = Koreanisch bridge-type.config.openweathermap.weather-api.language.option.la = Lettisch bridge-type.config.openweathermap.weather-api.language.option.lt = Litauisch bridge-type.config.openweathermap.weather-api.language.option.mk = Mazedonisch -bridge-type.config.openweathermap.weather-api.language.option.nl = Holländisch bridge-type.config.openweathermap.weather-api.language.option.no = Norwegisch +bridge-type.config.openweathermap.weather-api.language.option.fa = Persisch (Farsi) bridge-type.config.openweathermap.weather-api.language.option.pl = Polnisch -bridge-type.config.openweathermap.weather-api.language.option.pt = Portugiesisch bridge-type.config.openweathermap.weather-api.language.option.pt_br = Português Brasilien +bridge-type.config.openweathermap.weather-api.language.option.pt = Portugiesisch bridge-type.config.openweathermap.weather-api.language.option.ro = Rumänisch bridge-type.config.openweathermap.weather-api.language.option.ru = Russisch -bridge-type.config.openweathermap.weather-api.language.option.se = Schwedisch +bridge-type.config.openweathermap.weather-api.language.option.sr = Serbisch bridge-type.config.openweathermap.weather-api.language.option.sk = Slowakisch bridge-type.config.openweathermap.weather-api.language.option.sl = Slowenisch -bridge-type.config.openweathermap.weather-api.language.option.sr = Serbisch +bridge-type.config.openweathermap.weather-api.language.option.es = Spanisch +bridge-type.config.openweathermap.weather-api.language.option.se = Schwedisch bridge-type.config.openweathermap.weather-api.language.option.th = Thailändisch bridge-type.config.openweathermap.weather-api.language.option.tr = Türkisch bridge-type.config.openweathermap.weather-api.language.option.uk = Ukrainisch bridge-type.config.openweathermap.weather-api.language.option.vi = Vietnamesisch -bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinesisch - Simplified -bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinesisch - Traditional bridge-type.config.openweathermap.weather-api.language.option.zu = Zulu - -# thing types -thing-type.openweathermap.weather-and-forecast.label = Wetterinformationen -thing-type.openweathermap.weather-and-forecast.description = Ermöglicht die Anzeige der aktuellen Wetterinformationen und der Wettervorhersage. - -thing-type.openweathermap.uvindex.label = UV-Index -thing-type.openweathermap.uvindex.description = Ermöglicht die Anzeige des aktuellen UV-Index. - -thing-type.openweathermap.air-pollution.label = Luftqualität -thing-type.openweathermap.air-pollution.description = Ermöglicht die Anzeige der aktuellen Luftqualität. - -# thing types config -thing-type.config.openweathermap.weather-and-forecast.location.label = Ort der Wetterdaten -thing-type.config.openweathermap.weather-and-forecast.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). - -thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Stunden -thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Anzahl der Stunden für die Wettervorhersage. - -thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Tage -thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Anzahl der Tage für die Wettervorhersage. - -thing-type.config.openweathermap.uvindex.location.label = Ort der Wetterdaten -thing-type.config.openweathermap.uvindex.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). - -thing-type.config.openweathermap.uvindex.forecastDays.label = Tage -thing-type.config.openweathermap.uvindex.forecastDays.description = Anzahl der Tage für die UV-Index Vorhersage. - -thing-type.config.openweathermap.air-pollution.location.label = Ort der Wetterdaten -thing-type.config.openweathermap.air-pollution.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). - +bridge-type.config.openweathermap.weather-api.refreshInterval.label = Aktualisierungsintervall +bridge-type.config.openweathermap.weather-api.refreshInterval.description = Intervall zur Aktualisierung der OpenWeatherMap API (in min). thing-type.config.openweathermap.air-pollution.forecastHours.label = Stunden thing-type.config.openweathermap.air-pollution.forecastHours.description = Anzahl der Stunden für die Vorhersage der Luftqualität. - -thing-type.config.openweathermap.onecall.location.label = Ort der Wetterdaten -thing-type.config.openweathermap.onecall.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). - -thing-type.config.openweathermap.onecall.forecastMinutes.label = Minuten -thing-type.config.openweathermap.onecall.forecastMinutes.description = Anzahl der Minuten für die Vorhersage von Niederschlag. - -thing-type.config.openweathermap.onecall.forecastHours.label = Stunden -thing-type.config.openweathermap.onecall.forecastHours.description = Anzahl der Stunden für die Wettervorhersage. - +thing-type.config.openweathermap.air-pollution.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.air-pollution.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). +thing-type.config.openweathermap.onecall-history.historyDay.label = Historische Tage +thing-type.config.openweathermap.onecall-history.historyDay.description = Anzahl der Tage für die historischen Wetterdaten. +thing-type.config.openweathermap.onecall-history.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.onecall-history.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). thing-type.config.openweathermap.onecall.forecastDays.label = Tage thing-type.config.openweathermap.onecall.forecastDays.description = Anzahl der Tage für die Wettervorhersage, inklusive aktueller Tag. - +thing-type.config.openweathermap.onecall.forecastHours.label = Stunden +thing-type.config.openweathermap.onecall.forecastHours.description = Anzahl der Stunden für die Wettervorhersage. +thing-type.config.openweathermap.onecall.forecastMinutes.label = Minuten +thing-type.config.openweathermap.onecall.forecastMinutes.description = Anzahl der Minuten für die Vorhersage von Niederschlag. +thing-type.config.openweathermap.onecall.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.onecall.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). thing-type.config.openweathermap.onecall.numberOfAlerts.label = Wetterwarnungen thing-type.config.openweathermap.onecall.numberOfAlerts.description = Anzahl der Wetterwarnungen. +thing-type.config.openweathermap.uvindex.forecastDays.label = Tage +thing-type.config.openweathermap.uvindex.forecastDays.description = Anzahl der Tage für die UV-Index Vorhersage. +thing-type.config.openweathermap.uvindex.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.uvindex.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). +thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Tage +thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Anzahl der Tage für die Wettervorhersage. +thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Stunden +thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Anzahl der Stunden für die Wettervorhersage. +thing-type.config.openweathermap.weather-and-forecast.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.weather-and-forecast.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). # channel group types -channel-group-type.openweathermap.station.label = Wetterstation -channel-group-type.openweathermap.station.description = Fasst Daten über die Wetterstation oder den Ort zusammen. - -channel-group-type.openweathermap.weather.label = Aktuelles Wetter -channel-group-type.openweathermap.weather.description = Fasst aktuelle Wetterdaten zusammen. - -channel-group-type.openweathermap.hourlyForecast.label = 3 Stunden Wettervorhersage -channel-group-type.openweathermap.hourlyForecast.description = Fasst Daten der 5 Tage / 3 Stunden Wettervorhersage zusammen. - -channel-group-type.openweathermap.dailyForecast.label = Tägliche Wettervorhersage -channel-group-type.openweathermap.dailyForecast.description = Fasst Daten der 16 Tage / täglichen Wettervorhersage zusammen. - -channel-group-type.openweathermap.uvindex.label = Aktueller UV-Index -channel-group-type.openweathermap.uvindex.description = Fasst aktuelle UV-Index Daten zusammen. - -channel-group-type.openweathermap.uvindexForecast.label = UV-Index Vorhersage -channel-group-type.openweathermap.uvindexForecast.description = Fasst Daten der UV-Index Vorhersage zusammen. channel-group-type.openweathermap.airPollution.label = Aktuelle Luftqualität channel-group-type.openweathermap.airPollution.description = Fasst Daten über die aktuelle Luftqualität zusammen. - channel-group-type.openweathermap.airPollutionForecast.label = Vorhersage der Luftqualität channel-group-type.openweathermap.airPollutionForecast.description = Fasst Daten über die vorhergesagte Luftqualität zusammen. - -channel-group-type.openweathermap.oneCallCurrent.label = Aktuelles Wetter -channel-group-type.openweathermap.oneCallCurrent.description = Fasst aktuelle Wetterdaten der One Call API zusammen. - +channel-group-type.openweathermap.dailyForecast.label = Tägliche Wettervorhersage +channel-group-type.openweathermap.dailyForecast.description = Fasst Daten der 16 Tage / täglichen Wettervorhersage zusammen. +channel-group-type.openweathermap.hourlyForecast.label = 3 Stunden Wettervorhersage +channel-group-type.openweathermap.hourlyForecast.description = Fasst Daten der 5 Tage / 3 Stunden Wettervorhersage zusammen. channel-group-type.openweathermap.oneCallAlerts.label = Wetterwarnungen channel-group-type.openweathermap.oneCallAlerts.description = Fasst Daten von Wetterwarnungen zusammen. +channel-group-type.openweathermap.oneCallCurrent.label = Aktuelles Wetter +channel-group-type.openweathermap.oneCallCurrent.description = Fasst aktuelle Wetterdaten der One Call API zusammen. +channel-group-type.openweathermap.oneCallDaily.label = One Call API - Tägliche Wettervorhersage +channel-group-type.openweathermap.oneCallDaily.description = Fasst Daten der täglichen Wettervorhersage zusammen. +channel-group-type.openweathermap.oneCallHistory.label = Historische Wetterdaten +channel-group-type.openweathermap.oneCallHistory.description = Fasst historische Wetterdaten zusammen. +channel-group-type.openweathermap.oneCallHistoryHours.label = Stündliche Historische Wetterdaten +channel-group-type.openweathermap.oneCallHistoryHours.description = Fasst stündliche historische Wetterdaten zusammen. +channel-group-type.openweathermap.oneCallHourly.label = One Call API - Stündliche Wettervorhersage +channel-group-type.openweathermap.oneCallHourly.description = Fasst Daten der stündlichen Wettervorhersage zusammen. +channel-group-type.openweathermap.oneCallMinutely.label = One Call API - Minütige Wettervorhersage +channel-group-type.openweathermap.oneCallMinutely.description = Fasst Daten der minütigen Niederschlagsvorhersage zusammen. +channel-group-type.openweathermap.station.label = Wetterstation +channel-group-type.openweathermap.station.description = Fasst Daten über die Wetterstation oder den Ort zusammen. +channel-group-type.openweathermap.station.channel.location.description = Zeigt den Ort der Wetterstation in geographischen Koordinaten (Breitengrad/Längengrad/Höhe) an. +channel-group-type.openweathermap.uvindex.label = Aktueller UV-Index +channel-group-type.openweathermap.uvindex.description = Fasst aktuelle UV-Index Daten zusammen. +channel-group-type.openweathermap.uvindexForecast.label = UV-Index Vorhersage +channel-group-type.openweathermap.uvindexForecast.description = Fasst Daten der UV-Index Vorhersage zusammen. +channel-group-type.openweathermap.weather.label = Aktuelles Wetter +channel-group-type.openweathermap.weather.description = Fasst aktuelle Wetterdaten zusammen. -# channel groups -thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Wettervorhersage für 3 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Fasst Daten der Wettervorhersage in den nächsten drei Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Wettervorhersage für 6 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Fasst Daten der Wettervorhersage in sechs Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Wettervorhersage für 9 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Fasst Daten der Wettervorhersage in neun Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Wettervorhersage für 12 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Fasst Daten der Wettervorhersage in zwölf Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Wettervorhersage für 15 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Fasst Daten der Wettervorhersage in 15 Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Wettervorhersage für 18 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Fasst Daten der Wettervorhersage in 18 Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Wettervorhersage für 21 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Fasst Daten der Wettervorhersage in 21 Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Wettervorhersage für 24 Stunden -thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Fasst Daten der Wettervorhersage in 24 Stunden zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Wettervorhersage für heute -thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Wettervorhersage für morgen -thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Wettervorhersage für übermorgen -thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Wettervorhersage für 3 Tage -thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Wettervorhersage für 4 Tage -thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen zusammen. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Wettervorhersage für 5 Tage -thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen zusammen. - -thing-type.openweathermap.uvindex.group.forecastTomorrow.label = UV-Index für morgen -thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Fasst Daten der morgigen UV-Index Vorhersage zusammen. - -thing-type.openweathermap.uvindex.group.forecastDay2.label = UV-Index für übermorgen -thing-type.openweathermap.uvindex.group.forecastDay2.description = Fasst Daten der übermorgigen UV-Index Vorhersage zusammen. - -thing-type.openweathermap.uvindex.group.forecastDay3.label = UV-Index für 3 Tage -thing-type.openweathermap.uvindex.group.forecastDay3.description = Fasst Daten der UV-Index Vorhersage in drei Tagen zusammen. - -thing-type.openweathermap.uvindex.group.forecastDay4.label = UV-Index für 4 Tage -thing-type.openweathermap.uvindex.group.forecastDay4.description = Fasst Daten der UV-Index Vorhersage in vier Tagen zusammen. - -thing-type.openweathermap.uvindex.group.forecastDay5.label = UV-Index für 5 Tage -thing-type.openweathermap.uvindex.group.forecastDay5.description = Fasst Daten der UV-Index Vorhersage in fünf Tagen zusammen. - -thing-type.openweathermap.onecall.group.forecastToday.label = Wettervorhersage für heute -thing-type.openweathermap.onecall.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage der One Call API zusammen. - -thing-type.openweathermap.onecall.group.forecastTomorrow.label = Wettervorhersage für morgen -thing-type.openweathermap.onecall.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage der One Call API zusammen. - -thing-type.openweathermap.onecall.group.forecastDay2.label = Wettervorhersage für übermorgen -thing-type.openweathermap.onecall.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage der One Call API zusammen. - -thing-type.openweathermap.onecall.group.forecastDay3.label = Wettervorhersage für 3 Tage -thing-type.openweathermap.onecall.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen der One Call API zusammen. - -thing-type.openweathermap.onecall.group.forecastDay4.label = Wettervorhersage für 4 Tage -thing-type.openweathermap.onecall.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen der One Call API zusammen. - -thing-type.openweathermap.onecall.group.forecastDay5.label = Wettervorhersage für 5 Tage -thing-type.openweathermap.onecall.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen der One Call API zusammen. - -# channel types -channel-type.openweathermap.station-id.label = Station-ID -channel-type.openweathermap.station-id.description = Zeigt die ID der Wetterstation oder des Ortes an. - -channel-type.openweathermap.station-name.label = Name -channel-type.openweathermap.station-name.description = Zeigt den Namen der Wetterstation oder des Ortes an. - -channel-group-type.openweathermap.station.channel.location.label = Ort -channel-group-type.openweathermap.station.channel.location.description = Zeigt den Ort der Wetterstation in geographischen Koordinaten (Breitengrad/Längengrad/Höhe) an. - -channel-type.openweathermap.time-stamp.label = Letzte Messung -channel-type.openweathermap.time-stamp.description = Zeigt den Zeitpunkt der letzten Messung an. -channel-type.openweathermap.time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.hourly-forecast-time-stamp.label = Vorhersage Zeit -channel-type.openweathermap.hourly-forecast-time-stamp.description = Zeigt den Zeitpunkt der Vorhersage an. -channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.daily-forecast-time-stamp.label = Vorhersage Datum -channel-type.openweathermap.daily-forecast-time-stamp.description = Zeigt das Datum der Vorhersage an. -channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY - -channel-type.openweathermap.sunrise.label = Sonnenaufgang -channel-type.openweathermap.sunrise.description = Zeigt den Zeitpunkt des Sonnenaufgangs an. -channel-type.openweathermap.sunrise.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.sunset.label = Sonnenuntergang -channel-type.openweathermap.sunset.description = Zeigt den Zeitpunkt des Sonnenuntergangs an. -channel-type.openweathermap.sunset.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.condition.label = Wetterlage -channel-type.openweathermap.condition.description = Zeigt die aktuelle Wetterlage an. - -channel-type.openweathermap.forecasted-condition.label = Vorhergesagte Wetterlage -channel-type.openweathermap.forecasted-condition.description = Zeigt die vorhergesagte Wetterlage an. - -channel-type.openweathermap.condition-id.label = Wetterlage-ID -channel-type.openweathermap.condition-id.description = Zeigt die ID der Wetterlage an. - -channel-type.openweathermap.condition-icon.label = Icon -channel-type.openweathermap.condition-icon.description = Zeigt das Icon der Wetterlage an. - -channel-type.openweathermap.condition-icon-id.label = Icon-ID -channel-type.openweathermap.condition-icon-id.description = Zeigt die ID für das Icon der Wetterlage an. - -channel-type.openweathermap.forecasted-outdoor-temperature.label = Vorhergesagte Temperatur -channel-type.openweathermap.forecasted-outdoor-temperature.description = Zeigt die vorhergesagte Außentemperatur an. - -channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Minimale Temperatur -channel-type.openweathermap.forecasted-min-outdoor-temperature.description = Zeigt die vorhergesagte minimale Außentemperatur an. - -channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Maximale Temperatur -channel-type.openweathermap.forecasted-max-outdoor-temperature.description = Zeigt die vorhergesagte maximale Außentemperatur an. - -channel-type.openweathermap.apparent-temperature.label = Gefühlte Temperatur -channel-type.openweathermap.apparent-temperature.description = Zeigt die gefühlte Außentemperatur an. - -channel-type.openweathermap.forecasted-apparent-temperature.label = Vorhergesagte Gefühlte Temperatur -channel-type.openweathermap.forecasted-apparent-temperature.description = Zeigt die vorhergesagte gefühlte Außentemperatur an. - -channel-type.openweathermap.forecasted-barometric-pressure.label = Vorhergesagter Luftdruck -channel-type.openweathermap.forecasted-barometric-pressure.description = Zeigt den vorhergesagten Luftdruck an. - -channel-type.openweathermap.forecasted-atmospheric-humidity.label = Vorhergesagte Luftfeuchtigkeit -channel-type.openweathermap.forecasted-atmospheric-humidity.description = Zeigt die vorhergesagte Luftfeuchtigkeit an. - -channel-type.openweathermap.forecasted-wind-speed.label = Vorhergesagte Windgeschwindigkeit -channel-type.openweathermap.forecasted-wind-speed.description = Zeigt die vorhergesagte Windgeschwindigkeit an. - -channel-type.openweathermap.forecasted-wind-direction.label = Vorhergesagte Windrichtung -channel-type.openweathermap.forecasted-wind-direction.description = Zeigt die vorhergesagte Windrichtung an. - -channel-type.openweathermap.gust-speed.label = Windböengeschwindigkeit -channel-type.openweathermap.gust-speed.description = Zeigt die aktuelle Windböengeschwindigkeit an. - -channel-type.openweathermap.forecasted-gust-speed.label = Vorhergesagte Windböengeschwindigkeit -channel-type.openweathermap.forecasted-gust-speed.description = Zeigt die vorhergesagte Windböengeschwindigkeit an. - -channel-type.openweathermap.cloudiness.label = Bewölkung -channel-type.openweathermap.cloudiness.description = Zeigt die aktuelle Bewölkung an. - -channel-type.openweathermap.forecasted-cloudiness.label = Vorhergesagte Bewölkung -channel-type.openweathermap.forecasted-cloudiness.description = Zeigt die vorhergesagte Bewölkung an. - -channel-type.openweathermap.visibility.label = Sichtweite -channel-type.openweathermap.visibility.description = Zeigt die aktuelle Sichtweite an. - -channel-type.openweathermap.rain.label = Regen -channel-type.openweathermap.rain.description = Zeigt den kumulierten Regen der letzten Stunde an. - -channel-type.openweathermap.forecasted-rain.label = Vorhergesagter Regen -channel-type.openweathermap.forecasted-rain.description = Zeigt die vorhergesagte Regenmenge an. - -channel-type.openweathermap.snow.label = Schnee -channel-type.openweathermap.snow.description = Zeigt den kumulierten Schnee der letzten Stunde an. - -channel-type.openweathermap.forecasted-snow.label = Vorhergesagter Schnee -channel-type.openweathermap.forecasted-snow.description = Zeigt die vorhergesagte Schneemenge an. - -channel-type.openweathermap.precip-probability.label = Vorhergesagte Niederschlagswahrscheinlichkeit -channel-type.openweathermap.precip-probability.description = Zeigt die vorhergesagte Niederschlagswahrscheinlichkeit an. - -channel-type.openweathermap.uvindex.label = UV-Index -channel-type.openweathermap.uvindex.description = Zeigt den aktuellen UV-Index an. - -channel-type.openweathermap.forecasted-uvindex.label = Vorhergesagter UV-Index -channel-type.openweathermap.forecasted-uvindex.description = Zeigt den vorhergesagten UV-Index an. +# channel types channel-type.openweathermap.air-quality-index.label = Luftqualitätsindex channel-type.openweathermap.air-quality-index.description = Zeigt den aktuellen Luftqualitätsindex an. @@ -331,7 +198,51 @@ channel-type.openweathermap.air-quality-index.state.option.2 = Befriedigend channel-type.openweathermap.air-quality-index.state.option.3 = Moderat channel-type.openweathermap.air-quality-index.state.option.4 = Ungesund channel-type.openweathermap.air-quality-index.state.option.5 = Äußerst Ungesund - +channel-type.openweathermap.alert-description.label = Beschreibung +channel-type.openweathermap.alert-description.description = Zeigt die Beschreibung der Wetterwarnung an. +channel-type.openweathermap.alert-event.label = Art +channel-type.openweathermap.alert-event.description = Art der Warnung, z.B. FROST. +channel-type.openweathermap.alert-expires.label = Gültig bis +channel-type.openweathermap.alert-expires.description = Datum und Uhrzeit, bis zu dem die Warnung gültig ist. +channel-type.openweathermap.alert-expires.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.alert-onset.label = Gültig ab +channel-type.openweathermap.alert-onset.description = Datum und Uhrzeit, ab dem die Warnung gültig ist. +channel-type.openweathermap.alert-onset.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.alert-source.label = Quelle +channel-type.openweathermap.alert-source.description = Zeigt die Quelle der Wetterwarnung an. +channel-type.openweathermap.ammonia.label = Ammoniak +channel-type.openweathermap.ammonia.description = Aktuelle Konzentration an Ammoniak. +channel-type.openweathermap.apparent-day.label = Gefühlte Temperatur am Tag +channel-type.openweathermap.apparent-day.description = Zeigt die gefühlte Temperatur am Tag an. +channel-type.openweathermap.apparent-evening.label = Gefühlte Temperatur am Abend +channel-type.openweathermap.apparent-evening.description = Zeigt die gefühlte Temperatur am Abend an. +channel-type.openweathermap.apparent-morning.label = Gefühlte Temperatur am Morgen +channel-type.openweathermap.apparent-morning.description = Zeigt die gefühlte Temperatur am Morgen an. +channel-type.openweathermap.apparent-night.label = Gefühlte Temperatur in der Nacht +channel-type.openweathermap.apparent-night.description = Zeigt die gefühlte Temperatur in der Nacht an. +channel-type.openweathermap.apparent-temperature.label = Gefühlte Temperatur +channel-type.openweathermap.apparent-temperature.description = Zeigt die gefühlte Außentemperatur an. +channel-type.openweathermap.carbon-monoxide.label = Kohlenmonoxid +channel-type.openweathermap.carbon-monoxide.description = Aktuelle Konzentration an Kohlenmonoxid. +channel-type.openweathermap.cloudiness.label = Bewölkung +channel-type.openweathermap.cloudiness.description = Zeigt die aktuelle Bewölkung an. +channel-type.openweathermap.condition-icon-id.label = Icon-ID +channel-type.openweathermap.condition-icon-id.description = Zeigt die ID für das Icon der Wetterlage an. +channel-type.openweathermap.condition-icon.label = Icon +channel-type.openweathermap.condition-icon.description = Zeigt das Icon der Wetterlage an. +channel-type.openweathermap.condition-id.label = Wetterlage-ID +channel-type.openweathermap.condition-id.description = Zeigt die ID der Wetterlage an. +channel-type.openweathermap.condition.label = Wetterlage +channel-type.openweathermap.condition.description = Zeigt die aktuelle Wetterlage an. +channel-type.openweathermap.daily-forecast-time-stamp.label = Vorhersage Datum +channel-type.openweathermap.daily-forecast-time-stamp.description = Zeigt das Datum der Vorhersage an. +channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY +channel-type.openweathermap.day-temperature.label = Temperatur am Tag +channel-type.openweathermap.day-temperature.description = Zeigt die vorhergesagte Temperatur am Tag an. +channel-type.openweathermap.dew-point.label = Taupunkttemperatur +channel-type.openweathermap.dew-point.description = Zeigt die vorhergesagte Taupunkttemperatur an. +channel-type.openweathermap.evening-temperature.label = Temperatur am Abend +channel-type.openweathermap.evening-temperature.description = Prognostizierte Außentemperatur für den Abend. channel-type.openweathermap.forecasted-air-quality-index.label = Vorhergesagter Luftqualitätsindex channel-type.openweathermap.forecasted-air-quality-index.description = Zeigt den vorhergesagten Luftqualitätsindex an. channel-type.openweathermap.forecasted-air-quality-index.state.option.1 = Gut @@ -339,90 +250,117 @@ channel-type.openweathermap.forecasted-air-quality-index.state.option.2 = Befrie channel-type.openweathermap.forecasted-air-quality-index.state.option.3 = Moderat channel-type.openweathermap.forecasted-air-quality-index.state.option.4 = Ungesund channel-type.openweathermap.forecasted-air-quality-index.state.option.5 = Äußerst Ungesund - -channel-type.openweathermap.particulate-matter-2dot5.label = Feinstaub - PM2.5 -channel-type.openweathermap.particulate-matter-2dot5.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 2,5 µm. - -channel-type.openweathermap.forecasted-particulate-matter-2dot5.label = Vorhergesagter Feinstaub - PM2.5 -channel-type.openweathermap.forecasted-particulate-matter-2dot5.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 2,5 µm. - -channel-type.openweathermap.particulate-matter-10.label = Feinstaub - PM10 -channel-type.openweathermap.particulate-matter-10.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 10 µm. - -channel-type.openweathermap.forecasted-particulate-matter-10.label = Vorhergesagter Feinstaub - PM10 -channel-type.openweathermap.forecasted-particulate-matter-10.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 10 µm. - -channel-type.openweathermap.carbon-monoxide.label = Kohlenmonoxid -channel-type.openweathermap.carbon-monoxide.description = Aktuelle Konzentration an Kohlenmonoxid. - +channel-type.openweathermap.forecasted-ammonia.label = Vorhergesagter Ammoniak +channel-type.openweathermap.forecasted-ammonia.description = Vorhergesagte Konzentration an Ammoniak. +channel-type.openweathermap.forecasted-apparent-temperature.label = Vorhergesagte Gefühlte Temperatur +channel-type.openweathermap.forecasted-apparent-temperature.description = Zeigt die vorhergesagte gefühlte Außentemperatur an. +channel-type.openweathermap.forecasted-atmospheric-humidity.label = Vorhergesagte Luftfeuchtigkeit +channel-type.openweathermap.forecasted-atmospheric-humidity.description = Zeigt die vorhergesagte Luftfeuchtigkeit an. +channel-type.openweathermap.forecasted-barometric-pressure.label = Vorhergesagter Luftdruck +channel-type.openweathermap.forecasted-barometric-pressure.description = Zeigt den vorhergesagten Luftdruck an. channel-type.openweathermap.forecasted-carbon-monoxide.label = Vorhergesagter Kohlenmonoxid channel-type.openweathermap.forecasted-carbon-monoxide.description = Vorhergesagte Konzentration an Kohlenmonoxid. - -channel-type.openweathermap.nitrogen-monoxide.label = Stickstoffmonoxid -channel-type.openweathermap.nitrogen-monoxide.description = Aktuelle Konzentration an Stickstoffmonoxid. - +channel-type.openweathermap.forecasted-cloudiness.label = Vorhergesagte Bewölkung +channel-type.openweathermap.forecasted-cloudiness.description = Zeigt die vorhergesagte Bewölkung an. +channel-type.openweathermap.forecasted-condition.label = Vorhergesagte Wetterlage +channel-type.openweathermap.forecasted-condition.description = Zeigt die vorhergesagte Wetterlage an. +channel-type.openweathermap.forecasted-gust-speed.label = Vorhergesagte Windböengeschwindigkeit +channel-type.openweathermap.forecasted-gust-speed.description = Zeigt die vorhergesagte Windböengeschwindigkeit an. +channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Maximale Temperatur +channel-type.openweathermap.forecasted-max-outdoor-temperature.description = Zeigt die vorhergesagte maximale Außentemperatur an. +channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Minimale Temperatur +channel-type.openweathermap.forecasted-min-outdoor-temperature.description = Zeigt die vorhergesagte minimale Außentemperatur an. +channel-type.openweathermap.forecasted-nitrogen-dioxide.label = Vorhergesagter Stickstoffdioxid +channel-type.openweathermap.forecasted-nitrogen-dioxide.description = Vorhergesagte Konzentration an Stickstoffdioxid. channel-type.openweathermap.forecasted-nitrogen-monoxide.label = Vorhergesagter Stickstoffmonoxid channel-type.openweathermap.forecasted-nitrogen-monoxide.description = Vorhergesagte Konzentration an Stickstoffmonoxid. - +channel-type.openweathermap.forecasted-outdoor-temperature.label = Vorhergesagte Temperatur +channel-type.openweathermap.forecasted-outdoor-temperature.description = Zeigt die vorhergesagte Außentemperatur an. +channel-type.openweathermap.forecasted-ozone.label = Vorhergesagter Ozon +channel-type.openweathermap.forecasted-ozone.description = Vorhergesagte Konzentration an Ozon. +channel-type.openweathermap.forecasted-particulate-matter-10.label = Vorhergesagter Feinstaub - PM10 +channel-type.openweathermap.forecasted-particulate-matter-10.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 10 µm. +channel-type.openweathermap.forecasted-particulate-matter-2dot5.label = Vorhergesagter Feinstaub - PM2.5 +channel-type.openweathermap.forecasted-particulate-matter-2dot5.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 2,5 µm. +channel-type.openweathermap.forecasted-rain.label = Vorhergesagter Regen +channel-type.openweathermap.forecasted-rain.description = Zeigt die vorhergesagte Regenmenge an. +channel-type.openweathermap.forecasted-snow.label = Vorhergesagter Schnee +channel-type.openweathermap.forecasted-snow.description = Zeigt die vorhergesagte Schneemenge an. +channel-type.openweathermap.forecasted-sulphur-dioxide.label = Vorhergesagter Schwefeldioxid +channel-type.openweathermap.forecasted-sulphur-dioxide.description = Vorhergesagte Konzentration an Schwefeldioxid. +channel-type.openweathermap.forecasted-uvindex.label = Vorhergesagter UV-Index +channel-type.openweathermap.forecasted-uvindex.description = Zeigt den vorhergesagten UV-Index an. +channel-type.openweathermap.forecasted-wind-direction.label = Vorhergesagte Windrichtung +channel-type.openweathermap.forecasted-wind-direction.description = Zeigt die vorhergesagte Windrichtung an. +channel-type.openweathermap.forecasted-wind-speed.label = Vorhergesagte Windgeschwindigkeit +channel-type.openweathermap.forecasted-wind-speed.description = Zeigt die vorhergesagte Windgeschwindigkeit an. +channel-type.openweathermap.gust-speed.label = Windböengeschwindigkeit +channel-type.openweathermap.gust-speed.description = Zeigt die aktuelle Windböengeschwindigkeit an. +channel-type.openweathermap.hourly-forecast-time-stamp.label = Vorhersage Zeit +channel-type.openweathermap.hourly-forecast-time-stamp.description = Zeigt den Zeitpunkt der Vorhersage an. +channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.morning-temperature.label = Temperatur am Morgen +channel-type.openweathermap.morning-temperature.description = Zeigt die vorhergesagte Temperatur am Morgen an. +channel-type.openweathermap.night-temperature.label = Temperatur in der Nacht +channel-type.openweathermap.night-temperature.description = Zeigt die vorhergesagte Temperatur in der Nacht an. channel-type.openweathermap.nitrogen-dioxide.label = Stickstoffdioxid channel-type.openweathermap.nitrogen-dioxide.description = Aktuelle Konzentration an Stickstoffdioxid. - -channel-type.openweathermap.forecasted-nitrogen-dioxide.label = Vorhergesagter Stickstoffdioxid -channel-type.openweathermap.forecasted-nitrogen-dioxide.description = Vorhergesagte Konzentration an Stickstoffdioxid. - +channel-type.openweathermap.nitrogen-monoxide.label = Stickstoffmonoxid +channel-type.openweathermap.nitrogen-monoxide.description = Aktuelle Konzentration an Stickstoffmonoxid. channel-type.openweathermap.ozone.label = Ozon channel-type.openweathermap.ozone.description = Aktuelle Konzentration an Ozon. - -channel-type.openweathermap.forecasted-ozone.label = Vorhergesagter Ozon -channel-type.openweathermap.forecasted-ozone.description = Vorhergesagte Konzentration an Ozon. - +channel-type.openweathermap.particulate-matter-10.label = Feinstaub - PM10 +channel-type.openweathermap.particulate-matter-10.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 10 µm. +channel-type.openweathermap.particulate-matter-2dot5.label = Feinstaub - PM2.5 +channel-type.openweathermap.particulate-matter-2dot5.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 2,5 µm. +channel-type.openweathermap.precip-probability.label = Vorhergesagte Niederschlagswahrscheinlichkeit +channel-type.openweathermap.precip-probability.description = Zeigt die vorhergesagte Niederschlagswahrscheinlichkeit an. +channel-type.openweathermap.precipitation.label = Niederschlag +channel-type.openweathermap.precipitation.description = Zeigt die kumulierte Niederschlagmenge an. +channel-type.openweathermap.rain.label = Regen +channel-type.openweathermap.rain.description = Zeigt den kumulierten Regen der letzten Stunde an. +channel-type.openweathermap.snow.label = Schnee +channel-type.openweathermap.snow.description = Zeigt den kumulierten Schnee der letzten Stunde an. +channel-type.openweathermap.station-id.label = Station-ID +channel-type.openweathermap.station-id.description = Zeigt die ID der Wetterstation oder des Ortes an. +channel-type.openweathermap.station-name.label = Name +channel-type.openweathermap.station-name.description = Zeigt den Namen der Wetterstation oder des Ortes an. channel-type.openweathermap.sulphur-dioxide.label = Schwefeldioxid channel-type.openweathermap.sulphur-dioxide.description = Aktuelle Konzentration an Schwefeldioxid. - -channel-type.openweathermap.forecasted-sulphur-dioxide.label = Vorhergesagter Schwefeldioxid -channel-type.openweathermap.forecasted-sulphur-dioxide.description = Vorhergesagte Konzentration an Schwefeldioxid. - -channel-type.openweathermap.ammonia.label = Ammoniak -channel-type.openweathermap.ammonia.description = Aktuelle Konzentration an Ammoniak. - -channel-type.openweathermap.forecasted-ammonia.label = Vorhergesagter Ammoniak -channel-type.openweathermap.forecasted-ammonia.description = Vorhergesagte Konzentration an Ammoniak. - -channel-type.openweathermap.alert-event.label = Art -channel-type.openweathermap.alert-event.description = Art der Warnung, z.B. FROST. - -channel-type.openweathermap.alert-description.label = Beschreibung -channel-type.openweathermap.alert-description.description = Zeigt die Beschreibung der Wetterwarnung an. - -channel-type.openweathermap.alert-onset.label = Gültig ab -channel-type.openweathermap.alert-onset.description = Datum und Uhrzeit, ab dem die Warnung gültig ist. -channel-type.openweathermap.alert-onset.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.alert-expires.label = Gültig bis -channel-type.openweathermap.alert-expires.description = Datum und Uhrzeit, bis zu dem die Warnung gültig ist. -channel-type.openweathermap.alert-expires.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.alert-source.label = Quelle -channel-type.openweathermap.alert-source.description = Zeigt die Quelle der Wetterwarnung an. +channel-type.openweathermap.sunrise.label = Sonnenaufgang +channel-type.openweathermap.sunrise.description = Zeigt den Zeitpunkt des Sonnenaufgangs an. +channel-type.openweathermap.sunrise.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.sunset.label = Sonnenuntergang +channel-type.openweathermap.sunset.description = Zeigt den Zeitpunkt des Sonnenuntergangs an. +channel-type.openweathermap.sunset.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.time-stamp.label = Letzte Messung +channel-type.openweathermap.time-stamp.description = Zeigt den Zeitpunkt der letzten Messung an. +channel-type.openweathermap.time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.uvindex.label = UV-Index +channel-type.openweathermap.uvindex.description = Zeigt den aktuellen UV-Index an. +channel-type.openweathermap.visibility.label = Sichtweite +channel-type.openweathermap.visibility.description = Zeigt die aktuelle Sichtweite an. # thing status + offline.conf-error-missing-apikey = Der Parameter 'API Schlüssel' muss konfiguriert werden. -offline.conf-error-invalid-apikey = Ungültiger 'API Schlüssel'. Mehr Infos unter https://openweathermap.org/faq#error401. -offline.conf-error-not-supported-refreshInterval = Der Parameter 'Abfrageintervall' muss mindestens 1 min betragen. +offline.conf-error-invalid-apikey = Ungültiger 'API Schlüssel'. Mehr Infos unter https\://openweathermap.org/faq\#error401. +offline.conf-error-not-supported-refreshInterval = Der Parameter 'refreshInterval' muss mindestens 1 min betragen. offline.conf-error-not-supported-language = Der angegebene Parameter 'Sprache' wird nicht unterstützt. - offline.conf-error-missing-location = Der Parameter 'Ort' muss konfiguriert werden. offline.conf-error-parsing-location = Der Parameter 'Ort' kann nicht in Latitude und Longitude getrennt werden. -offline.conf-error-not-supported-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite: 3. +offline.conf-error-not-supported-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite\: 3. offline.conf-error-not-supported-number-of-days = Der Parameter 'forecastDays' muss zwischen 0 und 16 liegen. offline.conf-error-not-supported-uvindex-number-of-days = Der Parameter 'forecastDays' muss zwischen 1 und 8 liegen. -offline.conf-error-not-supported-air-pollution-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite: 1. - +offline.conf-error-not-supported-air-pollution-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite\: 1. offline.conf-error-not-supported-onecall-number-of-minutes = Der Parameter 'forecastMinutes' muss zwischen 0 and 60 liegen. offline.conf-error-not-supported-onecall-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 48 liegen. offline.conf-error-not-supported-onecall-number-of-days = Der Parameter 'forecastDays' muss zwischen 0 und 7 liegen. offline.conf-error-not-supported-onecall-number-of-alerts = Der Parameter 'numberOfAlerts' muss größer oder gleich 0 sein. # discovery result + discovery.weather-and-forecast.local.label = Lokales Wetter und Wettervorhersage -discovery.air-pollution.local.label = Lokale Luftqualität +discovery.air-pollution.local.label = Lokale Luftverschmutzung +discovery.onecall.local.label = One Call API - Lokales Wetter und Wettervorhersage +discovery.onecall-history.local.label = One Call API - Lokale historische Wetterdaten diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties index 666f18cc4f400..84882632278fe 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet_it.properties @@ -7,7 +7,7 @@ binding.openwebnet.description = Il binding OpenWebNet integra i sistemi BTicino offline.conf-error-no-ip-address = Impossibile connettersi al gateway. Nessun host/IP specificato nella configurazione. offline.conf-error-no-serial-port = Impossibile connettersi al gateway. Nessuna porta seriale specificata nella configurazione. -offline.conf-error-where = Il parametro OpenWebNet Address (where) nella configurazione nullo o non valido. +offline.conf-error-where = Il parametro OpenWebNet Address (where) nella configurazione è nullo o non valido. offline.conf-error-no-bridge = Nessun bridge associato. Assegnare un bridge nella configurazione. offline.conf-error-auth = Autenticazione fallita. Verificare la password nella configurazione. diff --git a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_sv.properties b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_sv.properties index 2de21829b8773..c8b3d234234aa 100644 --- a/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_sv.properties +++ b/bundles/org.openhab.binding.playstation/src/main/resources/OH-INF/i18n/playstation_sv.properties @@ -21,7 +21,7 @@ thing-type.config.playstation.PS4.pairingCode.description = Kod för att para op thing-type.config.playstation.PS4.connectionTimeout.label = Uppkopplings timeout thing-type.config.playstation.PS4.connectionTimeout.description = Hur många sekunder efter det senaste kommandot som uppkopplingen stängs ner. Använd 0 för att aldrig stänga ner. thing-type.config.playstation.PS4.autoConnect.label = Auto uppkoppling -thing-type.config.playstation.PS4.autoConnect.description = Skall bindingen försöka koppla upp sig mot PS4:an så fort den sätts på. +thing-type.config.playstation.PS4.autoConnect.description = Skall bindingen försöka koppla upp sig mot PS4\:an så fort den sätts på. thing-type.config.playstation.PS4.artworkSize.label = Omslagsbild storlek thing-type.config.playstation.PS4.artworkSize.description = Bredden och höjden på nerladdad omslagsbild. thing-type.config.playstation.PS4.outboundIP.label = Utgående IP diff --git a/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf_fr.properties b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf_fr.properties new file mode 100644 index 0000000000000..203a8408329f2 --- /dev/null +++ b/bundles/org.openhab.binding.sncf/src/main/resources/OH-INF/i18n/sncf_fr.properties @@ -0,0 +1,36 @@ + +binding.sncf.name = Extension SNCF +binding.sncf.description = Cette extension fournit des informations sur les chemins de fer français. + +config.thing-type.sncf.api.apiID.label = ID API +config.thing-type.sncf.api.apiID.description = Votre ID d'API SNCF + +thing-type.sncf.api.label = API SNCF +thing-type.sncf.api.description = Ce pont de connexion est la passerelle vers l'API SNCF. + +thing-type.sncf.station.label = Gare +thing-type.sncf.station.description = Représente une gare hébergeant un mode de transport. +thing-type.sncf.station.group.arrivals.label = Prochaine arrivée +thing-type.sncf.station.group.arrivals.description = Informations sur la prochaine arrivée en gare. +thing-type.sncf.station.group.departures.label = Prochain départ +thing-type.sncf.station.group.departures.description = Informations sur le prochain départ de cette gare. + +thing-type.config.sncf.station.stopPointId.label = ID Arrêt +thing-type.config.sncf.station.stopPointId.description = L'identifiant de l'arrêt de la station tel que défini par DIGITALSNCF. + +channel-type.sncf.direction.label = Direction +channel-type.sncf.direction.description = La direction de ce transport. +channel-type.sncf.lineName.label = Ligne +channel-type.sncf.lineName.description = Nom de la ligne (réseau + numéro/lettre) +channel-type.sncf.name.label = Nom +channel-type.sncf.name.description = Nom de la ligne. +channel-type.sncf.network.label = Réseau +channel-type.sncf.network.description = Nom du réseau de transport. +channel-type.sncf.timestamp.label = Horaire +channel-type.sncf.timestamp.description = Horaire de l'événement à venir. + +# Error messages +null-or-empty-api-key = ID d'API vide ou nul +error-invalid-apikey = ID d'API incorrect +null-or-empty-station-id = ID de station vide ou nul +null-or-empty-timezone = Le fuseau horaire est vide. Il aurait dû être défini lors de la première initialisation. diff --git a/bundles/org.openhab.binding.synopanalyzer/src/main/resources/OH-INF/i18n/synopanalyzer_fr.properties b/bundles/org.openhab.binding.synopanalyzer/src/main/resources/OH-INF/i18n/synopanalyzer_fr.properties index 0c899f39a4a76..7598b270e3caa 100644 --- a/bundles/org.openhab.binding.synopanalyzer/src/main/resources/OH-INF/i18n/synopanalyzer_fr.properties +++ b/bundles/org.openhab.binding.synopanalyzer/src/main/resources/OH-INF/i18n/synopanalyzer_fr.properties @@ -1,7 +1,7 @@ # binding binding.synopanalyzer.name = Extension Synop Analyzer -binding.synopanalyzer.description = Synop Analyzer permet de télécharger et interpréter les messages SYNOP. +binding.synopanalyzer.description = Cette extension permet de télécharger et interpréter les messages SYNOP. # thing types diff --git a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties index 1762ec4887ff5..79e426aa6c45f 100644 --- a/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties +++ b/bundles/org.openhab.binding.twitter/src/main/resources/OH-INF/i18n/twitter_fr.properties @@ -1,7 +1,7 @@ # binding binding.twitter.name = Extension Twitter -binding.twitter.description = Permet d'obtenir le dernier Tweet ou d'envoyer des Tweets et des images depuis vos règles d'automatisation. +binding.twitter.description = Cette extension permet d'obtenir le dernier Tweet ou d'envoyer des Tweets et des images depuis vos règles d'automatisation. # thing types diff --git a/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/thingstate_fr.properties b/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/thingstate_fr.properties new file mode 100644 index 0000000000000..4be8acb611d6d --- /dev/null +++ b/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/thingstate_fr.properties @@ -0,0 +1,9 @@ +upb.thingstate.controller_offline=PIM déconnecté +upb.thingstate.controller_comm_error=Erreur de communication avec le module d'interface courant +upb.thingstate.node_dead=L'appareil ne communique pas avec le contrôleur +upb.thingstate.node_notfound=Nœud introuvable dans le réseau +upb.thingstate.serial_notfound=Erreur série \: le port {0} n''existe pas +upb.thingstate.serial_inuse=Erreur série \: le port {0} est en cours d''utilisation +upb.thingstate.serial_unsupported=Erreur série \: opération non prise en charge sur le port {0} +upb.thingstate.serial_listeners=Erreur série \: trop de listeners sur le port {0} +upb.thingstate.serial_cfg_port=Port série non configuré diff --git a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties index bd7ccdd807cf3..901bc21fc75dd 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties +++ b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties @@ -10,9 +10,9 @@ urtsiDeviceCommandIntervalLabel = Befehlausführungsintervall urtsiDeviceCommandIntervalDescription = Die Zeit (in ms), die das Binding zwischen dem Absenden von zwei Befehlen warten soll rtsDeviceLabel = Somfy RTS Gerät -rtsDeviceDescription = Dies ist ein Gerät, das über RTS kommuniziert (z.B. ein Rolladenmotor). +rtsDeviceDescription = Dies ist ein Gerät, das über RTS kommuniziert (z.B. ein Rolladenmotor). rtsDeviceChannelLabel = Kanal -rtsDeviceChannelDescription = Der Kanel, der dem RTS Gerät am URTSI II zugewiesen wurde +rtsDeviceChannelDescription = Der Kanel, der dem RTS Gerät am URTSI II zugewiesen wurde positionChannelLabel = Position des RTS Geräts positionChannelDescription = Ändern der Position des RTS Gerätes diff --git a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties index 9fbd0fd148892..e176872fc537f 100644 --- a/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties +++ b/bundles/org.openhab.binding.vigicrues/src/main/resources/OH-INF/i18n/vigicrues_fr.properties @@ -1,7 +1,7 @@ # binding binding.vigicrues.name = Extension VigiCrues -binding.vigicrues.description = Récupère les niveaux et alertes des cours d'eau en France +binding.vigicrues.description = Cette extension récupère les niveaux et alertes des cours d'eau en France. # thing types diff --git a/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties index 0d239fbb647f9..cf031636e626b 100644 --- a/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties +++ b/bundles/org.openhab.binding.xmltv/src/main/resources/OH-INF/i18n/xmltv_fr.properties @@ -1,7 +1,7 @@ # binding binding.xmltv.name = Extension XmlTV -binding.xmltv.description = Cette extension permet de lire et analyser les fichiers de programmes au format XmlTV +binding.xmltv.description = Cette extension permet de lire et analyser les fichiers de programmes au format XmlTV. # bridge types diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties index e492b56048a9b..d04ae6a521439 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_de.properties @@ -1,9 +1,3 @@ -# service - -service.io.openhabcloud.label = openHAB Cloud - -# bundle config - io.config.openhabcloud.baseURL.label = URL io.config.openhabcloud.baseURL.description = URL des openHAB Cloud-Servers. io.config.openhabcloud.expose.label = Veröffentlichte Items @@ -12,3 +6,7 @@ io.config.openhabcloud.mode.label = Funktionen io.config.openhabcloud.mode.description = Welche Funktionen des openHAB Cloud-Dienstes sollen verwendet werden. io.config.openhabcloud.mode.option.notification = Benachrichtigungen io.config.openhabcloud.mode.option.remote = Benachrichtigungen & Fernzugriff + +# service + +service.io.openhabcloud.label = openHAB Cloud diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties index dd708656a2642..d28a4dc62df5a 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_fr.properties @@ -1,9 +1,3 @@ -# service - -service.io.openhabcloud.label = Cloud openHAB - -# bundle config - io.config.openhabcloud.baseURL.label = URL de base io.config.openhabcloud.baseURL.description = URL de base pour le serveur Cloud openHAB. io.config.openhabcloud.expose.label = Éléments à exposer @@ -12,3 +6,7 @@ io.config.openhabcloud.mode.label = Mode io.config.openhabcloud.mode.description = Les fonctionnalités du service Cloud openHAB à utiliser. io.config.openhabcloud.mode.option.notification = Notifications io.config.openhabcloud.mode.option.remote = Notifications et accès à distance + +# service + +service.io.openhabcloud.label = Cloud openHAB diff --git a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties index 84388bfb80708..40eedd0277541 100644 --- a/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties +++ b/bundles/org.openhab.io.openhabcloud/src/main/resources/OH-INF/i18n/openhabcloud_hu.properties @@ -1,9 +1,3 @@ -# service - -service.io.openhabcloud.label = openHAB felhő - -# bundle config - io.config.openhabcloud.baseURL.label = Alap webcím io.config.openhabcloud.baseURL.description = Az openHAB felhő kiszolgáló alap címe. io.config.openhabcloud.expose.label = Elemek közzététele @@ -12,3 +6,7 @@ io.config.openhabcloud.mode.label = Mód io.config.openhabcloud.mode.description = Az openHAB felhő használandó szolgáltatásainak listája. io.config.openhabcloud.mode.option.notification = Értesítések io.config.openhabcloud.mode.option.remote = Értesítések és távoli hozzáférés + +# service + +service.io.openhabcloud.label = openHAB felhő diff --git a/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts_de.properties b/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts_de.properties index 987eef96aafc5..c8dadad738266 100644 --- a/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts_de.properties +++ b/bundles/org.openhab.voice.googletts/src/main/resources/OH-INF/i18n/googletts_de.properties @@ -1,9 +1,3 @@ -# service - -service.voice.googletts.label = Google Cloud Text-to-Speech - -# bundle config - voice.config.googletts.authcode.label = Autorisierungscode voice.config.googletts.authcode.description = Der Autorisierungscode ist ein einmaliger Code, der benötigt wird, um den notwendigen Authentifizierungscode von der Google Cloud Plattform abzurufen. Aufruf der URL ... https\://accounts.google.com/o/oauth2/auth?client_id\={{clientId}}&redirect_uri\=urn\:ietf\:wg\:oauth\:2.0\:oob&scope\=https\://www.googleapis.com/auth/cloud-platform&response_type\=code im Browser, um einen Autorisierungscode zu generieren und ihn hier einzufügen. voice.config.googletts.clientId.label = Client Id @@ -22,3 +16,7 @@ voice.config.googletts.speakingRate.label = Sprachgeschwindigkeit voice.config.googletts.speakingRate.description = Die Sprachgeschwindigkeit kann bis zu 4x schneller oder langsamer sein als die normale Geschwindigkeit. voice.config.googletts.volumeGain.label = Lautstärke Verstärkung voice.config.googletts.volumeGain.description = Die Lautstärke der Sprachausgabe kann um bis zu 16db erhöht oder um bis zu -96db verringert werden. + +# service + +service.voice.googletts.label = Google Cloud Text-to-Speech From 62fa5aa236976bf3789d99786ba1e16eed276679 Mon Sep 17 00:00:00 2001 From: Martin Herbst Date: Sat, 11 Dec 2021 18:34:22 +0100 Subject: [PATCH 211/361] [homematic] Improve (re)connect handling to Homematic gateways (#11429) * Use globally unique id for registration of callback to allow ... the connection of multiple OH installations with one CCU. The bridge id is not sufficient for this purpose because it is same in all OH installations. Signed-off-by: Martin Herbst * Retry callback re-registration after connection is resumed Some services on the CCU need longer to start and are not available immediately after the connection to the CCU has been resumed. Improves the solution for #8808 Fixes #10439 Signed-off-by: Martin Herbst * Description was missing. Signed-off-by: Martin Herbst * Changed setting name and description to avoid confusion Signed-off-by: Martin Herbst * Added a troubleshooting tip to solve a communication problem Signed-off-by: Martin Herbst * Shortened the label name to follow the guide lines Signed-off-by: Martin Herbst * Print more information about the reason for the failure Signed-off-by: Martin Herbst * Using scheduler thread pool and simplified configuration Instead of configuring separate values for retry delays and number of retries only the maximum time for retries can be configured. The init method uses fixed delays. Signed-off-by: Martin Herbst * Don't retry to send if gateway does not answer at all Signed-off-by: Martin Herbst * Improved reconnect handling - unregister callback not necessary if connection is lost - wait 30s until clients and servers are restarted to give the gateway some time to recover Signed-off-by: Martin Herbst * Spotless Signed-off-by: Martin Herbst * Cancel an active future if the binding is stopped Signed-off-by: Martin Herbst Signed-off-by: Michael Schmidt --- .../org.openhab.binding.homematic/README.md | 14 +++++ .../internal/HomematicBindingConstants.java | 1 + .../internal/common/HomematicConfig.java | 16 +++++ .../AbstractHomematicGateway.java | 54 ++++++++++++----- .../communicator/client/BinRpcClient.java | 5 +- .../communicator/client/RpcClient.java | 58 ++++++++++++++++--- .../communicator/client/XmlRpcClient.java | 11 ++-- .../main/resources/OH-INF/thing/bridge.xml | 6 ++ 8 files changed, 134 insertions(+), 31 deletions(-) diff --git a/bundles/org.openhab.binding.homematic/README.md b/bundles/org.openhab.binding.homematic/README.md index 1dd7842f7fc88..26ff2b8f85bf1 100644 --- a/bundles/org.openhab.binding.homematic/README.md +++ b/bundles/org.openhab.binding.homematic/README.md @@ -157,6 +157,13 @@ The port number of the HMIP server (default = 2010) - **cuxdPort** The port number of the CUxD daemon (default = 8701) +- **groupPort** +The port number of the Group daemon (default = 9292) + +- **callbackRegTimeout** +Maximum time in seconds for callback registration in the Homematic gateway (default = 120s). +For a CCU2, the value may need to be increased to 180s. + - **installModeDuration** Time in seconds that the controller will be in install mode when a device discovery is initiated (default = 60) @@ -676,6 +683,13 @@ Examples: HmIP-BROLL, HmIP-FROLL, HmIP-BBL, HmIP-FBL and HmIP-DRBLI4 | openHAB | 0% | 100% | | CCU | 100% | 0% | +** The binding does not receive any status changes from the Homematic gateway** + +First of all, make sure that none of the ports needed to receive status changes from the gateway are blocked by firewall settings. + +If the computer running openHAB has more than one IP address, a wrong one may have been set as receiver for status changes. +In this case change the setting for `callbackHost` to the correct address. + ### Debugging and Tracing If you want to see what's going on in the binding, switch the log level to DEBUG in the Karaf console diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/HomematicBindingConstants.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/HomematicBindingConstants.java index a17dd71cc18a5..10118362983f6 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/HomematicBindingConstants.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/HomematicBindingConstants.java @@ -24,6 +24,7 @@ public class HomematicBindingConstants { public static final String BINDING_ID = "homematic"; + public static final String GATEWAY_POOL_NAME = "homematicGateway"; public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge"); public static final String CONFIG_DESCRIPTION_URI_CHANNEL = "channel-type:homematic:config"; diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/common/HomematicConfig.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/common/HomematicConfig.java index 9936668541d13..4d20f99cdbae3 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/common/HomematicConfig.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/common/HomematicConfig.java @@ -58,6 +58,8 @@ public class HomematicConfig { private int bufferSize = 2048; private HmGatewayInfo gatewayInfo; + private int callbackRegistrationRetries; + private int callbackRegTimeout; /** * Returns the Homematic gateway address. @@ -115,6 +117,20 @@ public void setBinCallbackPort(int binCallbackPort) { this.binCallbackPort = binCallbackPort; } + /** + * Sets timeout for callback registration. + */ + public void setCallbackRegTimeout(int timeout) { + this.callbackRegTimeout = timeout; + } + + /** + * Returns timeout for callback registrations. + */ + public int getCallbackRegTimeout() { + return callbackRegTimeout; + } + /** * Returns the HmGatewayInfo. */ diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/AbstractHomematicGateway.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/AbstractHomematicGateway.java index d834ec1f89f76..aba9227ab1ba9 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/AbstractHomematicGateway.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/AbstractHomematicGateway.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.homematic.internal.communicator; +import static org.openhab.binding.homematic.internal.HomematicBindingConstants.*; import static org.openhab.binding.homematic.internal.misc.HomematicConstants.*; import java.io.IOException; @@ -87,8 +88,8 @@ public abstract class AbstractHomematicGateway implements RpcEventListener, HomematicGateway, VirtualGateway { private final Logger logger = LoggerFactory.getLogger(AbstractHomematicGateway.class); public static final double DEFAULT_DISABLE_DELAY = 2.0; + private static final long RESTART_DELAY = 30; private static final long CONNECTION_TRACKER_INTERVAL_SECONDS = 15; - private static final String GATEWAY_POOL_NAME = "homematicGateway"; private final Map> rpcClients = new HashMap<>(); private final Map rpcServers = new HashMap<>(); @@ -189,6 +190,7 @@ public void initialize() throws IOException { logger.debug("Used Homematic transfer modes: {}", sb.toString()); startClients(); startServers(); + registerCallbacks(); if (!config.getGatewayInfo().isHomegear()) { // delay the newDevice event handling at startup, reduces some API calls @@ -211,7 +213,7 @@ public void dispose() { stopWatchdogs(); sendDelayedExecutor.stop(); receiveDelayedExecutor.stop(); - stopServers(); + stopServers(true); stopClients(); devices.clear(); echoEvents.clear(); @@ -253,25 +255,29 @@ private synchronized void startServers() throws IOException { rpcServer.start(); } } + } + + private void registerCallbacks() throws IOException { for (HmInterface hmInterface : availableInterfaces.keySet()) { - getRpcClient(hmInterface).init(hmInterface, hmInterface.toString() + "-" + id); + getRpcClient(hmInterface).init(hmInterface); } } /** * Stops the Homematic RPC server. */ - private synchronized void stopServers() { - for (HmInterface hmInterface : availableInterfaces.keySet()) { - try { - getRpcClient(hmInterface).release(hmInterface); - } catch (IOException ex) { - // recoverable exception, therefore only debug - logger.debug("Unable to release the connection to the gateway with id '{}': {}", id, ex.getMessage(), - ex); + private synchronized void stopServers(boolean releaseConnection) { + if (releaseConnection) { + for (HmInterface hmInterface : availableInterfaces.keySet()) { + try { + getRpcClient(hmInterface).release(hmInterface); + } catch (IOException ex) { + // recoverable exception, therefore only debug + logger.debug("Unable to release the connection to the gateway with id '{}': {}", id, + ex.getMessage(), ex); + } } } - for (TransferMode mode : rpcServers.keySet()) { rpcServers.get(mode).shutdown(); } @@ -896,10 +902,14 @@ private int translateFlags(boolean reset, boolean force, boolean defer) { */ private class ConnectionTrackerThread implements Runnable { private boolean connectionLost; + private boolean reStartPending = false; @Override public void run() { try { + if (reStartPending) { + return; + } ListBidcosInterfacesParser parser = getRpcClient(getDefaultInterface()) .listBidcosInterfaces(getDefaultInterface()); Integer dutyCycleRatio = parser.getDutyCycleRatio(); @@ -920,6 +930,11 @@ private void connectionConfirmed() { if (connectionLost) { connectionLost = false; logger.info("Connection resumed on gateway '{}'", id); + try { + registerCallbacks(); + } catch (IOException e) { + logger.warn("Connection only partially restored. It is recommended to restart the binding"); + } gatewayAdapter.onConnectionResumed(); } } @@ -930,10 +945,19 @@ private void handleInvalidConnection(String cause) throws IOException { logger.warn("Connection lost on gateway '{}', cause: \"{}\"", id, cause); gatewayAdapter.onConnectionLost(); } - stopServers(); + stopServers(false); stopClients(); - startClients(); - startServers(); + reStartPending = true; + logger.debug("Waiting {}s until restart attempt", RESTART_DELAY); + scheduler.schedule(() -> { + try { + startClients(); + startServers(); + } catch (IOException e) { + logger.debug("Restart failed: {}", e.getMessage()); + } + reStartPending = false; + }, RESTART_DELAY, TimeUnit.SECONDS); } } } diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/BinRpcClient.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/BinRpcClient.java index b814b91d897f7..f3c01c3fca67c 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/BinRpcClient.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/BinRpcClient.java @@ -40,6 +40,7 @@ public BinRpcClient(HomematicConfig config) { @Override public void dispose() { + super.dispose(); socketHandler.flush(); } @@ -54,8 +55,8 @@ protected String getRpcCallbackUrl() { } @Override - public void init(HmInterface hmInterface, String clientId) throws IOException { - super.init(hmInterface, clientId); + public void init(HmInterface hmInterface) throws IOException { + super.init(hmInterface); socketHandler.removeSocket(config.getRpcPort(hmInterface)); } diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java index 4f2fab2c823c9..e0e05109da678 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/RpcClient.java @@ -19,6 +19,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.openhab.binding.homematic.internal.HomematicBindingConstants; import org.openhab.binding.homematic.internal.common.HomematicConfig; @@ -41,6 +48,7 @@ import org.openhab.binding.homematic.internal.model.HmInterface; import org.openhab.binding.homematic.internal.model.HmParamsetType; import org.openhab.binding.homematic.internal.model.HmRssiInfo; +import org.openhab.core.common.ThreadPoolManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,18 +61,18 @@ public abstract class RpcClient { private final Logger logger = LoggerFactory.getLogger(RpcClient.class); protected static final int MAX_RPC_RETRY = 3; protected static final int RESP_BUFFER_SIZE = 8192; + private static final int INITIAL_CALLBACK_REG_DELAY = 20; // 20 s before first attempt + private static final int CALLBACK_REG_DELAY = 10; // 10 s between two attempts protected HomematicConfig config; + private String thisUID = UUID.randomUUID().toString(); + private ScheduledFuture future = null; + private int attempt; public RpcClient(HomematicConfig config) { this.config = config; } - /** - * Disposes the client. - */ - public abstract void dispose(); - /** * Returns a RpcRequest for this client. */ @@ -83,14 +91,48 @@ public RpcClient(HomematicConfig config) { /** * Register a callback for the specified interface where the Homematic gateway can send its events. */ - public void init(HmInterface hmInterface, String clientId) throws IOException { + public void init(HmInterface hmInterface) throws IOException { + ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(GATEWAY_POOL_NAME); RpcRequest request = createRpcRequest("init"); request.addArg(getRpcCallbackUrl()); - request.addArg(clientId); + request.addArg(thisUID); if (config.getGatewayInfo().isHomegear()) { request.addArg(Integer.valueOf(0x22)); } - sendMessage(config.getRpcPort(hmInterface), request); + logger.debug("Register callback for interface {}", hmInterface.getName()); + try { + attempt = 1; + sendMessage(config.getRpcPort(hmInterface), request); // first attempt without delay + } catch (IOException e) { + future = scheduler.scheduleWithFixedDelay(() -> { + logger.debug("Register callback for interface {}, attempt {}", hmInterface.getName(), ++attempt); + try { + sendMessage(config.getRpcPort(hmInterface), request); + future.cancel(true); + } catch (IOException ex) { + // Ignore, retry + } + }, INITIAL_CALLBACK_REG_DELAY, CALLBACK_REG_DELAY, TimeUnit.SECONDS); + try { + future.get(config.getCallbackRegTimeout(), TimeUnit.SECONDS); + } catch (CancellationException e1) { + logger.debug("Callback for interface {} successfully registered", hmInterface.getName()); + } catch (InterruptedException | ExecutionException e1) { + throw new IOException("Callback reg. thread interrupted", e1); + } catch (TimeoutException e1) { + logger.error("Callback registration for interface {} timed out", hmInterface.getName()); + throw new IOException("Unable to reconnect in time"); + } + future = null; + } + } + + /** + * Disposes the client. + */ + public void dispose() { + if (future != null) + future.cancel(true); } /** diff --git a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java index 3d82937eb450a..42e94154005cc 100644 --- a/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java +++ b/bundles/org.openhab.binding.homematic/src/main/java/org/openhab/binding/homematic/internal/communicator/client/XmlRpcClient.java @@ -49,10 +49,6 @@ public XmlRpcClient(HomematicConfig config, HttpClient httpClient) throws IOExce this.httpClient = httpClient; } - @Override - public void dispose() { - } - @Override public RpcRequest createRpcRequest(String methodName) { return new XmlRpcRequest(methodName); @@ -87,10 +83,13 @@ protected synchronized Object[] sendMessage(int port, RpcRequest request throw new IOException(ex); } catch (IOException ex) { reason = ex; - if ("init".equals(request.getMethodName())) { // no retries for "init" request + // no retries for "init" request or if connection is refused + if ("init".equals(request.getMethodName()) + || ex.getCause() != null && ex.getCause() instanceof ExecutionException) { break; } - logger.debug("XmlRpcMessage failed, sending message again {}/{}", rpcRetryCounter, MAX_RPC_RETRY); + logger.debug("XmlRpcMessage failed({}), sending message again {}/{}", ex.getMessage(), rpcRetryCounter, + MAX_RPC_RETRY); } } throw reason; diff --git a/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/thing/bridge.xml b/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/thing/bridge.xml index 468b5aa670428..343098ea1d90e 100644 --- a/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/thing/bridge.xml +++ b/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/thing/bridge.xml @@ -95,6 +95,12 @@ true 9292 + + + Maximum time in seconds for callback registration in the Homematic gateway. + true + 120 + Time in seconds that the controller will be in install mode when a device discovery is initiated From 87fda909ec5a2001e09abc3b01a36cabecdc685e Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Sat, 11 Dec 2021 19:39:40 +0100 Subject: [PATCH 212/361] Add virtual flag handling. (#11751) Signed-off-by: Mark Herwege Signed-off-by: Michael Schmidt --- .../internal/protocol/NikoHomeControlConstants.java | 3 +++ .../internal/protocol/nhc2/NhcAction2.java | 11 ++++++++++- .../protocol/nhc2/NikoHomeControlCommunication2.java | 7 ++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java index 55f2ca6699267..f748ce3229e95 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java @@ -35,6 +35,9 @@ public static enum ActionType { public static final String NHCON = "On"; public static final String NHCOFF = "Off"; + public static final String NHCTRUE = "True"; + public static final String NHCFALSE = "False"; + public static final String NHCTRIGGERED = "Triggered"; // rollershutter constants in the Nhc layer diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java index 1155ac5b6f843..cc65d27307815 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.nikohomecontrol.internal.protocol.nhc2; +import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.*; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.nikohomecontrol.internal.protocol.NhcAction; @@ -117,7 +119,14 @@ public void setState(int state) { public void execute(String command) { logger.debug("execute action {} of type {} for {}", command, type, id); - nhcComm.executeAction(id, command); + String cmd; + if ("flag".equals(model)) { + cmd = NHCON.equals(command) ? NHCTRUE : NHCFALSE; + } else { + cmd = command; + } + + nhcComm.executeAction(id, cmd); } /** diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java index 61d407f29ba0e..8cd4e82e72ce1 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java @@ -362,7 +362,7 @@ private void addDevice(NhcDevice2 device) { .orElse(null); } - if ("action".equals(device.type)) { + if ("action".equals(device.type) || "virtual".equals(device.type)) { if (!actions.containsKey(device.uuid)) { logger.debug("adding action device {}, {}", device.uuid, device.name); @@ -382,6 +382,7 @@ private void addDevice(NhcDevice2 device) { case "socket": case "switched-generic": case "switched-fan": + case "flag": actionType = ActionType.RELAY; break; case "dimmer": @@ -480,7 +481,7 @@ private void updateLightState(NhcAction2 action, List devicePropert booleanState = basicStateProperty.get().basicState; } - if (NHCOFF.equals(booleanState)) { + if (NHCOFF.equals(booleanState) || NHCFALSE.equals(booleanState)) { action.setBooleanState(false); logger.debug("setting action {} internally to OFF", action.getId()); } @@ -497,7 +498,7 @@ private void updateLightState(NhcAction2 action, List devicePropert } } - if (NHCON.equals(booleanState)) { + if (NHCON.equals(booleanState) || NHCTRUE.equals(booleanState)) { action.setBooleanState(true); logger.debug("setting action {} internally to ON", action.getId()); } From a61361835cf34909e6f22e019feb71f41674c580 Mon Sep 17 00:00:00 2001 From: Matthias Herrmann Date: Sat, 11 Dec 2021 23:06:47 +0100 Subject: [PATCH 213/361] Extend .gitignore (#11372) Signed-off-by: Matthias Herrmann Signed-off-by: Michael Schmidt --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 85fdc9acd73e3..65c16962936a7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ features/**/src/main/feature .factorypath pom.xml.versionsBackup .openapi-generator + +.metals +.vim +shell.nix +tags From 4a36985a17073904c45c3f6362eab1ae4a56e647 Mon Sep 17 00:00:00 2001 From: Matthew Skinner Date: Sun, 12 Dec 2021 19:08:53 +1100 Subject: [PATCH 214/361] [ipcamera] Add new channel lastEventData for detailed extra data on alarms (#11748) * Add new channel * Last Event Data channel finished. * Remove info logging. * Fix bugs * Fix ONVIF wont use different ports in xaddr paths. Signed-off-by: Matthew Skinner Signed-off-by: Michael Schmidt --- .../org.openhab.binding.ipcamera/README.md | 1 + .../ipcamera/internal/DahuaHandler.java | 10 +++++ .../binding/ipcamera/internal/Ffmpeg.java | 2 +- .../binding/ipcamera/internal/Helper.java | 6 +++ .../ipcamera/internal/HikvisionHandler.java | 7 ++- .../internal/IpCameraBindingConstants.java | 1 + .../internal/handler/IpCameraHandler.java | 2 +- .../internal/onvif/OnvifConnection.java | 43 +++++++++++-------- .../resources/OH-INF/thing/thing-types.xml | 9 ++++ 9 files changed, 60 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.binding.ipcamera/README.md b/bundles/org.openhab.binding.ipcamera/README.md index ac7b6862eded4..037163166d4fe 100644 --- a/bundles/org.openhab.binding.ipcamera/README.md +++ b/bundles/org.openhab.binding.ipcamera/README.md @@ -238,6 +238,7 @@ The channels are kept consistent as much as possible from brand to brand to make | `itemLeft` | Switch (read only) | Will turn ON if an API camera detects an item has been left behind. | | `itemTaken` | Switch (read only) | Will turn ON if an API camera detects an item has been stolen. | | `lastMotionType` | String | Cameras with multiple alarm types will update this with which alarm last detected motion, i.e. a lineCrossing, faceDetection or item stolen alarm. You can also use this to create a timestamp of when the last motion was detected by creating a rule when this channel changes. | +| `lastEventData` | String | Detailed information about the last smart alarm that can contain information like which Line number was crossed and in which direction. The channel `lastMotionType` will hold the name of the alarm that this data belongs to. | | `lineCrossingAlarm` | Switch (read only) | Will turn on if the API camera detects motion has crossed a line. | | `mjpegUrl` | String | The URL for the ipcamera.mjpeg stream. | | `motionAlarm` | Switch (read only) | The status of the 'video motion' events in ONVIF and API cameras. Also see `cellMotionAlarm` as these can give different results. | diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/DahuaHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/DahuaHandler.java index 816233f2619a2..85489ab66a097 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/DahuaHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/DahuaHandler.java @@ -22,6 +22,7 @@ import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; +import org.openhab.core.library.types.StringType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; @@ -63,6 +64,14 @@ private void processEvent(String content) { return; } String action = content.substring(startIndex, endIndex); + startIndex = content.indexOf(";data=", startIndex); + if (startIndex > 0) { + endIndex = content.lastIndexOf("}"); + if (endIndex > 0) { + String data = content.substring(startIndex + 6, endIndex + 1); + ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(data)); + } + } switch (code) { case "VideoMotion": if ("Start".equals(action)) { @@ -106,6 +115,7 @@ private void processEvent(String content) { ipCameraHandler.noMotionDetected(CHANNEL_LINE_CROSSING_ALARM); } break; + case "AudioAnomaly": case "AudioMutation": if ("Start".equals(action)) { ipCameraHandler.audioDetected(); diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Ffmpeg.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Ffmpeg.java index b940e76e8b4d7..36fdb5a094630 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Ffmpeg.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Ffmpeg.java @@ -171,7 +171,7 @@ public void run() { } } } catch (IOException e) { - logger.warn("An error occured trying to process the messages from FFmpeg."); + logger.warn("An IO error occured trying to start FFmpeg:{}", e.getMessage()); } finally { switch (format) { case GIF: diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java index 48cbab5ceeeb9..a66ee4d32a38c 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/Helper.java @@ -96,6 +96,12 @@ public static String fetchXML(String message, String sectionHeading, String key) if (sectionHeaderBeginning > 0) { result = result.substring(0, sectionHeaderBeginning); } + if (!key.endsWith(">")) { + startIndex = result.indexOf(">"); + if (startIndex != -1) { + return result.substring(startIndex + 1); + } + } return result; } diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java index 51ae91b6e16fa..7436fe31bd6f9 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/HikvisionHandler.java @@ -65,6 +65,7 @@ private void processEvent(String content) { if (content.contains("hannelID>" + nvrChannel) || content.contains("0")) { final int debounce = 3; String eventType = Helper.fetchXML(content, "", ""); + ipCameraHandler.setChannelState(CHANNEL_LAST_EVENT_DATA, new StringType(content)); switch (eventType) { case "videoloss": if (content.contains("inactive")) { @@ -120,7 +121,11 @@ public void channelRead(@Nullable ChannelHandlerContext ctx, @Nullable Object ms String content = msg.toString(); logger.trace("HTTP Result back from camera is \t:{}:", content); if (content.startsWith("--boundary")) {// Alarm checking goes in here// - processEvent(content); + int startIndex = content.indexOf("<");// skip to start of XML content + if (startIndex != -1) { + String eventData = content.substring(startIndex, content.length()); + processEvent(eventData); + } } else { String replyElement = Helper.fetchXML(content, "", "<"); switch (replyElement) { diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java index 49ed7f536f896..5fb04b07f9b0c 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/IpCameraBindingConstants.java @@ -132,6 +132,7 @@ public static enum FFmpegFormat { public static final String CHANNEL_EXTERNAL_LIGHT = "externalLight"; public static final String CHANNEL_DOORBELL = "doorBell"; public static final String CHANNEL_LAST_MOTION_TYPE = "lastMotionType"; + public static final String CHANNEL_LAST_EVENT_DATA = "lastEventData"; public static final String CHANNEL_GOTO_PRESET = "gotoPreset"; public static final String CHANNEL_START_STREAM = "startStream"; public static final String CHANNEL_ENABLE_PRIVACY_MODE = "enablePrivacyMode"; diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java index d0e90dd75906d..3fc0960b6a3a3 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/handler/IpCameraHandler.java @@ -1366,7 +1366,7 @@ void pollingCameraConnection() { snapshotIsFfmpeg(); } else { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Camera failed to report a valid Snaphot and/or RTSP URL. See readme on how to use the SNAPSHOT_URL_OVERRIDE feature."); + "Camera failed to report a valid Snaphot and/or RTSP URL. Check user/pass is correct, or use the advanced configs to manually provide a URL."); } } diff --git a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java index 95a0e109f2198..f5c2b1f4db12a 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java +++ b/bundles/org.openhab.binding.ipcamera/src/main/java/org/openhab/binding/ipcamera/internal/onvif/OnvifConnection.java @@ -119,13 +119,13 @@ public static enum RequestType { private String user = ""; private String password = ""; private int onvifPort = 80; - private String deviceXAddr = "/onvif/device_service"; - private String eventXAddr = "/onvif/device_service"; - private String mediaXAddr = "/onvif/device_service"; + private String deviceXAddr = "http://" + ipAddress + "/onvif/device_service"; + private String eventXAddr = "http://" + ipAddress + "/onvif/device_service"; + private String mediaXAddr = "http://" + ipAddress + "/onvif/device_service"; @SuppressWarnings("unused") - private String imagingXAddr = "/onvif/device_service"; - private String ptzXAddr = "/onvif/ptz_service"; - private String subscriptionXAddr = "/onvif/device_service"; + private String imagingXAddr = "http://" + ipAddress + "/onvif/device_service"; + private String ptzXAddr = "http://" + ipAddress + "/onvif/ptz_service"; + private String subscriptionXAddr = "http://" + ipAddress + "/onvif/device_service"; private boolean isConnected = false; private int mediaProfileIndex = 0; private String snapshotUri = ""; @@ -334,7 +334,7 @@ public void processReply(String message) { } else if (message.contains("GetEventPropertiesResponse")) { sendOnvifRequest(requestBuilder(RequestType.CreatePullPointSubscription, eventXAddr)); } else if (message.contains("CreatePullPointSubscriptionResponse")) { - subscriptionXAddr = removeIPfromUrl(Helper.fetchXML(message, "SubscriptionReference>", "Address>")); + subscriptionXAddr = Helper.fetchXML(message, "SubscriptionReference>", "Address>"); logger.debug("subscriptionXAddr={}", subscriptionXAddr); sendOnvifRequest(requestBuilder(RequestType.PullMessages, subscriptionXAddr)); } else if (message.contains("GetStatusResponse")) { @@ -376,7 +376,7 @@ HttpRequest requestBuilder(RequestType requestType, String xAddr) { String getXmlCache = getXml(requestType); if (requestType.equals(RequestType.CreatePullPointSubscription) || requestType.equals(RequestType.PullMessages) || requestType.equals(RequestType.Renew) || requestType.equals(RequestType.Unsubscribe)) { - headerTo = "http://" + ipAddress + xAddr + ""; + headerTo = "" + xAddr + ""; extraEnvelope = " xmlns:a=\"http://www.w3.org/2005/08/addressing\""; } String headers; @@ -396,16 +396,13 @@ HttpRequest requestBuilder(RequestType requestType, String xAddr) { } else {// GetSystemDateAndTime must not be password protected as per spec. headers = ""; } - FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, new HttpMethod("POST"), xAddr); + FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, new HttpMethod("POST"), + removeIPfromUrl(xAddr)); String actionString = Helper.fetchXML(getXmlCache, requestType.toString(), "xmlns=\""); request.headers().add("Content-Type", "application/soap+xml; charset=utf-8; action=\"" + actionString + "/" + requestType + "\""); request.headers().add("Charset", "utf-8"); - if (onvifPort != 80) { - request.headers().set("Host", ipAddress + ":" + onvifPort); - } else { - request.headers().set("Host", ipAddress); - } + request.headers().set("Host", extractIPportFromUrl(xAddr)); request.headers().set("Connection", HttpHeaderValues.CLOSE); request.headers().set("Accept-Encoding", "gzip, deflate"); String fullXml = "" @@ -437,25 +434,35 @@ String removeIPfromUrl(String url) { return url.substring(index); } + String extractIPportFromUrl(String url) { + int startIndex = url.indexOf("//") + 2; + int endIndex = url.indexOf("/", startIndex);// skip past any :port to the slash / + if (startIndex != -1 && endIndex != -1) { + return url.substring(startIndex, endIndex); + } + logger.debug("We hit an issue extracting IP:PORT from url:{}", url); + return ""; + } + void parseXAddr(String message) { // Normally I would search '' instead but Foscam needed this work around. - String temp = removeIPfromUrl(Helper.fetchXML(message, ":{}", message); diff --git a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml index c5b4dd7f40be3..d643a30a7ccba 100644 --- a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/thing/thing-types.xml @@ -880,6 +880,7 @@ + @@ -1710,6 +1711,7 @@ + @@ -2367,6 +2369,13 @@ + + String + + A string that contains detailed data on the last alarm that was triggered. + + + Switch From 9492ea493db1cfe2252305e015cefad5611d2d79 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sun, 12 Dec 2021 12:02:14 +0100 Subject: [PATCH 215/361] [urtsi] Fixed leading spaces in translations (#11757) * Fixed leading spaces in translations * Add @text in binding.xml * Added @text in urtsi.properties Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../main/resources/OH-INF/binding/binding.xml | 2 +- .../main/resources/OH-INF/i18n/urtsi.properties | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/binding/binding.xml index 15ca7f87fe40c..1c70499dc1286 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/binding/binding.xml +++ b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/binding/binding.xml @@ -3,7 +3,7 @@ xmlns:binding="https://openhab.org/schemas/binding/v1.0.0" xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd"> - Somfy URTSI II Binding + @text/bindingLabel @text/bindingDescription diff --git a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties index 16168b0a3118b..50fe6c51ce8ee 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties +++ b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi.properties @@ -1,18 +1,19 @@ # binding + bindingDescription = This is the binding for Somfy Universal RTS Interface II (URTSI II). +bindingLabel = Somfy URTSI II Binding # thing types + +positionChannelLabel = RTS Device position +positionChannelDescription = Change the position of your device +rtsDeviceLabel = Somfy RTS Device +rtsDeviceDescription = This is the RTS device (e.g. a rollershutter). +rtsDeviceChannelLabel = Channel +rtsDeviceChannelDescription = The URTSI II channel the RTS device is assigned to at URTSI II. urtsiDeviceLabel = Somfy URTSI II Device urtsiDeviceDescription = This is the Somfy URTSI II box. urtsiDevicePortLabel = Port urtsiDevicePortDescription = The port which is used to access the device (e.g. /dev/ttyUSB0) urtsiDeviceCommandIntervalLabel = Command execution interval urtsiDeviceCommandIntervalDescription = The time (in ms) the binding should wait between sending commands to the device - -rtsDeviceLabel = Somfy RTS Device -rtsDeviceDescription = This is the RTS device (e.g. a rollershutter). -rtsDeviceChannelLabel = Channel -rtsDeviceChannelDescription = The URTSI II channel the RTS device is assigned to at URTSI II. - -positionChannelLabel = RTS Device position -positionChannelDescription = Change the position of your device From c207173d13fc0ef0536990bcaff9308ef86fc02f Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Sun, 12 Dec 2021 12:55:09 +0100 Subject: [PATCH 216/361] [knx] Upgrade Calimero library to release 2.5. (#11759) - Upstream update of base library for KNX access from v2.4 to v2.5. - Adapt AbstractKNXClient to new interface and replace calls of deprecated methods. Fixes #6849. Signed-off-by: Holger Friedrich Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.knx/pom.xml | 6 +++--- .../knx/internal/client/AbstractKNXClient.java | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.binding.knx/pom.xml b/bundles/org.openhab.binding.knx/pom.xml index 0fd8b473bb5fd..f7faff1148a82 100644 --- a/bundles/org.openhab.binding.knx/pom.xml +++ b/bundles/org.openhab.binding.knx/pom.xml @@ -22,7 +22,7 @@ com.github.calimero calimero-core - 2.4 + 2.5 compile @@ -34,7 +34,7 @@ com.github.calimero calimero-device - 2.4 + 2.5 compile @@ -46,7 +46,7 @@ com.github.calimero calimero-rxtx - 2.4 + 2.5 compile 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 de860c6bed274..a791cea90b0f5 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 @@ -12,6 +12,7 @@ */ package org.openhab.binding.knx.internal.client; +import java.time.Duration; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.LinkedBlockingQueue; @@ -48,7 +49,7 @@ import tuwien.auto.calimero.mgmt.ManagementClientImpl; import tuwien.auto.calimero.mgmt.ManagementProcedures; import tuwien.auto.calimero.mgmt.ManagementProceduresImpl; -import tuwien.auto.calimero.process.ProcessCommunicationBase; +import tuwien.auto.calimero.process.ProcessCommunication; import tuwien.auto.calimero.process.ProcessCommunicator; import tuwien.auto.calimero.process.ProcessCommunicatorImpl; import tuwien.auto.calimero.process.ProcessEvent; @@ -181,17 +182,17 @@ private synchronized boolean connect() { managementProcedures = new ManagementProceduresImpl(link); ManagementClient managementClient = new ManagementClientImpl(link); - managementClient.setResponseTimeout(responseTimeout); + managementClient.responseTimeout(Duration.ofSeconds(responseTimeout)); this.managementClient = managementClient; deviceInfoClient = new DeviceInfoClientImpl(managementClient); ProcessCommunicator processCommunicator = new ProcessCommunicatorImpl(link); - processCommunicator.setResponseTimeout(responseTimeout); + processCommunicator.responseTimeout(Duration.ofSeconds(responseTimeout)); processCommunicator.addProcessListener(processListener); this.processCommunicator = processCommunicator; - ProcessCommunicationResponder responseCommunicator = new ProcessCommunicationResponder(link); + ProcessCommunicationResponder responseCommunicator = new ProcessCommunicationResponder(link, null); this.responseCommunicator = responseCommunicator; link.addLinkListener(this); @@ -439,7 +440,7 @@ public void respondToKNX(OutboundSpec responseSpec) throws KNXException { } } - private void sendToKNX(ProcessCommunicationBase communicator, KNXNetworkLink link, GroupAddress groupAddress, + private void sendToKNX(ProcessCommunication communicator, KNXNetworkLink link, GroupAddress groupAddress, String dpt, Type type) throws KNXException { if (!connectIfNotAutomatic()) { return; From ff015295fe8e4e77f03c7b7e42cb0de93587a7ec Mon Sep 17 00:00:00 2001 From: M Valla <12682715+mvalla@users.noreply.github.com> Date: Sun, 12 Dec 2021 13:21:52 +0100 Subject: [PATCH 217/361] [openwebnet] reduced log messages during UPnP bridge discovery (#11705) Signed-off-by: Massimo Valla Signed-off-by: Michael Schmidt --- .../internal/discovery/BusGatewayUpnpDiscovery.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/BusGatewayUpnpDiscovery.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/BusGatewayUpnpDiscovery.java index 2190cc9cb25ab..b2b4f29dc0d54 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/BusGatewayUpnpDiscovery.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/BusGatewayUpnpDiscovery.java @@ -150,10 +150,10 @@ public Set getSupportedThingTypeUIDs() { @Override public @Nullable DiscoveryResult createResult(RemoteDevice device) { - logger.info("Found device {}", device.getType()); + logger.debug("Found device {}", device.getType()); DeviceInfo devInfo = new DeviceInfo(device); if (!devInfo.manufacturer.matches("")) { - logger.info(" |- {} ({})", devInfo.modelName, devInfo.manufacturer); + logger.debug(" |- {} ({})", devInfo.modelName, devInfo.manufacturer); } ThingUID thingId = generateThingUID(devInfo); if (thingId != null) { @@ -226,7 +226,7 @@ public Set getSupportedThingTypeUIDs() { } } } - logger.info("Found BTicino device: not a OpenWebNet gateway or is not supported (UDN={})", idString); + logger.info("Found BTicino device: not a OpenWebNet gateway or not supported (UDN={})", idString); } return null; } From 431f0d041312c23e985eb93589b4d9b41ce7528e Mon Sep 17 00:00:00 2001 From: M Valla <12682715+mvalla@users.noreply.github.com> Date: Sun, 12 Dec 2021 13:58:27 +0100 Subject: [PATCH 218/361] [openwebnet] Add support for Dry Contact and IR interfaces for WHO=25 (#11747) * [openwebnet] updated where parameter labels Signed-off-by: Massimo Valla * [openwebnet] added support for DryContact/IR interfaces Signed-off-by: Massimo Valla * [openwebnet] updated README Signed-off-by: Massimo Valla * [openwebnet] checkstyle Signed-off-by: Massimo Valla Signed-off-by: Michael Schmidt --- .../org.openhab.binding.openwebnet/README.md | 18 ++-- .../internal/OpenWebNetBindingConstants.java | 7 +- .../OpenWebNetDeviceDiscoveryService.java | 6 ++ .../handler/OpenWebNetScenarioHandler.java | 94 ++++++++++++++++--- .../thing/BusCENPlusScenarioControl.xml | 2 +- .../OH-INF/thing/BusCENScenarioControl.xml | 2 +- .../OH-INF/thing/BusDryContactIR.xml | 38 ++++++++ .../resources/OH-INF/thing/GenericDevice.xml | 2 +- .../main/resources/OH-INF/thing/channels.xml | 8 ++ .../internal/handler/OwnIdTest.java | 12 ++- 10 files changed, 161 insertions(+), 28 deletions(-) create mode 100644 bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDryContactIR.xml diff --git a/bundles/org.openhab.binding.openwebnet/README.md b/bundles/org.openhab.binding.openwebnet/README.md index 89e1b8665e350..734e86658adde 100644 --- a/bundles/org.openhab.binding.openwebnet/README.md +++ b/bundles/org.openhab.binding.openwebnet/README.md @@ -45,6 +45,7 @@ The following Things and OpenWebNet `WHOs` are supported: | Automation | `2` | `bus_automation` | BUS roller shutters, with position feedback and auto-calibration | Successfully tested: LN4672M2 | | Temperature Control | `4` | `bus_thermo_zone`, `bus_thermo_sensor` | Thermo zones management and temperature sensors (probes). NOTE Central Units (4 or 99 zones) are not fully supported yet. See [Channels - Thermo](#configuring-thermo) for more details. | Successfully tested: H/LN4691, HS4692, KG4691; thermo sensors: L/N/NT4577 + 3455 | | CEN & CEN+ Scenarios | `15` & `25` | `bus_cen_scenario_control`, `bus_cenplus_scenario_control` | CEN/CEN+ scenarios events and virtual activation | Successfully tested: scenario buttons: HC/HD/HS/L/N/NT4680 | +| Dry Contact and IR Interfaces | `25` | `bus_dry_contact_ir` | Dry Contacts and IR Interfaces | Successfully tested: contact interfaces F428 and 3477; IR sensors: HC/HD/HS/L/N/NT4610 | | Energy Management | `18` | `bus_energy_meter` | Energy Management | Successfully tested: F520, F521 | ### For ZigBee (Radio) @@ -123,12 +124,13 @@ Devices can be discovered automatically using an Inbox Scan after a gateway has For any manually added device, you must configure: - the associated gateway (`Parent Bridge` menu) -- the `where` config parameter (`OpenWebNet Device Address`): +- the `where` configuration parameter (`OpenWebNet Address`): - example for BUS/SCS: - light device with WHERE address Point to Point `A=2 PL=4` --> `where="24"` - light device with WHERE address Point to Point `A=03 PL=11` on local bus --> `where="0311#4#01"` - CEN scenario with WHERE address Point to Point `A=05 PL=12` --> `where="0512"` - CEN+ configured scenario `5`: add a `2` before --> `where="25"` + - Dry Contact or IR Interface `99`: add a `3` before --> `where="399"` - example for ZigBee devices: `where=765432101#9`. The ID of the device (ADDR part) is usually written in hexadecimal on the device itself, for example `ID 0074CBB1`: convert to decimal (`7654321`) and add `01#9` at the end to obtain `where=765432101#9`. For 2-unit switch devices (`zb_on_off_switch2u`), last part should be `00#9`. @@ -138,13 +140,13 @@ In BTicino MyHOME Thermoregulation (WHO=4) each **zone** has associated a thermo Thermo zones can be configured defining a `bus_thermo_zone` Thing for each zone with the following parameters: -- the `where` config parameter (`OpenWebNet Device Address`): +- the `where` configuration parameter (`OpenWebNet Address`): - example BUS/SCS Thermo zone `1` --> `where="1"` -- the `standAlone` config parameter (`boolean`, default: `true`): identifies if the zone is managed or not by a Central Unit (4 or 99 zones). `standAlone=true` means no Central Unit is present in the system. +- the `standAlone` configuration parameter (`boolean`, default: `true`): identifies if the zone is managed or not by a Central Unit (4 or 99 zones). `standAlone=true` means no Central Unit is present in the system. Temperature sensors can be configured defining a `bus_thermo_sensor` Thing with the following parameters: -- the `where` config parameter (`OpenWebNet Device Address`): +- the `where` configuration parameter (`OpenWebNet Address`): - example sensor `5` of external zone `00` --> `where="500"` - example: slave sensor `3` of zone `2` --> `where="302"` @@ -155,7 +157,7 @@ Systems with Central Units (4 or 99 zones) are not fully supported yet. ## Channels -### Lighting, Automation, Power meter and CEN/CEN+ Scenario Events channels +### Lighting, Automation, Power meter, CEN/CEN+ Scenario Events and Dry Contact / IR Interfaces channels | Channel Type ID (channel ID) | Applies to Thing Type IDs | Item Type | Description | Read/Write | | ---------------------------------------- | ------------------------------------------------------------- | ------------- | ----------------------------------------------------- | :--------: | @@ -163,6 +165,7 @@ Systems with Central Units (4 or 99 zones) are not fully supported yet. | `brightness` | `bus_dimmer`, `zb_dimmer` | Dimmer | To adjust the brightness value (Percent, `ON`, `OFF`) | R/W | | `shutter` | `bus_automation` | Rollershutter | To activate roller shutters (`UP`, `DOWN`, `STOP`, Percent - [see Shutter position](#shutter-position)) | R/W | | `button#X` | `bus_cen_scenario_control`, `bus_cenplus_scenario_control` | String | Trigger channel for CEN/CEN+ scenario events [see possible values](#cen-cen-channels) | R (TRIGGER) | +| `sensor` | `bus_dry_contact_ir` | Switch | Indicates if a Dry Contact Interface is `ON`/`OFF`, or if a IR Sensor is detecting movement (`ON`), or not (`OFF`) | R | | `power` | `bus_energy_meter` | Number:Power | The current active power usage from Energy Meter | R | ### Thermo channels @@ -233,6 +236,7 @@ Bridge openwebnet:bus_gateway:mybridge "MyHOMEServer1" [ host="192.168.1.35", pa bus_thermo_sensor EXT_tempsensor "External Temperature" [ where="500"] bus_cen_scenario_control LR_CEN_scenario "Living Room CEN" [ where="51", buttons="4,3,8"] bus_cenplus_scenario_control LR_CENplus_scenario "Living Room CEN+" [ where="212", buttons="1,5,18" ] + bus_dry_contact_ir LR_IR_sensor "Living Room IR Sensor" [ where="399" ] } ``` @@ -275,8 +279,9 @@ String iLR_zone_cv "Conditioning valves" (g Number:Temperature iEXT_temp "Temperature [%.1f %unit%]" (gExternal) { channel="openwebnet:bus_thermo_sensor:mybridge:EXT_tempsensor:temperature" } -String iCENPlusProxyItem "CEN+ Proxy Item" +String iCENPlusProxyItem "CEN+ Proxy Item" +Switch iLR_IR_sensor "Sensor" { channel="openwebnet:bus_dry_contact_ir:mybridge:LR_IR_sensor:sensor" } ``` @@ -299,6 +304,7 @@ sitemap openwebnet label="OpenWebNet Binding Example Sitemap" Default item=iLR_switch icon="light" Default item=iLR_dimmer icon="light" Default item=iLR_shutter + Switch item=iLR_IR_sensor mappings=[ON="Presence", OFF="No Presence"] } Frame label="Energy Meters" icon="energy" diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/OpenWebNetBindingConstants.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/OpenWebNetBindingConstants.java index 218aa20fe996e..42bfec1c95787 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/OpenWebNetBindingConstants.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/OpenWebNetBindingConstants.java @@ -25,8 +25,8 @@ * The {@link OpenWebNetBindingConstants} class defines common constants, which are used across the whole binding. * * @author Massimo Valla - Initial contribution - * @author Andrea Conte - Energy management, Thermoregulation * @author Gilberto Cocchi - Thermoregulation + * @author Andrea Conte - Energy management, Thermoregulation */ @NonNullByDefault @@ -62,6 +62,8 @@ public class OpenWebNetBindingConstants { public static final ThingTypeUID THING_TYPE_BUS_CEN_SCENARIO_CONTROL = new ThingTypeUID(BINDING_ID, "bus_cen_scenario_control"); public static final String THING_LABEL_BUS_CEN_SCENARIO_CONTROL = "CEN Control"; + public static final ThingTypeUID THING_TYPE_BUS_DRY_CONTACT_IR = new ThingTypeUID(BINDING_ID, "bus_dry_contact_ir"); + public static final String THING_LABEL_BUS_DRY_CONTACT_IR = "Dry Contact/IR"; public static final ThingTypeUID THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL = new ThingTypeUID(BINDING_ID, "bus_cenplus_scenario_control"); public static final String THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL = "CEN+ Control"; @@ -94,7 +96,7 @@ public class OpenWebNetBindingConstants { public static final Set ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_ENERGY_METER); // ## CEN/CEN+ Scenario public static final Set SCENARIO_SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BUS_CEN_SCENARIO_CONTROL, - THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL); + THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL, THING_TYPE_BUS_DRY_CONTACT_IR); // ## Groups public static final Set DEVICE_SUPPORTED_THING_TYPES = Stream .of(LIGHTING_SUPPORTED_THING_TYPES, AUTOMATION_SUPPORTED_THING_TYPES, @@ -130,6 +132,7 @@ public class OpenWebNetBindingConstants { public static final String CHANNEL_SCENARIO_BUTTON = "button#"; public static final String CHANNEL_TYPE_CEN_BUTTON_EVENT = "cenButtonEvent"; public static final String CHANNEL_TYPE_CEN_PLUS_BUTTON_EVENT = "cenPlusButtonEvent"; + public static final String CHANNEL_DRY_CONTACT_IR = "sensor"; // devices config properties public static final String CONFIG_PROPERTY_WHERE = "where"; diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java index 2c75705e40ab2..58abc3fa2303d 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java @@ -159,6 +159,12 @@ public void newDiscoveryResult(Where where, OpenDeviceType deviceType, @Nullable deviceWho = Who.CEN_SCENARIO_SCHEDULER; break; } + case SCS_DRY_CONTACT_IR: { + thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR; + thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_DRY_CONTACT_IR; + deviceWho = Who.CEN_PLUS_SCENARIO_SCHEDULER; + break; + } case MULTIFUNCTION_SCENARIO_CONTROL: { thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL; thingLabel = OpenWebNetBindingConstants.THING_LABEL_BUS_CENPLUS_SCENARIO_CONTROL; diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetScenarioHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetScenarioHandler.java index 3ae1a35d01e64..375a7ff66ef4d 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetScenarioHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetScenarioHandler.java @@ -26,6 +26,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants; import org.openhab.binding.openwebnet.internal.actions.OpenWebNetCENActions; +import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -36,6 +37,7 @@ import org.openhab.core.thing.type.ChannelKind; import org.openhab.core.thing.type.ChannelTypeUID; import org.openhab.core.types.Command; +import org.openwebnet4j.communication.OWNException; import org.openwebnet4j.message.BaseOpenMessage; import org.openwebnet4j.message.CEN; import org.openwebnet4j.message.CEN.Pressure; @@ -51,8 +53,9 @@ import org.slf4j.LoggerFactory; /** - * The {@link OpenWebNetScenarioHandler} is responsible for handling commands/messages for CEN/CEN+ Scenarios. It - * extends the abstract {@link OpenWebNetThingHandler}. + * The {@link OpenWebNetScenarioHandler} is responsible for handling CEN/CEN+ Scenarios messages and Dry Contact / IR + * Interfaces messages. + * It extends the abstract {@link OpenWebNetThingHandler}. * * @author Massimo Valla - Initial contribution */ @@ -112,13 +115,21 @@ public String toString() { } } + private boolean isDryContactIR = false; private boolean isCENPlus = false; + private static long lastAllDevicesRefreshTS = -1; // timestamp when the last request for all device refresh was sent + // for this handler + protected static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 10000; // interval in msec before sending another all + // devices refresh request public static final Set SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.SCENARIO_SUPPORTED_THING_TYPES; public OpenWebNetScenarioHandler(Thing thing) { super(thing); - if (OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL.equals(thing.getThingTypeUID())) { + if (OpenWebNetBindingConstants.THING_TYPE_BUS_DRY_CONTACT_IR.equals(thing.getThingTypeUID())) { + isDryContactIR = true; + logger.debug("created DryContact/IR device for thing: {}", getThing().getUID()); + } else if (OpenWebNetBindingConstants.THING_TYPE_BUS_CENPLUS_SCENARIO_CONTROL.equals(thing.getThingTypeUID())) { isCENPlus = true; logger.debug("created CEN+ device for thing: {}", getThing().getUID()); } else { @@ -156,7 +167,7 @@ public Collection> getServices() { @Override protected String ownIdPrefix() { - if (isCENPlus) { + if (isCENPlus || isDryContactIR) { return Who.CEN_PLUS_SCENARIO_SCHEDULER.value().toString(); } else { return Who.CEN_SCENARIO_SCHEDULER.value().toString(); @@ -167,13 +178,33 @@ protected String ownIdPrefix() { protected void handleMessage(BaseOpenMessage msg) { super.handleMessage(msg); if (msg.isCommand()) { - triggerChannel((CEN) msg); + if (isDryContactIR) { + updateDryContactIRState((CENPlusScenario) msg); + } else { + triggerButtonChannel((CEN) msg); + } } else { logger.debug("handleMessage() Ignoring unsupported DIM for thing {}. Frame={}", getThing().getUID(), msg); } } - private void triggerChannel(CEN cenMsg) { + private void updateDryContactIRState(CENPlusScenario msg) { + logger.debug("updateDryContactIRState() for thing: {}", thing.getUID()); + try { + if (msg.isOn()) { + updateState(CHANNEL_DRY_CONTACT_IR, OnOffType.ON); + } else if (msg.isOff()) { + updateState(CHANNEL_DRY_CONTACT_IR, OnOffType.OFF); + } else { + logger.debug("updateDryContactIRState() Ignoring unsupported WHAT for thing {}. Frame={}", + getThing().getUID(), msg); + } + } catch (FrameException fe) { + logger.warn("updateDryContactIRState() Ignoring invalid frame {}", msg); + } + } + + private void triggerButtonChannel(CEN cenMsg) { Integer buttonNumber; try { buttonNumber = cenMsg.getButtonNumber(); @@ -244,7 +275,6 @@ private void triggerChannel(CEN cenMsg) { return; } } - triggerChannel(channel.getUID(), pressEv.toString()); } @@ -326,21 +356,59 @@ private static Set csvStringToSetInt(String s) { @Override protected void handleChannelCommand(ChannelUID channel, Command command) { - logger.warn("CEN/CEN+ channels are trigger channels and do not handle commands"); + logger.warn("CEN/CEN+ and DryContact/IR have read-only channels. Ignoring command {} for channel {}", command, + channel); } @Override protected void refreshDevice(boolean refreshAll) { - logger.debug("CEN/CEN+ channels are trigger channels and do not have state"); + if (isDryContactIR) { + if (refreshAll) { + long now = System.currentTimeMillis(); + if (now - lastAllDevicesRefreshTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) { + try { + send(CENPlusScenario.requestStatus("30")); + lastAllDevicesRefreshTS = now; + } catch (OWNException e) { + logger.warn("Excpetion while requesting all DryContact/IR devices refresh: {}", e.getMessage()); + } + } else { + logger.debug("Refresh all devices just sent..."); + } + } else { + requestState(); + } + } else { + logger.debug("CEN/CEN+ channels are trigger channels and do not have state"); + } } @Override - protected Where buildBusWhere(String wStr) throws IllegalArgumentException { - return new WhereCEN(wStr); + protected void requestChannelState(ChannelUID channel) { + if (isDryContactIR) { + requestState(); + } else { + logger.debug("CEN/CEN+ channels are trigger channels and do not have state"); + } + } + + /* helper method to request DryContact/IR device state */ + private void requestState() { + Where w = deviceWhere; + if (w != null) { + try { + send(CENPlusScenario.requestStatus(w.value())); + } catch (OWNException e) { + logger.warn("requestState() Exception while requesting device state: {} for thing {}", e.getMessage(), + thing.getUID()); + } + } else { + logger.warn("Could not requestState(): deviceWhere is null"); + } } @Override - protected void requestChannelState(ChannelUID channel) { - logger.debug("CEN/CEN+ channels are trigger channels and do not have state"); + protected Where buildBusWhere(String wStr) throws IllegalArgumentException { + return new WhereCEN(wStr); } } diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENPlusScenarioControl.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENPlusScenarioControl.xml index dbb589b143033..5c369e87f3f4b 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENPlusScenarioControl.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENPlusScenarioControl.xml @@ -31,7 +31,7 @@ - Use 2+N[0-2047]. Example: scenario control 5 --> WHERE=25 + Use 2+N[0-2047]. Example: scenario control 5 --> where=25 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENScenarioControl.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENScenarioControl.xml index 5f5700d1fff28..72bb2c5f17311 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENScenarioControl.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusCENScenarioControl.xml @@ -31,7 +31,7 @@ - Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01 + Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDryContactIR.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDryContactIR.xml new file mode 100644 index 0000000000000..3c84f62b2301e --- /dev/null +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDryContactIR.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + A OpenWebNet BUS/SCS Dry Contact Interface or IR Interface. BTicino models: 3477/F428, IR 4610-4611-4640 + etc. + + + + + + + BTicino/Legrand + BTI-3477/F428/IR 4610-4611-4640 etc. + 2510 + + + ownId + + + + + Automation Dry Contacts (N=1-201): example N=60 --> where=360. Alarm Dry Contacts and IR sensors + (Zone=1-9, N=1-9): example Zone=4, N=5 --> where=345 + + + + + diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml index c5589c9088d8a..0cbfbce668cf8 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml @@ -24,7 +24,7 @@ - + It identifies one OpenWebNet device diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/channels.xml index ddba826d737e8..caefd2555837f 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/channels.xml @@ -205,4 +205,12 @@ + + + Switch + + Dry Contact Interface or IR Interface sensor movement (read only) + + + diff --git a/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/internal/handler/OwnIdTest.java b/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/internal/handler/OwnIdTest.java index 3fc51cb5464cc..fb7f2c81220c0 100644 --- a/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/internal/handler/OwnIdTest.java +++ b/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/internal/handler/OwnIdTest.java @@ -22,6 +22,7 @@ import org.openwebnet4j.message.BaseOpenMessage; import org.openwebnet4j.message.FrameException; import org.openwebnet4j.message.Where; +import org.openwebnet4j.message.WhereCEN; import org.openwebnet4j.message.WhereEnergyManagement; import org.openwebnet4j.message.WhereLightAutom; import org.openwebnet4j.message.WhereThermo; @@ -60,9 +61,9 @@ public class OwnIdTest { * BUS Thermo actuator 1#2 1 4.1 1 * BUS TempSensor 500 500 4.500 500 * BUS Energy 51 51 18.51 51 - * -INACTIVE- BUS CEN 51 51 15.51 51 - * -INACTIVE- BUS CEN+ 212 212 25.212 212 - * -INACTIVE- BUS DryContact 399 399 25.399 399 + * BUS CEN 51 51 15.51 51 + * BUS CEN+ 212 212 25.212 212 + * BUS DryContact 399 399 25.399 399 * */ // @formatter:on @@ -79,7 +80,10 @@ public enum TEST { bus_thermo(new WhereThermo("1"), Who.fromValue(4),"*#4*1*0*0020##" , "1", "4.1", "1"), bus_thermo_act(new WhereThermo("1#2"), Who.fromValue(4),"*#4*1#2*20*0##" ,"1", "4.1", "1"), bus_tempSensor(new WhereThermo("500"), Who.fromValue(4), "*#4*500*15*1*0020*0001##", "500", "4.500", "500"), - bus_energy(new WhereEnergyManagement("51"), Who.fromValue(18), "*#18*51*113##", "51", "18.51", "51"); + bus_energy(new WhereEnergyManagement("51"), Who.fromValue(18), "*#18*51*113##", "51", "18.51", "51"), + bus_cen(new WhereCEN("51"), Who.fromValue(15), "*15*31*51##", "51", "15.51", "51"), + bus_cen_plus(new WhereCEN("212"), Who.fromValue(25), "*25*21#31*212##", "212", "25.212", "212"), + bus_drycontact(new WhereCEN("399"), Who.fromValue(25), "*25*32#1*399##", "399", "25.399", "399"); // @formatter:on From a6534d7031868207a20d1afdce88e1bafa571835 Mon Sep 17 00:00:00 2001 From: Pieter Buts Date: Sun, 12 Dec 2021 17:15:16 +0100 Subject: [PATCH 219/361] Fix xml unmarshalling exception in DenonMarantzHttpConnector.java (#11766) Signed-off-by: Michael Schmidt --- .../internal/connector/http/DenonMarantzHttpConnector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/connector/http/DenonMarantzHttpConnector.java b/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/connector/http/DenonMarantzHttpConnector.java index 31fa274cca133..57a4593a71e27 100644 --- a/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/connector/http/DenonMarantzHttpConnector.java +++ b/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/connector/http/DenonMarantzHttpConnector.java @@ -364,12 +364,12 @@ public PropertyRenamerDelegate(XMLStreamReader xsr) { @Override public String getAttributeLocalName(int index) { - return Introspector.decapitalize(super.getAttributeLocalName(index)); + return Introspector.decapitalize(super.getAttributeLocalName(index)).intern(); } @Override public String getLocalName() { - return Introspector.decapitalize(super.getLocalName()); + return Introspector.decapitalize(super.getLocalName()).intern(); } } } From 5cc5188c22ac686e522c27ffa3061e7b9d2269cd Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Sun, 12 Dec 2021 08:40:51 -0800 Subject: [PATCH 220/361] [myq] Fix for controlling lights (#11765) Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- .../openhab/binding/myq/internal/handler/MyQLampHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.myq/src/main/java/org/openhab/binding/myq/internal/handler/MyQLampHandler.java b/bundles/org.openhab.binding.myq/src/main/java/org/openhab/binding/myq/internal/handler/MyQLampHandler.java index 80c537eee5b4b..f2fc63be49503 100644 --- a/bundles/org.openhab.binding.myq/src/main/java/org/openhab/binding/myq/internal/handler/MyQLampHandler.java +++ b/bundles/org.openhab.binding.myq/src/main/java/org/openhab/binding/myq/internal/handler/MyQLampHandler.java @@ -62,8 +62,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (bridge != null && localDevice != null) { BridgeHandler handler = bridge.getHandler(); if (handler != null) { - ((MyQAccountHandler) handler).sendLampAction(localDevice, - command == OnOffType.ON ? "turnon" : "turnoff"); + ((MyQAccountHandler) handler).sendLampAction(localDevice, command == OnOffType.ON ? "on" : "off"); } } } From 2515e373fb5052d32198be201d611bd68f2fd0d3 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Sun, 12 Dec 2021 18:02:05 +0100 Subject: [PATCH 221/361] New Crowdin updates (#11762) * New translations openweathermap.properties (German) * New translations openweathermap.properties (German) * New translations urtsi.properties (German) Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/openweathermap_de.properties | 14 ++++++------- .../resources/OH-INF/i18n/urtsi_de.properties | 21 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties index b82b5b5a9b919..f0127dcf691b6 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties @@ -12,21 +12,21 @@ thing-type.openweathermap.onecall-history.description = Ermöglicht die Anzeige thing-type.openweathermap.onecall.label = One Call API - Wetterinformationen thing-type.openweathermap.onecall.description = Ermöglicht die Anzeige der aktuellen Wetterinformationen und der Wettervorhersage. thing-type.openweathermap.onecall.group.forecastDay2.label = Wettervorhersage für übermorgen -thing-type.openweathermap.onecall.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage zusammen. thing-type.openweathermap.onecall.group.forecastDay3.label = Wettervorhersage für 3 Tage -thing-type.openweathermap.onecall.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen zusammen. thing-type.openweathermap.onecall.group.forecastDay4.label = Wettervorhersage für 4 Tage -thing-type.openweathermap.onecall.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen zusammen. thing-type.openweathermap.onecall.group.forecastDay5.label = Wettervorhersage für 5 Tage -thing-type.openweathermap.onecall.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen zusammen. thing-type.openweathermap.onecall.group.forecastDay6.label = Wettervorhersage für 6 Tage thing-type.openweathermap.onecall.group.forecastDay6.description = Fasst Daten der Wettervorhersage in sechs Tagen zusammen. thing-type.openweathermap.onecall.group.forecastDay7.label = Wettervorhersage für 7 Tage thing-type.openweathermap.onecall.group.forecastDay7.description = Fasst Daten der Wettervorhersage in sieben Tagen zusammen. thing-type.openweathermap.onecall.group.forecastToday.label = Wettervorhersage für heute -thing-type.openweathermap.onecall.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage zusammen. thing-type.openweathermap.onecall.group.forecastTomorrow.label = Wettervorhersage für morgen -thing-type.openweathermap.onecall.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage der One Call API zusammen. +thing-type.openweathermap.onecall.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage zusammen. thing-type.openweathermap.uvindex.label = UV-Index thing-type.openweathermap.uvindex.description = Ermöglicht die Anzeige des aktuellen UV-Index. thing-type.openweathermap.uvindex.group.forecastDay2.label = UV-Index für übermorgen @@ -168,7 +168,7 @@ channel-group-type.openweathermap.hourlyForecast.description = Fasst Daten der 5 channel-group-type.openweathermap.oneCallAlerts.label = Wetterwarnungen channel-group-type.openweathermap.oneCallAlerts.description = Fasst Daten von Wetterwarnungen zusammen. channel-group-type.openweathermap.oneCallCurrent.label = Aktuelles Wetter -channel-group-type.openweathermap.oneCallCurrent.description = Fasst aktuelle Wetterdaten der One Call API zusammen. +channel-group-type.openweathermap.oneCallCurrent.description = Fasst Daten des aktuellen Wetters zusammen. channel-group-type.openweathermap.oneCallDaily.label = One Call API - Tägliche Wettervorhersage channel-group-type.openweathermap.oneCallDaily.description = Fasst Daten der täglichen Wettervorhersage zusammen. channel-group-type.openweathermap.oneCallHistory.label = Historische Wetterdaten diff --git a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties index 901bc21fc75dd..bd8df8e36c164 100644 --- a/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties +++ b/bundles/org.openhab.binding.urtsi/src/main/resources/OH-INF/i18n/urtsi_de.properties @@ -1,18 +1,19 @@ # binding + bindingDescription = Dies ist das Binding für Somfy Universal RTS Interface II (URTSI II). +bindingLabel = Somfy URTSI II Binding # thing types + +positionChannelLabel = Position des RTS Geräts +positionChannelDescription = Ändern der Position des RTS Gerätes. +rtsDeviceLabel = Somfy RTS Gerät +rtsDeviceDescription = Dies ist ein Gerät, das über RTS kommuniziert (z.B. ein Rolladenmotor). +rtsDeviceChannelLabel = Kanal +rtsDeviceChannelDescription = Der Kanal, der dem RTS Gerät am URTSI II zugewiesen wurde. urtsiDeviceLabel = Somfy URTSI II Gerät urtsiDeviceDescription = Dies ist die Somfy URTSI II Box. urtsiDevicePortLabel = Port -urtsiDevicePortDescription = Der Port, über den das Gerät angesprochen wird (z.B. /dev/ttyUSB0) +urtsiDevicePortDescription = Der Port, über den das Gerät angesprochen wird (z.B. /dev/ttyUSB0). urtsiDeviceCommandIntervalLabel = Befehlausführungsintervall -urtsiDeviceCommandIntervalDescription = Die Zeit (in ms), die das Binding zwischen dem Absenden von zwei Befehlen warten soll - -rtsDeviceLabel = Somfy RTS Gerät -rtsDeviceDescription = Dies ist ein Gerät, das über RTS kommuniziert (z.B. ein Rolladenmotor). -rtsDeviceChannelLabel = Kanal -rtsDeviceChannelDescription = Der Kanel, der dem RTS Gerät am URTSI II zugewiesen wurde - -positionChannelLabel = Position des RTS Geräts -positionChannelDescription = Ändern der Position des RTS Gerätes +urtsiDeviceCommandIntervalDescription = Die Zeit (in ms), die das Binding zwischen dem Absenden von zwei Befehlen warten soll. From fa903fdf6e9674c33e6b56a14c657087c1c32f0d Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sun, 12 Dec 2021 19:32:51 +0100 Subject: [PATCH 222/361] Add default translations for io add-ons (#11753) * Add default translations for io add-ons This makes the texts used by these add-ons translatable with Crowdin. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/homekit.properties | 47 +++++++++++++++++++ .../OH-INF/i18n/hueemulation.properties | 28 +++++++++++ .../io/metrics/MetricsRestController.java | 2 +- .../resources/OH-INF/i18n/metrics.properties | 20 ++++++++ .../java/org/openhab/io/neeo/NeeoService.java | 6 +-- .../resources/OH-INF/i18n/neeo.properties | 12 +++++ 6 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 bundles/org.openhab.io.homekit/src/main/resources/OH-INF/i18n/homekit.properties create mode 100644 bundles/org.openhab.io.hueemulation/src/main/resources/OH-INF/i18n/hueemulation.properties create mode 100644 bundles/org.openhab.io.metrics/src/main/resources/OH-INF/i18n/metrics.properties create mode 100644 bundles/org.openhab.io.neeo/src/main/resources/OH-INF/i18n/neeo.properties diff --git a/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/i18n/homekit.properties b/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/i18n/homekit.properties new file mode 100644 index 0000000000000..918f9ed5b68eb --- /dev/null +++ b/bundles/org.openhab.io.homekit/src/main/resources/OH-INF/i18n/homekit.properties @@ -0,0 +1,47 @@ +io.config.homekit.blockUserDeletion.label = Block deletion of the HomeKit user +io.config.homekit.blockUserDeletion.description = Block deletion of the HomeKit user information from openHAB and the unpairing of devices +io.config.homekit.group.core.label = Core Configuration +io.config.homekit.group.network.label = Network Settings +io.config.homekit.group.network.description = General network settings +io.config.homekit.group.thermostat.label = Thermostat Settings +io.config.homekit.group.thermostat.description = General thermostat settings +io.config.homekit.group.thermostatCurrentHeatingCooling.label = Thermostat Current Heating/Cooling Mapping +io.config.homekit.group.thermostatCurrentHeatingCooling.description = String values used by your thermostat to set different targetHeatingCooling modes +io.config.homekit.group.thermostatTargetHeatingCooling.label = Thermostat Target Heating/Cooling Mapping +io.config.homekit.group.thermostatTargetHeatingCooling.description = String values used by your thermostat to set different targetHeatingCooling modes +io.config.homekit.name.label = Bridge name +io.config.homekit.name.description = Name of the HomeKit bridge +io.config.homekit.networkInterface.label = Network Interface +io.config.homekit.networkInterface.description = Defines the IP address of the network interface to expose the HomeKit integration on. +io.config.homekit.pin.label = Pin +io.config.homekit.pin.description = Defines the pin, used for pairing, in the form ###-##-###. +io.config.homekit.port.label = Port +io.config.homekit.port.description = Defines the port the HomeKit integration listens on. +io.config.homekit.qrCode.label = HomeKit QR Code +io.config.homekit.qrCode.description = Scan QR code with home app to add openHAB as HomeKit bridge. +io.config.homekit.setupId.label = Setup ID +io.config.homekit.setupId.description = Setup ID used for pairing using QR Code. Alphanumeric code of length 4. +io.config.homekit.startDelay.label = Start Delay +io.config.homekit.startDelay.description = HomeKit start delay in case of item configuration differences. +io.config.homekit.thermostatCurrentModeCooling.label = Cooling Value +io.config.homekit.thermostatCurrentModeCooling.description = Value for setting target heatingCoolingCurrentMode to COOL (IE: indicating that the air condition is currently cooling the home). +io.config.homekit.thermostatCurrentModeHeating.label = Heating Value +io.config.homekit.thermostatCurrentModeHeating.description = Value for setting target heatingCoolingCurrentMode to HEAT (IE: indicating that the heater is currently warming the home). +io.config.homekit.thermostatCurrentModeOff.label = Off Value +io.config.homekit.thermostatCurrentModeOff.description = Value for setting target heatingCoolingCurrentMode to OFF (IE: the hvac is currently idle, because the target temperature has been reached per the mode). +io.config.homekit.thermostatTargetModeAuto.label = Auto Value +io.config.homekit.thermostatTargetModeAuto.description = Word used to set the target heatingCoolingMode to AUTO (if a thermostat is defined). +io.config.homekit.thermostatTargetModeCool.label = Cool Value +io.config.homekit.thermostatTargetModeCool.description = Word used to set the target heatingCoolingMode to COOL (if a thermostat is defined). +io.config.homekit.thermostatTargetModeHeat.label = Heat Value +io.config.homekit.thermostatTargetModeHeat.description = Word used to set the target heatingCoolingMode to HEAT (if a thermostat is defined). +io.config.homekit.thermostatTargetModeOff.label = Off Value +io.config.homekit.thermostatTargetModeOff.description = Word used to set the target heatingCoolingMode to OFF (if a thermostat is defined). +io.config.homekit.useFahrenheitTemperature.label = Use Fahrenheit Temperature +io.config.homekit.useFahrenheitTemperature.description = Defines whether or not to direct HomeKit clients to use fahrenheit temperatures instead of celsius. +io.config.homekit.useOHmDNS.label = Use openHAB mDNS service +io.config.homekit.useOHmDNS.description = Defines whether mDNS service of openHAB or a separate instance of mDNS should be used. + +# service + +service.io.homekit.label = HomeKit Integration diff --git a/bundles/org.openhab.io.hueemulation/src/main/resources/OH-INF/i18n/hueemulation.properties b/bundles/org.openhab.io.hueemulation/src/main/resources/OH-INF/i18n/hueemulation.properties new file mode 100644 index 0000000000000..231bfb59628c5 --- /dev/null +++ b/bundles/org.openhab.io.hueemulation/src/main/resources/OH-INF/i18n/hueemulation.properties @@ -0,0 +1,28 @@ +io.config.hueemulation.createNewUserOnEveryEndpoint.label = Pairing: Add Unknown User-keys +io.config.hueemulation.createNewUserOnEveryEndpoint.description = Set this option to create new users on the fly during the next pairing mode period. This helps with Amazon Echo device discovery. This option is automatically switched off after the timeout. +io.config.hueemulation.discoveryHttpPort.label = Optional Discovery Web Port +io.config.hueemulation.discoveryHttpPort.description = Some Hue applications require a different port (80) then what openHAB runs on by default (8080). This option will only advertise a different port then what we are listening on. Useful if you have an iptables rule redirect traffic from this port to the openHAB port. +io.config.hueemulation.discoveryIp.label = Optional Discovery Address +io.config.hueemulation.discoveryIp.description = If your host has multiple IP addresses you may specify the IP(s) you would like to advertise in the UPNP discovery process. You may safely leave this empty on most systems. Use commas to separate multiple entries. +io.config.hueemulation.ignoreItemsWithTags.label = Ignore Items by Tag +io.config.hueemulation.ignoreItemsWithTags.description = All items that are tagged with the given tags are ignore by the Hue Emulation Service. Use commas to separate multiple entries. +io.config.hueemulation.pairingEnabled.label = Device Pairing +io.config.hueemulation.pairingEnabled.description = Pairing must be enabled to connect a new device. Pairing is automatically disabled after the configured pairing time (usually 60 seconds). +io.config.hueemulation.pairingTimeout.label = Pairing Timeout +io.config.hueemulation.pairingTimeout.description = Pairing is automatically disabled after the given time in seconds. +io.config.hueemulation.permanentV1bridge.label = Permanently Emulate V1 Hue Bridge +io.config.hueemulation.permanentV1bridge.description = There is no obvious reason to not emulate the newer bridge all the time, but here is the option if you want the old (round Hue bridge) to be emulated. +io.config.hueemulation.restrictToTagsColorLights.label = Color Item Tags +io.config.hueemulation.restrictToTagsColorLights.description = The HUE emulation can either publish all Color items if this is set to an empty string or filter items by tags. Use commas to separate multiple entries. +io.config.hueemulation.restrictToTagsSwitches.label = Switch Item Tags +io.config.hueemulation.restrictToTagsSwitches.description = The HUE emulation can either publish Switch items if this is set to an empty string or filter items by tags. Use commas to separate multiple entries. +io.config.hueemulation.restrictToTagsWhiteLights.label = White Item Tags +io.config.hueemulation.restrictToTagsWhiteLights.description = The HUE emulation can either publish all Dimmer items if this is set to an empty string or filter items by tags. Use commas to separate multiple entries. +io.config.hueemulation.temporarilyEmulateV1bridge.label = Pairing: Temporarily Emulate V1 Hue Bridge +io.config.hueemulation.temporarilyEmulateV1bridge.description = Some Amazon Echos only support V1 bridges (round hardware bridge). This option is only active during discovery and automatically switched off after the timeout. +io.config.hueemulation.uuid.label = Unique Bridge ID +io.config.hueemulation.uuid.description = Each Hue bridge has a universal unique id (UUID) assigned. This is random generated if no value has been assigned. Note on Amazon Alexa Echo devices: It might help to change the UUID after you have changed item ids. The Echos will recognize this service as a new bridge. + +# service + +service.io.hueemulation.label = Hue Emulation diff --git a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java index b245a4f55c402..4b79d71e8c4b6 100644 --- a/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java +++ b/bundles/org.openhab.io.metrics/src/main/java/org/openhab/io/metrics/MetricsRestController.java @@ -64,7 +64,7 @@ @RolesAllowed({ Role.USER, Role.ADMIN }) @Tag(name = MetricsRestController.PATH_METRICS) @NonNullByDefault -@ConfigurableService(category = "io", label = "Metrics service", description_uri = "io:metrics") +@ConfigurableService(category = "io", label = "Metrics Service", description_uri = "io:metrics") public class MetricsRestController { private final Logger logger = LoggerFactory.getLogger(MetricsRestController.class); public static final String PATH_METRICS = "metrics"; diff --git a/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/i18n/metrics.properties b/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/i18n/metrics.properties new file mode 100644 index 0000000000000..d7d436f258c33 --- /dev/null +++ b/bundles/org.openhab.io.metrics/src/main/resources/OH-INF/i18n/metrics.properties @@ -0,0 +1,20 @@ +io.config.metrics.group.influx.label = Influx Metrics +io.config.metrics.group.jmx.label = JMX Metrics +io.config.metrics.influxDB.label = Database Name +io.config.metrics.influxDB.description = The Name of the Database to Use. Defaults to "openhab". +io.config.metrics.influxMetricsEnabled.label = Enabled +io.config.metrics.influxMetricsEnabled.description = Enable the Influx (www.influxdata.com) Metrics. Further Configuration of the InfluxDB Instance Necessary. +io.config.metrics.influxPassword.label = Password +io.config.metrics.influxPassword.description = The InfluxDB Password (No Default). +io.config.metrics.influxURL.label = URL +io.config.metrics.influxURL.description = The URL of the InfluxDB Instance. Defaults to http://localhost:8086 +io.config.metrics.influxUpdateIntervalInSeconds.label = Update Interval in Seconds +io.config.metrics.influxUpdateIntervalInSeconds.description = Controls How Often Metrics Are Exported to InfluxDB (in Seconds). Defaults to 300 +io.config.metrics.influxUsername.label = User Name +io.config.metrics.influxUsername.description = The InfluxDB User Name (No Default). +io.config.metrics.jmxMetricsEnabled.label = Enabled +io.config.metrics.jmxMetricsEnabled.description = Enable the Java Management Extensions (JMX) Metrics. + +# service + +service.io.metrics.label = Metrics Service diff --git a/bundles/org.openhab.io.neeo/src/main/java/org/openhab/io/neeo/NeeoService.java b/bundles/org.openhab.io.neeo/src/main/java/org/openhab/io/neeo/NeeoService.java index 4e750474da79f..7366663ab8f73 100644 --- a/bundles/org.openhab.io.neeo/src/main/java/org/openhab/io/neeo/NeeoService.java +++ b/bundles/org.openhab.io.neeo/src/main/java/org/openhab/io/neeo/NeeoService.java @@ -28,6 +28,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.binding.BindingInfoRegistry; +import org.openhab.core.config.core.ConfigurableService; import org.openhab.core.events.Event; import org.openhab.core.events.EventFilter; import org.openhab.core.events.EventPublisher; @@ -70,9 +71,8 @@ * @author Tim Roberts - Initial Contribution */ @NonNullByDefault -@Component(service = EventSubscriber.class, property = { "service.pid=org.openhab.io.neeo.NeeoService", - "service.config.description.uri=io:neeo", "service.config.label=NEEO Integration", - "service.config.category=io" }) +@Component(service = EventSubscriber.class, property = { "service.pid=org.openhab.io.neeo.NeeoService" }) +@ConfigurableService(category = "io", label = "NEEO Integration", description_uri = "io:neeo") public class NeeoService implements EventSubscriber, NetworkAddressChangeListener { /** The logger */ diff --git a/bundles/org.openhab.io.neeo/src/main/resources/OH-INF/i18n/neeo.properties b/bundles/org.openhab.io.neeo/src/main/resources/OH-INF/i18n/neeo.properties new file mode 100644 index 0000000000000..d4acc837d684c --- /dev/null +++ b/bundles/org.openhab.io.neeo/src/main/resources/OH-INF/i18n/neeo.properties @@ -0,0 +1,12 @@ +io.config.neeo.checkStatusInterval.label = Check Status Interval (seconds) +io.config.neeo.checkStatusInterval.description = The interval (in seconds) to check the status of the brain +io.config.neeo.exposeAll.label = Expose All +io.config.neeo.exposeAll.description = Expose all things +io.config.neeo.exposeNeeoBinding.label = Expose NEEO Binding +io.config.neeo.exposeNeeoBinding.description = Expose things found by the NEEO Binding +io.config.neeo.searchLimit.label = Search Limit +io.config.neeo.searchLimit.description = The maximum number of results to return for a search + +# service + +service.io.neeo.label = NEEO Integration From 954a4fe8639166050d1cd2b773baaa875abdc462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20K=C3=BCper?= Date: Sun, 12 Dec 2021 19:32:58 +0100 Subject: [PATCH 223/361] [deutschebahn] Implemented filters for trains in timetable (#11745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implemented filters within timetable. Signed-off-by: Sönke Küper * Added position information for filtertokens, to allow detailled failure information Signed-off-by: Sönke Küper * Added documentation for non matching values. Signed-off-by: Sönke Küper * Applied review remarks. Signed-off-by: Sönke Küper Co-authored-by: Sönke Küper Signed-off-by: Michael Schmidt --- .../README.md | 20 ++ .../AbstractDtoAttributeSelector.java | 12 + .../internal/AttributeSelection.java | 14 + .../DeutscheBahnTimetableConfiguration.java | 29 +- .../DeutscheBahnTimetableHandler.java | 18 +- .../deutschebahn/internal/EventAttribute.java | 137 ++++++-- .../internal/EventAttributeSelection.java | 38 +++ .../internal/TimetableStopFilter.java | 5 +- .../internal/TripLabelAttribute.java | 47 ++- .../internal/filter/AndOperator.java | 41 +++ .../internal/filter/AndPredicate.java | 55 ++++ .../internal/filter/BracketCloseToken.java | 41 +++ .../internal/filter/BracketOpenToken.java | 41 +++ .../internal/filter/ChannelNameEquals.java | 114 +++++++ .../internal/filter/FilterParser.java | 299 ++++++++++++++++++ .../filter/FilterParserException.java | 33 ++ .../internal/filter/FilterScanner.java | 239 ++++++++++++++ .../filter/FilterScannerException.java | 42 +++ .../internal/filter/FilterToken.java | 45 +++ .../internal/filter/FilterTokenVisitor.java | 51 +++ .../internal/filter/OperatorToken.java | 31 ++ .../internal/filter/OrOperator.java | 41 +++ .../internal/filter/OrPredicate.java | 55 ++++ ...tableStopByStringEventAttributeFilter.java | 69 ++++ .../filter/TimetableStopPredicate.java | 28 ++ .../internal/timetable/TimetableLoader.java | 15 +- .../resources/OH-INF/thing/thing-types.xml | 5 + .../internal/EventAttributeTest.java | 25 +- .../internal/filter/FilterParserTest.java | 284 +++++++++++++++++ .../internal/filter/FilterScannerTest.java | 114 +++++++ ...tableByStringEventAttributeFilterTest.java | 111 +++++++ 31 files changed, 2040 insertions(+), 59 deletions(-) create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndOperator.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndPredicate.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketCloseToken.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketOpenToken.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/ChannelNameEquals.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParser.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserException.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScanner.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerException.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterToken.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterTokenVisitor.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OperatorToken.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrOperator.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrPredicate.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopByStringEventAttributeFilter.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopPredicate.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserTest.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerTest.java create mode 100644 bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/TimetableByStringEventAttributeFilterTest.java diff --git a/bundles/org.openhab.binding.deutschebahn/README.md b/bundles/org.openhab.binding.deutschebahn/README.md index 23184d523fea2..9a2aec47e5093 100644 --- a/bundles/org.openhab.binding.deutschebahn/README.md +++ b/bundles/org.openhab.binding.deutschebahn/README.md @@ -40,7 +40,27 @@ In addition you can configure if only arrivals, only departures or all trains sh | `accessToken` | | Yes | The access token for the timetable api within the developer portal of Deutsche Bahn. | | `evaNo` | | Yes | The eva nr. of the train station for which the timetable will be requested.| | `trainFilter` | | Yes | Selects the trains that will be displayed in the timetable. Either only arrivals, only departures or all trains can be displayed. | +| `additionalFilter` | | No | Specifies additional filters for trains, that should be displayed within the timetable. | +** Additional filter ** +If you only want to display certain trains within your timetable, you can specify an additional filter. This will be evaluated when loading trains, +and only trains that matches the given filter will be contained within the timetable. + +To specify an advanced filter you can + +- specify a filter for the value of a given channel. Therefore you must specify the channel name (with channel group) and specify a compare value like this: +`departure#line="RE60"` this will select all trains with line RE60 +- use regular expressions for expected channel values, for example: `departure#line="RE.*"`, this will match all lines starting with "RE". +- combine multiple statements as "and" conjunction by using `&`. If used, both parts must match, for example: `departure#line="RE60" & trip#category="WFB"` +- combine multiple statements as "or" disjunction by using `|`. If used, one of the parts must match, for example: `departure#line="RE60" | departure#line="RE60"` +- use brackets to build more complex queries like `trip#category="RE" AND (departure#line="17" OR departure#line="57")` + +If a channel has multiple values, like the channels `arrival#planned-path` and `departure#planned-path` have a list of stations, +only one of the values must match the given expression. So you can specify a filter like `departure#planned-path="Hannover Hbf"` +to easily display only trains that will go to Hannover Hbf. + +If the filtered value is not present for a train, for example if you filter a departure attribute but train ends at the selected station, +the filter will not match. ### Configuring the trains diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java index b5c6db1040b75..827008f156f60 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AbstractDtoAttributeSelector.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.deutschebahn.internal; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; @@ -37,6 +38,7 @@ public abstract class AbstractDtoAttributeSelector getState; private final String channelTypeName; private final Class stateType; + private final Function> valueToList; /** * Creates an new {@link EventAttribute}. @@ -49,11 +51,13 @@ protected AbstractDtoAttributeSelector(final String channelTypeName, // final Function getter, // final BiConsumer setter, // final Function getState, // + final Function> valueToList, // final Class stateType) { this.channelTypeName = channelTypeName; this.getter = getter; this.setter = setter; this.getState = getState; + this.valueToList = valueToList; this.stateType = stateType; } @@ -92,6 +96,14 @@ public final VALUE_TYPE getValue(final DTO_TYPE object) { return this.getter.apply(object); } + /** + * Returns a list of values as string list. + * Returns empty list if value is not present, singleton list if attribute is not single-valued. + */ + public final List getStringValues(DTO_TYPE object) { + return this.valueToList.apply(getValue(object)); + } + /** * Sets the value for the selected attribute in the given DTO object */ diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java index 6c0d767066949..54226218025d0 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/AttributeSelection.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.deutschebahn.internal; +import java.util.List; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; @@ -25,9 +27,21 @@ @NonNullByDefault public interface AttributeSelection { + /** + * Returns the value for this attribute. + */ + @Nullable + public abstract Object getValue(TimetableStop stop); + /** * Returns the {@link State} that should be set for the channels'value for this attribute. */ @Nullable public abstract State getState(TimetableStop stop); + + /** + * Returns a list of values as string list. + * Returns empty list if value is not present, singleton list if attribute is not single-valued. + */ + public abstract List getStringValues(TimetableStop t); } diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java index ee93c69650e1b..f04d0a09a940e 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableConfiguration.java @@ -12,7 +12,16 @@ */ package org.openhab.binding.deutschebahn.internal; +import java.util.List; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.filter.FilterParser; +import org.openhab.binding.deutschebahn.internal.filter.FilterParserException; +import org.openhab.binding.deutschebahn.internal.filter.FilterScanner; +import org.openhab.binding.deutschebahn.internal.filter.FilterScannerException; +import org.openhab.binding.deutschebahn.internal.filter.FilterToken; +import org.openhab.binding.deutschebahn.internal.filter.TimetableStopPredicate; /** * The {@link DeutscheBahnTimetableConfiguration} for the Timetable bridge-type. @@ -37,10 +46,28 @@ public class DeutscheBahnTimetableConfiguration { */ public String trainFilter = ""; + /** + * Specifies additional filters for trains to be displayed within the timetable. + */ + public String additionalFilter = ""; + /** * Returns the {@link TimetableStopFilter}. */ - public TimetableStopFilter getTimetableStopFilter() { + public TimetableStopFilter getTrainFilterFilter() { return TimetableStopFilter.valueOf(this.trainFilter.toUpperCase()); } + + /** + * Returns the additional configured {@link TimetableStopPredicate} or null if not specified. + */ + public @Nullable TimetableStopPredicate getAdditionalFilter() throws FilterScannerException, FilterParserException { + if (additionalFilter.isBlank()) { + return null; + } else { + final FilterScanner scanner = new FilterScanner(); + final List filterTokens = scanner.processInput(additionalFilter); + return FilterParser.parse(filterTokens); + } + } } diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java index 616493a999157..6daaca73205d5 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/DeutscheBahnTimetableHandler.java @@ -30,6 +30,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.deutschebahn.internal.filter.AndPredicate; +import org.openhab.binding.deutschebahn.internal.filter.FilterParserException; +import org.openhab.binding.deutschebahn.internal.filter.FilterScannerException; +import org.openhab.binding.deutschebahn.internal.filter.TimetableStopPredicate; import org.openhab.binding.deutschebahn.internal.timetable.TimetableLoader; import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Api; import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1ApiFactory; @@ -151,14 +155,22 @@ public void initialize() { try { final TimetablesV1Api api = this.timetablesV1ApiFactory.create(config.accessToken, HttpUtil::executeUrl); - final TimetableStopFilter stopFilter = config.getTimetableStopFilter(); + final TimetableStopFilter stopFilter = config.getTrainFilterFilter(); + final TimetableStopPredicate additionalFilter = config.getAdditionalFilter(); + + final TimetableStopPredicate combinedFilter; + if (additionalFilter == null) { + combinedFilter = stopFilter; + } else { + combinedFilter = new AndPredicate(stopFilter, additionalFilter); + } final EventType eventSelection = stopFilter == TimetableStopFilter.ARRIVALS ? EventType.ARRIVAL : EventType.ARRIVAL; this.loader = new TimetableLoader( // api, // - stopFilter, // + combinedFilter, // eventSelection, // currentTimeProvider, // config.evaNo, // @@ -170,6 +182,8 @@ public void initialize() { this.updateChannels(); this.restartJob(); }); + } catch (FilterScannerException | FilterParserException e) { + this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); } catch (JAXBException | SAXException | URISyntaxException e) { this.logger.error("Error initializing api", e); this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java index 26ad3e5a098ca..d67cd6bd65d04 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttribute.java @@ -17,6 +17,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.function.BiConsumer; @@ -55,145 +56,155 @@ public final class EventAttribute * Planned Path. */ public static final EventAttribute PPTH = new EventAttribute<>("planned-path", Event::getPpth, - Event::setPpth, StringType::new, StringType.class); + Event::setPpth, StringType::new, EventAttribute::splitOnPipeToList, StringType.class); /** * Changed Path. */ public static final EventAttribute CPTH = new EventAttribute<>("changed-path", Event::getCpth, - Event::setCpth, StringType::new, StringType.class); + Event::setCpth, StringType::new, EventAttribute::splitOnPipeToList, StringType.class); /** * Planned platform. */ public static final EventAttribute PP = new EventAttribute<>("planned-platform", Event::getPp, - Event::setPp, StringType::new, StringType.class); + Event::setPp, StringType::new, EventAttribute::singletonList, StringType.class); /** * Changed platform. */ public static final EventAttribute CP = new EventAttribute<>("changed-platform", Event::getCp, - Event::setCp, StringType::new, StringType.class); + Event::setCp, StringType::new, EventAttribute::singletonList, StringType.class); /** * Planned time. */ public static final EventAttribute PT = new EventAttribute<>("planned-time", - getDate(Event::getPt), setDate(Event::setPt), EventAttribute::createDateTimeType, DateTimeType.class); + getDate(Event::getPt), setDate(Event::setPt), EventAttribute::createDateTimeType, + EventAttribute::mapDateToStringList, DateTimeType.class); /** * Changed time. */ public static final EventAttribute CT = new EventAttribute<>("changed-time", - getDate(Event::getCt), setDate(Event::setCt), EventAttribute::createDateTimeType, DateTimeType.class); + getDate(Event::getCt), setDate(Event::setCt), EventAttribute::createDateTimeType, + EventAttribute::mapDateToStringList, DateTimeType.class); /** * Planned status. */ public static final EventAttribute PS = new EventAttribute<>("planned-status", - Event::getPs, Event::setPs, EventAttribute::fromEventStatus, StringType.class); + Event::getPs, Event::setPs, EventAttribute::fromEventStatus, EventAttribute::listFromEventStatus, + StringType.class); /** * Changed status. */ public static final EventAttribute CS = new EventAttribute<>("changed-status", - Event::getCs, Event::setCs, EventAttribute::fromEventStatus, StringType.class); + Event::getCs, Event::setCs, EventAttribute::fromEventStatus, EventAttribute::listFromEventStatus, + StringType.class); /** * Hidden. */ public static final EventAttribute HI = new EventAttribute<>("hidden", Event::getHi, - Event::setHi, EventAttribute::parseHidden, OnOffType.class); + Event::setHi, EventAttribute::parseHidden, EventAttribute::mapIntegerToStringList, OnOffType.class); /** * Cancellation time. */ public static final EventAttribute CLT = new EventAttribute<>("cancellation-time", - getDate(Event::getClt), setDate(Event::setClt), EventAttribute::createDateTimeType, DateTimeType.class); + getDate(Event::getClt), setDate(Event::setClt), EventAttribute::createDateTimeType, + EventAttribute::mapDateToStringList, DateTimeType.class); /** * Wing. */ public static final EventAttribute WINGS = new EventAttribute<>("wings", Event::getWings, - Event::setWings, StringType::new, StringType.class); + Event::setWings, StringType::new, EventAttribute::splitOnPipeToList, StringType.class); /** * Transition. */ public static final EventAttribute TRA = new EventAttribute<>("transition", Event::getTra, - Event::setTra, StringType::new, StringType.class); + Event::setTra, StringType::new, EventAttribute::singletonList, StringType.class); /** * Planned distant endpoint. */ public static final EventAttribute PDE = new EventAttribute<>("planned-distant-endpoint", - Event::getPde, Event::setPde, StringType::new, StringType.class); + Event::getPde, Event::setPde, StringType::new, EventAttribute::singletonList, StringType.class); /** * Changed distant endpoint. */ public static final EventAttribute CDE = new EventAttribute<>("changed-distant-endpoint", - Event::getCde, Event::setCde, StringType::new, StringType.class); + Event::getCde, Event::setCde, StringType::new, EventAttribute::singletonList, StringType.class); /** * Distant change. */ public static final EventAttribute DC = new EventAttribute<>("distant-change", Event::getDc, - Event::setDc, DecimalType::new, DecimalType.class); + Event::setDc, DecimalType::new, EventAttribute::mapIntegerToStringList, DecimalType.class); /** * Line. */ public static final EventAttribute L = new EventAttribute<>("line", Event::getL, Event::setL, - StringType::new, StringType.class); + StringType::new, EventAttribute::singletonList, StringType.class); /** * Messages. */ public static final EventAttribute, StringType> MESSAGES = new EventAttribute<>("messages", - EventAttribute.getMessages(), EventAttribute::setMessages, EventAttribute::mapMessages, StringType.class); + EventAttribute.getMessages(), EventAttribute::setMessages, EventAttribute::mapMessages, + EventAttribute::mapMessagesToList, StringType.class); /** * Planned Start station. */ public static final EventAttribute PLANNED_START_STATION = new EventAttribute<>( "planned-start-station", EventAttribute.getSingleStationFromPath(Event::getPpth, true), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), StringType::new, EventAttribute::singletonList, StringType.class); /** * Planned Previous stations. */ - public static final EventAttribute PLANNED_PREVIOUS_STATIONS = new EventAttribute<>( + public static final EventAttribute, StringType> PLANNED_PREVIOUS_STATIONS = new EventAttribute<>( "planned-previous-stations", EventAttribute.getIntermediateStationsFromPath(Event::getPpth, true), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), EventAttribute::fromStringList, EventAttribute::nullToEmptyList, + StringType.class); /** * Planned Target station. */ public static final EventAttribute PLANNED_TARGET_STATION = new EventAttribute<>( "planned-target-station", EventAttribute.getSingleStationFromPath(Event::getPpth, false), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), StringType::new, EventAttribute::singletonList, StringType.class); /** * Planned Following stations. */ - public static final EventAttribute PLANNED_FOLLOWING_STATIONS = new EventAttribute<>( + public static final EventAttribute, StringType> PLANNED_FOLLOWING_STATIONS = new EventAttribute<>( "planned-following-stations", EventAttribute.getIntermediateStationsFromPath(Event::getPpth, false), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), EventAttribute::fromStringList, EventAttribute::nullToEmptyList, + StringType.class); /** * Changed Start station. */ public static final EventAttribute CHANGED_START_STATION = new EventAttribute<>( "changed-start-station", EventAttribute.getSingleStationFromPath(Event::getCpth, true), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), StringType::new, EventAttribute::singletonList, StringType.class); /** * Changed Previous stations. */ - public static final EventAttribute CHANGED_PREVIOUS_STATIONS = new EventAttribute<>( + public static final EventAttribute, StringType> CHANGED_PREVIOUS_STATIONS = new EventAttribute<>( "changed-previous-stations", EventAttribute.getIntermediateStationsFromPath(Event::getCpth, true), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), EventAttribute::fromStringList, EventAttribute::nullToEmptyList, + StringType.class); /** * Changed Target station. */ public static final EventAttribute CHANGED_TARGET_STATION = new EventAttribute<>( "changed-target-station", EventAttribute.getSingleStationFromPath(Event::getCpth, false), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), StringType::new, EventAttribute::singletonList, StringType.class); /** * Changed Following stations. */ - public static final EventAttribute CHANGED_FOLLOWING_STATIONS = new EventAttribute<>( + public static final EventAttribute, StringType> CHANGED_FOLLOWING_STATIONS = new EventAttribute<>( "changed-following-stations", EventAttribute.getIntermediateStationsFromPath(Event::getCpth, false), - EventAttribute.voidSetter(), StringType::new, StringType.class); + EventAttribute.voidSetter(), EventAttribute::fromStringList, EventAttribute::nullToEmptyList, + StringType.class); /** * List containing all known {@link EventAttribute}. @@ -214,14 +225,38 @@ private EventAttribute(final String channelTypeName, // final Function getter, // final BiConsumer setter, // final Function getState, // + final Function> valueToList, // final Class stateType) { - super(channelTypeName, getter, setter, getState, stateType); + super(channelTypeName, getter, setter, getState, valueToList, stateType); } private static StringType fromEventStatus(final EventStatus value) { return new StringType(value.value()); } + private static List listFromEventStatus(final @Nullable EventStatus value) { + if (value == null) { + return Collections.emptyList(); + } else { + return Collections.singletonList(value.value()); + } + } + + private static StringType fromStringList(final List value) { + return new StringType(value.stream().collect(Collectors.joining(" - "))); + } + + private static List nullToEmptyList(@Nullable final List value) { + return value == null ? Collections.emptyList() : value; + } + + /** + * Returns a list containing only the given value or empty list if value is null. + */ + private static List singletonList(@Nullable String value) { + return value == null ? Collections.emptyList() : Collections.singletonList(value); + } + private static OnOffType parseHidden(@Nullable Integer value) { return OnOffType.from(value != null && value == 1); } @@ -291,6 +326,24 @@ private static StringType mapMessages(final @Nullable List messages) { } } + /** + * Maps the status codes from the messages into string list. + */ + private static List mapMessagesToList(final @Nullable List messages) { + if (messages == null || messages.isEmpty()) { + return Collections.emptyList(); + } else { + return messages // + .stream()// + .filter((Message message) -> message.getC() != null) // + .map(Message::getC) // + .distinct() // + .map(MessageCodes::getMessage) // + .filter((String messageText) -> !messageText.isEmpty()) // + .collect(Collectors.toList()); + } + } + private static Function> getMessages() { return new Function>() { @@ -305,6 +358,22 @@ private static StringType mapMessages(final @Nullable List messages) { }; } + private static List mapIntegerToStringList(@Nullable Integer value) { + if (value == null) { + return Collections.emptyList(); + } else { + return Collections.singletonList(String.valueOf(value)); + } + } + + private static List mapDateToStringList(@Nullable Date value) { + if (value == null) { + return Collections.emptyList(); + } else { + return Collections.singletonList(DATETIME_FORMAT.format(value)); + } + } + /** * Returns an single station from an path value (i.e. pipe separated value of stations). * @@ -337,7 +406,7 @@ private static StringType mapMessages(final @Nullable List messages) { * @param removeFirst if true the first value will be removed, false will remove the last * value. */ - private static Function getIntermediateStationsFromPath( + private static Function> getIntermediateStationsFromPath( final Function getPath, boolean removeFirst) { return (final Event event) -> { final String path = getPath.apply(event); @@ -351,7 +420,7 @@ private static StringType mapMessages(final @Nullable List messages) { } else { stations = stations.limit(stationValues.length - 1); } - return stations.collect(Collectors.joining(" - ")); + return stations.collect(Collectors.toList()); }; } @@ -372,6 +441,10 @@ private static String[] splitPath(final String path) { return path.split("\\|"); } + private static List splitOnPipeToList(final String value) { + return Arrays.asList(value.split("\\|")); + } + /** * Returns an {@link EventAttribute} for the given channel-type and {@link EventType}. */ diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java index 51224949f9a10..ee681ec3b65a3 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/EventAttributeSelection.java @@ -12,6 +12,10 @@ */ package org.openhab.binding.deutschebahn.internal; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; @@ -49,4 +53,38 @@ public State getState(TimetableStop stop) { return this.eventAttribute.getState(event); } } + + @Override + public @Nullable Object getValue(TimetableStop stop) { + final Event event = eventType.getEvent(stop); + if (event == null) { + return UnDefType.UNDEF; + } else { + return this.eventAttribute.getValue(event); + } + } + + @Override + public List getStringValues(TimetableStop stop) { + final Event event = eventType.getEvent(stop); + if (event == null) { + return Collections.emptyList(); + } else { + return this.eventAttribute.getStringValues(event); + } + } + + @Override + public int hashCode() { + return Objects.hash(eventAttribute, eventType); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof EventAttributeSelection)) { + return false; + } + final EventAttributeSelection other = (EventAttributeSelection) obj; + return Objects.equals(eventAttribute, other.eventAttribute) && eventType == other.eventType; + } } diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java index e0256f42453e9..192b4b39e356c 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TimetableStopFilter.java @@ -12,9 +12,8 @@ */ package org.openhab.binding.deutschebahn.internal; -import java.util.function.Predicate; - import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.filter.TimetableStopPredicate; import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; /** @@ -23,7 +22,7 @@ * @author Sönke Küper - initial contribution. */ @NonNullByDefault -public enum TimetableStopFilter implements Predicate { +public enum TimetableStopFilter implements TimetableStopPredicate { /** * Selects all entries. diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java index 2acbaeaab5e40..3b0750bd0a8a2 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/TripLabelAttribute.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.deutschebahn.internal; +import java.util.Collections; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; @@ -44,29 +46,30 @@ public final class TripLabelAttribute exte * Trip category. */ public static final TripLabelAttribute C = new TripLabelAttribute<>("category", TripLabel::getC, - TripLabel::setC, StringType::new, StringType.class); + TripLabel::setC, StringType::new, TripLabelAttribute::singletonList, StringType.class); /** * Number. */ public static final TripLabelAttribute N = new TripLabelAttribute<>("number", TripLabel::getN, - TripLabel::setN, StringType::new, StringType.class); + TripLabel::setN, StringType::new, TripLabelAttribute::singletonList, StringType.class); /** * Filter flags. */ public static final TripLabelAttribute F = new TripLabelAttribute<>("filter-flags", - TripLabel::getF, TripLabel::setF, StringType::new, StringType.class); + TripLabel::getF, TripLabel::setF, StringType::new, TripLabelAttribute::singletonList, StringType.class); /** * Trip Type. */ public static final TripLabelAttribute T = new TripLabelAttribute<>("trip-type", - TripLabel::getT, TripLabel::setT, TripLabelAttribute::fromTripType, StringType.class); + TripLabel::getT, TripLabel::setT, TripLabelAttribute::fromTripType, TripLabelAttribute::listFromTripType, + StringType.class); /** * Owner. */ public static final TripLabelAttribute O = new TripLabelAttribute<>("owner", TripLabel::getO, - TripLabel::setO, StringType::new, StringType.class); + TripLabel::setO, StringType::new, TripLabelAttribute::singletonList, StringType.class); /** * Creates an new {@link TripLabelAttribute}. @@ -79,8 +82,9 @@ private TripLabelAttribute(final String channelTypeName, // final Function getter, // final BiConsumer setter, // final Function getState, // + final Function> valueToList, // final Class stateType) { - super(channelTypeName, getter, setter, getState, stateType); + super(channelTypeName, getter, setter, getState, valueToList, stateType); } @Nullable @@ -92,10 +96,41 @@ public State getState(TimetableStop stop) { return super.getState(stop.getTl()); } + @Override + public @Nullable Object getValue(TimetableStop stop) { + if (stop.getTl() == null) { + return UnDefType.UNDEF; + } + return super.getValue(stop.getTl()); + } + + @Override + public List getStringValues(TimetableStop stop) { + if (stop.getTl() == null) { + return Collections.emptyList(); + } + return this.getStringValues(stop.getTl()); + } + private static StringType fromTripType(final TripType value) { return new StringType(value.value()); } + private static List listFromTripType(@Nullable final TripType value) { + if (value == null) { + return Collections.emptyList(); + } else { + return Collections.singletonList(value.value()); + } + } + + /** + * Returns a list containing only the given value or empty list if value is null. + */ + private static List singletonList(@Nullable String value) { + return value == null ? Collections.emptyList() : Collections.singletonList(value); + } + /** * Returns an {@link TripLabelAttribute} for the given channel-name. */ diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndOperator.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndOperator.java new file mode 100644 index 0000000000000..eb5a5b0de2e5e --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndOperator.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A token representing an conjunction. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class AndOperator extends OperatorToken { + + /** + * Creates new {@link AndOperator}. + */ + public AndOperator(int position) { + super(position); + } + + @Override + public String toString() { + return "&"; + } + + @Override + public R accept(FilterTokenVisitor visitor) throws FilterParserException { + return visitor.handle(this); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndPredicate.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndPredicate.java new file mode 100644 index 0000000000000..a2162a17bb40d --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/AndPredicate.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * And conjunction for {@link TimetableStopPredicate}. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class AndPredicate implements TimetableStopPredicate { + + private final TimetableStopPredicate first; + private final TimetableStopPredicate second; + + /** + * Creates an new {@link AndPredicate}. + */ + public AndPredicate(TimetableStopPredicate first, TimetableStopPredicate second) { + this.first = first; + this.second = second; + } + + @Override + public boolean test(TimetableStop t) { + return first.test(t) && second.test(t); + } + + /** + * Returns first argument. + */ + TimetableStopPredicate getFirst() { + return first; + } + + /** + * Returns second argument. + */ + TimetableStopPredicate getSecond() { + return second; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketCloseToken.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketCloseToken.java new file mode 100644 index 0000000000000..f056569337342 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketCloseToken.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A token representing an closing bracket. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class BracketCloseToken extends OperatorToken { + + /** + * Creates new {@link BracketCloseToken}. + */ + public BracketCloseToken(int position) { + super(position); + } + + @Override + public String toString() { + return ")"; + } + + @Override + public R accept(FilterTokenVisitor visitor) throws FilterParserException { + return visitor.handle(this); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketOpenToken.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketOpenToken.java new file mode 100644 index 0000000000000..03d00cdf70873 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/BracketOpenToken.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A token representing an opening bracket. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class BracketOpenToken extends OperatorToken { + + /** + * Creates new {@link BracketOpenToken}. + */ + public BracketOpenToken(int position) { + super(position); + } + + @Override + public String toString() { + return "("; + } + + @Override + public R accept(FilterTokenVisitor visitor) throws FilterParserException { + return visitor.handle(this); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/ChannelNameEquals.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/ChannelNameEquals.java new file mode 100644 index 0000000000000..34313311f180a --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/ChannelNameEquals.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.AttributeSelection; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.EventAttributeSelection; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.TripLabelAttribute; + +/** + * Token representing an attribute filter. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public final class ChannelNameEquals extends FilterToken { + + private final String channelName; + private final Pattern filterValue; + private String channelGroup; + + /** + * Creates an new {@link ChannelNameEquals}. + */ + public ChannelNameEquals(int position, String channelGroup, String channelName, Pattern filterPattern) { + super(position); + this.channelGroup = channelGroup; + this.channelName = channelName; + this.filterValue = filterPattern; + } + + /** + * Returns the channel group. + */ + public String getChannelGroup() { + return channelGroup; + } + + /** + * Returns the channel name. + */ + public String getChannelName() { + return channelName; + } + + /** + * Returns the filter value. + */ + public Pattern getFilterValue() { + return filterValue; + } + + @Override + public String toString() { + return this.channelGroup + "#" + channelName + "=\"" + this.filterValue.toString() + "\""; + } + + @Override + public R accept(FilterTokenVisitor visitor) throws FilterParserException { + return visitor.handle(this); + } + + /** + * Maps this into an {@link TimetableStopByStringEventAttributeFilter}. + */ + public TimetableStopByStringEventAttributeFilter mapToPredicate() throws FilterParserException { + return new TimetableStopByStringEventAttributeFilter(mapAttributeSelection(), filterValue); + } + + private AttributeSelection mapAttributeSelection() throws FilterParserException { + switch (this.channelGroup) { + case "trip": + final TripLabelAttribute tripAttribute = TripLabelAttribute.getByChannelName(this.channelName); + if (tripAttribute == null) { + throw new FilterParserException("Invalid trip channel: " + channelName); + } + return tripAttribute; + + case "departure": + final EventType eventTypeDeparture = EventType.DEPARTURE; + final EventAttribute departureAttribute = EventAttribute.getByChannelName(this.channelName, + eventTypeDeparture); + if (departureAttribute == null) { + throw new FilterParserException("Invalid departure channel: " + channelName); + } + return new EventAttributeSelection(eventTypeDeparture, departureAttribute); + + case "arrival": + final EventType eventTypeArrival = EventType.ARRIVAL; + final EventAttribute arrivalAttribute = EventAttribute.getByChannelName(this.channelName, + eventTypeArrival); + if (arrivalAttribute == null) { + throw new FilterParserException("Invalid arrival channel: " + channelName); + } + return new EventAttributeSelection(eventTypeArrival, arrivalAttribute); + default: + throw new FilterParserException("Unknown channel group: " + channelGroup); + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParser.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParser.java new file mode 100644 index 0000000000000..e030997bbaa6c --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParser.java @@ -0,0 +1,299 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Parses an {@link FilterToken}-Sequence into a {@link TimetableStopPredicate}. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class FilterParser { + + /** + * Parser's state. + */ + private abstract static class State implements FilterTokenVisitor { + + @Nullable + private State previousState; + + public State(@Nullable State previousState) { + this.previousState = previousState; + } + + private final State handle(FilterToken token) throws FilterParserException { + return token.accept(this); + } + + protected abstract State handleChildResult(TimetableStopPredicate predicate) throws FilterParserException; + + @Override + public final State handle(ChannelNameEquals channelEquals) throws FilterParserException { + final TimetableStopByStringEventAttributeFilter predicate = channelEquals.mapToPredicate(); + return this.handleChildResult(predicate); + } + + protected final State publishResultToPrevious(TimetableStopPredicate predicate) throws FilterParserException { + return this.getPreviousState().handleChildResult(predicate); + } + + protected State getPreviousState() throws FilterParserException { + final State previousStateValue = this.previousState; + if (previousStateValue == null) { + throw new FilterParserException("Invalid filter"); + } else { + return previousStateValue; + } + } + + /** + * Returns the result. + */ + public abstract TimetableStopPredicate getResult() throws FilterParserException; + } + + /** + * Initial state for the parser. + */ + private static final class InitialState extends State { + + @Nullable + private TimetableStopPredicate result; + + public InitialState() { + super(null); + } + + @Override + public State handle(OrOperator operator) throws FilterParserException { + final TimetableStopPredicate currentResult = this.result; + this.result = null; + if (currentResult == null) { + throw new FilterParserException( + "Invalid filter: first argument missing for '|' at " + operator.getPosition()); + } + return new OrState(this, currentResult); + } + + @Override + public State handle(AndOperator operator) throws FilterParserException { + final TimetableStopPredicate currentResult = this.result; + this.result = null; + if (currentResult == null) { + throw new FilterParserException( + "Invalid filter: first argument missing for '&' at " + operator.getPosition()); + } + return new AndState(this, currentResult); + } + + @Override + public State handle(BracketOpenToken token) throws FilterParserException { + this.result = null; + return new SubQueryState(this); + } + + @Override + public State handle(BracketCloseToken token) throws FilterParserException { + throw new FilterParserException("Unexpected token " + token.toString() + " at " + token.getPosition()); + } + + @Override + protected State handleChildResult(TimetableStopPredicate predicate) throws FilterParserException { + if (this.result == null) { + this.result = predicate; + return this; + } else { + throw new FilterParserException("Invalid filter: Operator for multiple filters missing."); + } + } + + @Override + public TimetableStopPredicate getResult() throws FilterParserException { + final TimetableStopPredicate currentResult = this.result; + if (currentResult != null) { + return currentResult; + } + throw new FilterParserException("Invalid filter."); + } + } + + /** + * State while parsing an conjunction. + */ + private static final class AndState extends State { + + private final TimetableStopPredicate first; + + public AndState(State previousState, final TimetableStopPredicate first) { + super(previousState); + this.first = first; + } + + @Override + public State handle(OrOperator operator) throws FilterParserException { + throw new FilterParserException("Invalid second argument for '&' operator " + operator.toString() + " at " + + operator.getPosition()); + } + + @Override + public State handle(AndOperator operator) throws FilterParserException { + throw new FilterParserException("Invalid second argument for '&' operator " + operator.toString() + " at " + + operator.getPosition()); + } + + @Override + public State handle(BracketOpenToken token) throws FilterParserException { + return new SubQueryState(this); + } + + @Override + public State handle(BracketCloseToken token) throws FilterParserException { + throw new FilterParserException( + "Invalid second argument for '&' operator " + token.toString() + " at " + token.getPosition()); + } + + @Override + protected State handleChildResult(TimetableStopPredicate predicate) throws FilterParserException { + return this.publishResultToPrevious(new AndPredicate(first, predicate)); + } + + @Override + public TimetableStopPredicate getResult() throws FilterParserException { + throw new FilterParserException("Invalid filter"); + } + } + + /** + * State while parsing an disjunction. + */ + private static final class OrState extends State { + + private final TimetableStopPredicate first; + + public OrState(State previousState, final TimetableStopPredicate first) { + super(previousState); + this.first = first; + } + + @Override + public State handle(OrOperator operator) throws FilterParserException { + throw new FilterParserException("Invalid second argument for '|' operator " + operator.toString() + " at " + + operator.getPosition()); + } + + @Override + public State handle(AndOperator operator) throws FilterParserException { + throw new FilterParserException("Invalid second argument for '|' operator " + operator.toString() + " at " + + operator.getPosition()); + } + + @Override + public State handle(BracketOpenToken token) throws FilterParserException { + return new SubQueryState(this); + } + + @Override + public State handle(BracketCloseToken token) throws FilterParserException { + throw new FilterParserException( + "Invalid second argument for '|' operator " + token.toString() + " at " + token.getPosition()); + } + + @Override + protected State handleChildResult(TimetableStopPredicate second) throws FilterParserException { + return this.publishResultToPrevious(new OrPredicate(first, second)); + } + + @Override + public TimetableStopPredicate getResult() throws FilterParserException { + throw new FilterParserException("Invalid filter"); + } + } + + /** + * State while parsing an Subquery. + */ + private static final class SubQueryState extends State { + + @Nullable + private TimetableStopPredicate currentResult; + + public SubQueryState(State previousState) { + super(previousState); + } + + @Override + public State handle(OrOperator operator) throws FilterParserException { + TimetableStopPredicate result = this.currentResult; + if (result == null) { + throw new FilterParserException( + "Operator '|' at " + operator.getPosition() + " must not be first element in subquery."); + } + return new OrState(this, result); + } + + @Override + public State handle(AndOperator operator) throws FilterParserException { + TimetableStopPredicate result = this.currentResult; + if (result == null) { + throw new FilterParserException( + "Operator '&' at" + operator.getPosition() + " must not be first element in subquery."); + } + return new AndState(this, result); + } + + @Override + public State handle(BracketOpenToken token) throws FilterParserException { + return new SubQueryState(this); + } + + @Override + public State handle(BracketCloseToken token) throws FilterParserException { + TimetableStopPredicate result = this.currentResult; + if (result == null) { + throw new FilterParserException("Subquery must not be empty at " + token.getPosition()); + } + return publishResultToPrevious(result); + } + + @Override + protected State handleChildResult(TimetableStopPredicate predicate) { + this.currentResult = predicate; + return this; + } + + @Override + public TimetableStopPredicate getResult() throws FilterParserException { + throw new FilterParserException("Invalid filter"); + } + } + + private FilterParser() { + } + + /** + * Parses the given {@link FilterToken} into an {@link TimetableStopPredicate}. + */ + public static TimetableStopPredicate parse(final List tokens) throws FilterParserException { + State state = new InitialState(); + for (FilterToken token : tokens) { + state = state.handle(token); + } + return state.getResult(); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserException.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserException.java new file mode 100644 index 0000000000000..8efb6f4002ad1 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserException.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception showing problems during parsing a filter expression. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public final class FilterParserException extends Exception { + + private static final long serialVersionUID = 3104578924298682889L; + + /** + * Creates an new {@link FilterParserException}. + */ + public FilterParserException(String message) { + super(message); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScanner.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScanner.java new file mode 100644 index 0000000000000..8282807426450 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScanner.java @@ -0,0 +1,239 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Scanner for filter expression. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class FilterScanner { + + private static final Set OP_CHARS = new HashSet<>(Arrays.asList('&', '|', '!', '(', ')')); + private static final Pattern CHANNEL_NAME = Pattern.compile("(trip|arrival|departure)#(\\S+)"); + + /** + * State of the scanner. + */ + private interface State { + + /** + * Handles the next read character. + * + * @return Returns the next scanner state. + */ + public abstract State handle(int position, char currentChar) throws FilterScannerException; + + /** + * Called when no more input is available. + */ + public abstract void finish(int position) throws FilterScannerException; + } + + /** + * Initial state of the scanner. + */ + private final class InitialState implements State { + + @Override + public State handle(int position, char currentChar) throws FilterScannerException { + // Skip white spaces + if (Character.isWhitespace(currentChar)) { + return this; + } + + switch (currentChar) { + // Handle all operator tokens + case '&': + result.add(new AndOperator(position)); + return this; + case '|': + result.add(new OrOperator(position)); + return this; + case '(': + result.add(new BracketOpenToken(position)); + return this; + case ')': + result.add(new BracketCloseToken(position)); + return this; + default: + final ChannelNameState channelNameState = new ChannelNameState(); + return channelNameState.handle(position, currentChar); + } + } + + @Override + public void finish(int position) { + } + } + + /** + * State scanning an channel name until the equals-sign. + */ + private final class ChannelNameState implements State { + + private final StringBuilder channelName = new StringBuilder(); + private int startPosition = -1; + + @Override + public State handle(int position, final char currentChar) throws FilterScannerException { + // Skip white spaces at front + if (Character.isWhitespace(currentChar) && channelName.toString().isEmpty()) { + return this; + } + + if (Character.isWhitespace(currentChar)) { + throw new FilterScannerException(position, "Channel name must not contain whitespace."); + } + + if (currentChar == '=') { + final String channelNameValue = this.channelName.toString(); + if (channelNameValue.isEmpty()) { + throw new FilterScannerException(position, "Channel name must not be empty."); + } + + final Matcher matcher = CHANNEL_NAME.matcher(channelNameValue); + if (!matcher.matches()) { + throw new FilterScannerException(position, "Invalid channel name: " + channelNameValue); + } + + return new ExpectQuotesState(startPosition, matcher.group(1), matcher.group(2)); + } + + if (OP_CHARS.contains(currentChar)) { + throw new FilterScannerException(position, "Channel name must not contain operation char."); + } + + this.channelName.append(currentChar); + if (startPosition == -1) { + startPosition = position; + } + return this; + } + + @Override + public void finish(int position) throws FilterScannerException { + throw new FilterScannerException(position, "Filter value is missing."); + } + } + + /** + * State after channel name, wiating for quotes. + */ + private final class ExpectQuotesState implements State { + + private final int startPosition; + private final String channelName; + private String channelGroup; + + /** + * Creates an new {@link ExpectQuotesState}. + */ + public ExpectQuotesState(int startPosition, final String channelGroup, String channelName) { + this.startPosition = startPosition; + this.channelGroup = channelGroup; + this.channelName = channelName; + } + + @Override + public State handle(int position, char currentChar) throws FilterScannerException { + if (currentChar != '"') { + throw new FilterScannerException(position, "Filter value must start with quotes"); + } + return new FilterValueState(startPosition, channelGroup, channelName); + } + + @Override + public void finish(int position) throws FilterScannerException { + throw new FilterScannerException(position, "Filter value is missing."); + } + } + + /** + * State scanning the filter value until next quotes. + */ + private final class FilterValueState implements State { + + private final int startPosition; + private final String channelGroup; + private final String channelName; + private final StringBuilder filterValue; + + /** + * Creates an new {@link FilterValueState}. + */ + public FilterValueState(int startPosition, String channelGroup, String channelName) { + this.startPosition = startPosition; + this.channelGroup = channelGroup; + this.channelName = channelName; + this.filterValue = new StringBuilder(); + } + + @Override + public State handle(int position, char currentChar) throws FilterScannerException { + if (currentChar == '"') { + finish(position); + return new InitialState(); + } + filterValue.append(currentChar); + return this; + } + + @Override + public void finish(int position) throws FilterScannerException { + String filterPattern = this.filterValue.toString(); + try { + result.add(new ChannelNameEquals(startPosition, this.channelGroup, this.channelName, + Pattern.compile(filterPattern))); + } catch (PatternSyntaxException e) { + throw new FilterScannerException(position, "Filter pattern is invalid: " + filterPattern, e); + } + } + } + + private List result; + + /** + * Creates an new {@link FilterScanner}. + */ + public FilterScanner() { + this.result = new ArrayList<>(); + } + + /** + * Scans the given filter expression and returns the result sequence of {@link FilterToken}. + */ + public List processInput(String value) throws FilterScannerException { + State state = new InitialState(); + for (int pos = 0; pos < value.length(); pos++) { + char currentChar = value.charAt(pos); + state = state.handle(pos + 1, currentChar); + } + + state.finish(value.length()); + + return this.result; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerException.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerException.java new file mode 100644 index 0000000000000..abb64f66f1cb5 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerException.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.regex.PatternSyntaxException; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Exception for errors within the filter scanner. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class FilterScannerException extends Exception { + + private static final long serialVersionUID = -7319023069454747511L; + + /** + * Creates an exception with given position and message. + */ + FilterScannerException(int position, String message) { + super("Scanner failed at positon: " + position + ": " + message); + } + + /** + * Creates an exception with given position, message and cause. + */ + FilterScannerException(int position, String message, PatternSyntaxException e) { + super("Scanner failed at positon: " + position + ": " + message, e); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterToken.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterToken.java new file mode 100644 index 0000000000000..03f9e03af3b74 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterToken.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A token representing a part of an filter expression. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public abstract class FilterToken { + + private final int position; + + /** + * Creates an new {@link FilterToken}. + */ + public FilterToken(int position) { + this.position = position; + } + + /** + * Returns the start position of the token. + */ + public final int getPosition() { + return position; + } + + /** + * Accept for {@link FilterTokenVisitor}. + */ + public abstract R accept(FilterTokenVisitor visitor) throws FilterParserException; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterTokenVisitor.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterTokenVisitor.java new file mode 100644 index 0000000000000..79c28089d549d --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/FilterTokenVisitor.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Visitor for {@link FilterToken}. + * + * @author Sönke Küper - Initial Contribution. + * + * @param Return type. + */ +@NonNullByDefault +public interface FilterTokenVisitor { + + /** + * Handles {@link ChannelNameEquals}. + */ + public abstract R handle(ChannelNameEquals equals) throws FilterParserException; + + /** + * Handles {@link OrOperator}. + */ + public abstract R handle(OrOperator operator) throws FilterParserException; + + /** + * Handles {@link AndOperator}. + */ + public abstract R handle(AndOperator operator) throws FilterParserException; + + /** + * Handles {@link BracketOpenToken}. + */ + public abstract R handle(BracketOpenToken token) throws FilterParserException; + + /** + * Handles {@link BracketCloseToken}. + */ + public abstract R handle(BracketCloseToken token) throws FilterParserException; +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OperatorToken.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OperatorToken.java new file mode 100644 index 0000000000000..4c4d86762bd83 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OperatorToken.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Abstraction for all operators. + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public abstract class OperatorToken extends FilterToken { + + /** + * Creates an new {@link OperatorToken}. + */ + public OperatorToken(int position) { + super(position); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrOperator.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrOperator.java new file mode 100644 index 0000000000000..14a18beb63da5 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrOperator.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A token representing an disjunction. + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class OrOperator extends OperatorToken { + + /** + * Creates new {@link OrOperator}. + */ + public OrOperator(int position) { + super(position); + } + + @Override + public String toString() { + return "|"; + } + + @Override + public R accept(FilterTokenVisitor visitor) throws FilterParserException { + return visitor.handle(this); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrPredicate.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrPredicate.java new file mode 100644 index 0000000000000..5224a96d36875 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/OrPredicate.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Disjunction for {@link TimetableStopPredicate}. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +final class OrPredicate implements TimetableStopPredicate { + + private final TimetableStopPredicate first; + private final TimetableStopPredicate second; + + /** + * Creates an new {@link OrPredicate}. + */ + public OrPredicate(TimetableStopPredicate first, TimetableStopPredicate second) { + this.first = first; + this.second = second; + } + + @Override + public boolean test(TimetableStop t) { + return first.test(t) || second.test(t); + } + + /** + * Returns first argument. + */ + TimetableStopPredicate getFirst() { + return first; + } + + /** + * Returns second argument. + */ + TimetableStopPredicate getSecond() { + return second; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopByStringEventAttributeFilter.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopByStringEventAttributeFilter.java new file mode 100644 index 0000000000000..b3ab27f6fc694 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopByStringEventAttributeFilter.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.List; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.AttributeSelection; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Abstract predicate that filters timetable stops by an selected attribute of an {@link TimetableStop}. + * + * If value has multiple values (for example stations on the planned-path) the predicate will return true, + * if at least one value matches the given filter. + * + * @author Sönke Küper - initial contribution + */ +@NonNullByDefault +public final class TimetableStopByStringEventAttributeFilter implements TimetableStopPredicate { + + private final AttributeSelection attributeSelection; + private final Pattern filter; + + /** + * Creates an new {@link TimetableStopByStringEventAttributeFilter}. + */ + TimetableStopByStringEventAttributeFilter(final AttributeSelection attributeSelection, final Pattern filter) { + this.attributeSelection = attributeSelection; + this.filter = filter; + } + + @Override + public boolean test(TimetableStop t) { + final List values = attributeSelection.getStringValues(t); + + for (String actualValue : values) { + if (filter.matcher(actualValue).matches()) { + return true; + } + } + return false; + } + + /** + * Returns the {@link AttributeSelection}. + */ + final AttributeSelection getAttributeSelection() { + return attributeSelection; + } + + /** + * Returns the filter pattern. + */ + final Pattern getFilter() { + return filter; + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopPredicate.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopPredicate.java new file mode 100644 index 0000000000000..c90a41197c1b1 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/filter/TimetableStopPredicate.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import java.util.function.Predicate; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; + +/** + * Predicate to match an TimetableStop + * + * @author Sönke Küper - initial contribution. + */ +@NonNullByDefault +public interface TimetableStopPredicate extends Predicate { + +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java index 96d1cf38639dc..9efa6b3132a15 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java +++ b/bundles/org.openhab.binding.deutschebahn/src/main/java/org/openhab/binding/deutschebahn/internal/timetable/TimetableLoader.java @@ -31,7 +31,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.deutschebahn.internal.EventAttribute; import org.openhab.binding.deutschebahn.internal.EventType; -import org.openhab.binding.deutschebahn.internal.TimetableStopFilter; +import org.openhab.binding.deutschebahn.internal.filter.TimetableStopPredicate; import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; import org.openhab.binding.deutschebahn.internal.timetable.dto.Timetable; import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; @@ -60,7 +60,7 @@ public final class TimetableLoader { private final Map cachedChanges; private final TimetablesV1Api api; - private final TimetableStopFilter stopFilter; + private final TimetableStopPredicate stopPredicate; private final TimetableStopComparator comparator; private final Supplier currentTimeProvider; private int stopCount; @@ -76,14 +76,15 @@ public final class TimetableLoader { * Creates an new {@link TimetableLoader}. * * @param api {@link TimetablesV1Api} to use. - * @param stopFilter Filter for selection of loaded {@link TimetableStop}. + * @param stopPredicate Filter for selection of loaded {@link TimetableStop}. * @param requestedStopCount Count of stops to be loaded on each call. * @param currentTimeProvider {@link Supplier} for the current time. */ - public TimetableLoader(final TimetablesV1Api api, final TimetableStopFilter stopFilter, final EventType eventToSort, - final Supplier currentTimeProvider, final String evaNo, final int requestedStopCount) { + public TimetableLoader(final TimetablesV1Api api, final TimetableStopPredicate stopPredicate, + final EventType eventToSort, final Supplier currentTimeProvider, final String evaNo, + final int requestedStopCount) { this.api = api; - this.stopFilter = stopFilter; + this.stopPredicate = stopPredicate; this.currentTimeProvider = currentTimeProvider; this.evaNo = evaNo; this.stopCount = requestedStopCount; @@ -206,7 +207,7 @@ private void updatePlan(final Date currentTime) throws IOException { final List stops = timetable // .getS() // .stream() // - .filter(this.stopFilter) // + .filter(this.stopPredicate) // .collect(Collectors.toList()); // Merge the loaded stops with the cached changes and put them into the plan cache. diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml index d85a7c028ebac..18eebbe775a25 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/thing/thing-types.xml @@ -32,6 +32,11 @@ + + true + + Specifies additional filters for trains, that should be displayed within the timetable. + diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java index 1f11a0891b56c..fa5929f4a202e 100644 --- a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/EventAttributeTest.java @@ -18,6 +18,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.Arrays; import java.util.GregorianCalendar; import java.util.List; import java.util.function.Consumer; @@ -218,24 +219,32 @@ public void testChangedFinalStation() { public void testPlannedIntermediateStations() { String expectedFollowing = "Bielefeld Hbf - Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf"; doTestEventAttribute("planned-intermediate-stations", "planned-following-stations", - (Event e) -> e.setPpth(SAMPLE_PATH), expectedFollowing, new StringType(expectedFollowing), - EventType.DEPARTURE, false); + (Event e) -> e.setPpth(SAMPLE_PATH), + Arrays.asList("Bielefeld Hbf", "Herford", "Löhne(Westf)", "Bad Oeynhausen", "Porta Westfalica", + "Minden(Westf)", "Bückeburg", "Stadthagen", "Haste", "Wunstorf", "Hannover Hbf"), + new StringType(expectedFollowing), EventType.DEPARTURE, false); String expectedPrevious = "Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf - Lehrte"; doTestEventAttribute("planned-intermediate-stations", "planned-previous-stations", - (Event e) -> e.setPpth(SAMPLE_PATH), expectedPrevious, new StringType(expectedPrevious), - EventType.ARRIVAL, false); + (Event e) -> e.setPpth(SAMPLE_PATH), + Arrays.asList("Herford", "Löhne(Westf)", "Bad Oeynhausen", "Porta Westfalica", "Minden(Westf)", + "Bückeburg", "Stadthagen", "Haste", "Wunstorf", "Hannover Hbf", "Lehrte"), + new StringType(expectedPrevious), EventType.ARRIVAL, false); } @Test public void testChangedIntermediateStations() { String expectedFollowing = "Bielefeld Hbf - Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf"; doTestEventAttribute("changed-intermediate-stations", "changed-following-stations", - (Event e) -> e.setCpth(SAMPLE_PATH), expectedFollowing, new StringType(expectedFollowing), - EventType.DEPARTURE, false); + (Event e) -> e.setCpth(SAMPLE_PATH), + Arrays.asList("Bielefeld Hbf", "Herford", "Löhne(Westf)", "Bad Oeynhausen", "Porta Westfalica", + "Minden(Westf)", "Bückeburg", "Stadthagen", "Haste", "Wunstorf", "Hannover Hbf"), + new StringType(expectedFollowing), EventType.DEPARTURE, false); String expectedPrevious = "Herford - Löhne(Westf) - Bad Oeynhausen - Porta Westfalica - Minden(Westf) - Bückeburg - Stadthagen - Haste - Wunstorf - Hannover Hbf - Lehrte"; doTestEventAttribute("changed-intermediate-stations", "changed-previous-stations", - (Event e) -> e.setCpth(SAMPLE_PATH), expectedPrevious, new StringType(expectedPrevious), - EventType.ARRIVAL, false); + (Event e) -> e.setCpth(SAMPLE_PATH), + Arrays.asList("Herford", "Löhne(Westf)", "Bad Oeynhausen", "Porta Westfalica", "Minden(Westf)", + "Bückeburg", "Stadthagen", "Haste", "Wunstorf", "Hannover Hbf", "Lehrte"), + new StringType(expectedPrevious), EventType.ARRIVAL, false); } @Test diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserTest.java new file mode 100644 index 0000000000000..813cc81cad962 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterParserTest.java @@ -0,0 +1,284 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.AttributeSelection; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.EventAttributeSelection; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.TripLabelAttribute; + +/** + * Tests for {@link FilterParser} + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public class FilterParserTest { + + private static final class FilterTokenSequenceBuilder { + + private final List tokens = new ArrayList<>(); + private int position = 0; + + private int getPos() { + this.position++; + return this.position; + } + + public List build() { + return this.tokens; + } + + public FilterTokenSequenceBuilder and() { + this.tokens.add(new AndOperator(getPos())); + return this; + } + + public FilterTokenSequenceBuilder or() { + this.tokens.add(new OrOperator(getPos())); + return this; + } + + public FilterTokenSequenceBuilder bracketOpen() { + this.tokens.add(new BracketOpenToken(getPos())); + return this; + } + + public FilterTokenSequenceBuilder bracketClose() { + this.tokens.add(new BracketCloseToken(getPos())); + return this; + } + + public ChannelNameEquals channelFilter(String channelGroup, String channelName, String pattern) { + ChannelNameEquals channelNameEquals = new ChannelNameEquals(getPos(), channelGroup, channelName, + Pattern.compile(pattern)); + this.tokens.add(channelNameEquals); + return channelNameEquals; + } + + public FilterTokenSequenceBuilder channelFilter(ChannelNameEquals equals) { + this.tokens.add(equals); + return this; + } + } + + private static FilterTokenSequenceBuilder builder() { + return new FilterTokenSequenceBuilder(); + } + + private static void checkAttributeFilter(TimetableStopPredicate predicate, ChannelNameEquals channelEquals, + EventType eventType, EventAttribute eventAttribute) { + checkAttributeFilter(predicate, channelEquals, new EventAttributeSelection(eventType, eventAttribute)); + } + + private static void checkAttributeFilter(TimetableStopPredicate predicate, ChannelNameEquals channelEquals, + AttributeSelection attributeSelection) { + assertThat(predicate, is(instanceOf(TimetableStopByStringEventAttributeFilter.class))); + TimetableStopByStringEventAttributeFilter attributeFilter = (TimetableStopByStringEventAttributeFilter) predicate; + assertThat(attributeFilter.getFilter(), is(channelEquals.getFilterValue())); + assertThat(attributeFilter.getAttributeSelection(), is(attributeSelection)); + } + + private static OrPredicate assertOr(TimetableStopPredicate predicate) { + assertThat(predicate, is(instanceOf(OrPredicate.class))); + return (OrPredicate) predicate; + } + + private static AndPredicate assertAnd(TimetableStopPredicate predicate) { + assertThat(predicate, is(instanceOf(AndPredicate.class))); + return (AndPredicate) predicate; + } + + @Test + public void testParseSimple() throws FilterParserException { + final List input = new ArrayList<>(); + ChannelNameEquals channelEquals = new ChannelNameEquals(1, "trip", "number", Pattern.compile("20")); + input.add(channelEquals); + final TimetableStopPredicate result = FilterParser.parse(input); + checkAttributeFilter(result, channelEquals, TripLabelAttribute.N); + } + + @Test + public void testParseAnd() throws FilterParserException { + final FilterTokenSequenceBuilder b = builder(); + final ChannelNameEquals channelEquals01 = b.channelFilter("trip", "number", "20"); + b.and(); + final ChannelNameEquals channelEquals02 = b.channelFilter("trip", "number", "30"); + final TimetableStopPredicate result = FilterParser.parse(b.build()); + final AndPredicate andPredicate = assertAnd(result); + + checkAttributeFilter(andPredicate.getFirst(), channelEquals01, TripLabelAttribute.N); + checkAttributeFilter(andPredicate.getSecond(), channelEquals02, TripLabelAttribute.N); + } + + @Test + public void testParseOr() throws FilterParserException { + final FilterTokenSequenceBuilder b = builder(); + final ChannelNameEquals channelEquals01 = b.channelFilter("trip", "number", "20"); + b.or(); + final ChannelNameEquals channelEquals02 = b.channelFilter("trip", "number", "30"); + final TimetableStopPredicate result = FilterParser.parse(b.build()); + final OrPredicate orPredicate = assertOr(result); + + checkAttributeFilter(orPredicate.getFirst(), channelEquals01, TripLabelAttribute.N); + checkAttributeFilter(orPredicate.getSecond(), channelEquals02, TripLabelAttribute.N); + } + + @Test + public void testParseWithBrackets() throws FilterParserException { + final FilterTokenSequenceBuilder b = new FilterTokenSequenceBuilder(); + final ChannelNameEquals channelEquals01 = b.channelFilter("trip", "number", "20"); + b.and(); + b.bracketOpen(); + final ChannelNameEquals channelEquals02 = b.channelFilter("departure", "line", "RE10"); + b.or(); + final ChannelNameEquals channelEquals03 = b.channelFilter("departure", "line", "RE20"); + b.bracketClose(); + final List input = b.build(); + + final TimetableStopPredicate result = FilterParser.parse(input); + final AndPredicate andPredicate = assertAnd(result); + + checkAttributeFilter(andPredicate.getFirst(), channelEquals01, TripLabelAttribute.N); + final OrPredicate orPredicate = assertOr(andPredicate.getSecond()); + + checkAttributeFilter(orPredicate.getFirst(), channelEquals02, EventType.DEPARTURE, EventAttribute.L); + checkAttributeFilter(orPredicate.getSecond(), channelEquals03, EventType.DEPARTURE, EventAttribute.L); + } + + @Test + public void testParseWithMultipleBrackets() throws FilterParserException { + final FilterTokenSequenceBuilder b = builder(); + b.bracketOpen(); + b.bracketOpen(); + final ChannelNameEquals channelEquals01 = b.channelFilter("trip", "number", "20"); + b.and(); + final ChannelNameEquals channelEquals02 = b.channelFilter("departure", "line", "RE22"); + b.bracketClose(); + b.or(); + b.bracketOpen(); + final ChannelNameEquals channelEquals03 = b.channelFilter("trip", "number", "30"); + b.and(); + final ChannelNameEquals channelEquals04 = b.channelFilter("departure", "line", "RE33"); + b.bracketClose(); + b.bracketClose(); + + final List input = b.build(); + + final TimetableStopPredicate result = FilterParser.parse(input); + final OrPredicate orPredicate = assertOr(result); + + final AndPredicate firstAnd = assertAnd(orPredicate.getFirst()); + checkAttributeFilter(firstAnd.getFirst(), channelEquals01, TripLabelAttribute.N); + checkAttributeFilter(firstAnd.getSecond(), channelEquals02, EventType.DEPARTURE, EventAttribute.L); + + final AndPredicate secondAnd = assertAnd(orPredicate.getSecond()); + checkAttributeFilter(secondAnd.getFirst(), channelEquals03, TripLabelAttribute.N); + checkAttributeFilter(secondAnd.getSecond(), channelEquals04, EventType.DEPARTURE, EventAttribute.L); + } + + @Test + public void testParseErrors() { + final ChannelNameEquals channelEquals = new ChannelNameEquals(1, "trip", "number", Pattern.compile("20")); + try { + FilterParser.parse(Collections.emptyList()); + fail(); + } catch (FilterParserException e) { + } + + try { + FilterParser.parse(builder().and().build()); + fail(); + } catch (FilterParserException e) { + } + + try { + FilterParser.parse(builder().or().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().bracketOpen().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().bracketClose().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().bracketOpen().bracketClose().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().bracketOpen().and().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().bracketOpen().and().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).and().bracketOpen().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).and().bracketClose().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).or().bracketOpen().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).or().bracketClose().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).and().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(builder().channelFilter(channelEquals).or().build()); + fail(); + } catch (FilterParserException e) { + } + try { + FilterParser.parse(Arrays.asList(channelEquals, channelEquals)); + fail(); + } catch (FilterParserException e) { + } + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerTest.java new file mode 100644 index 0000000000000..68fc3fbf122b1 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/FilterScannerTest.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link FilterScanner} + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public class FilterScannerTest { + + private static void assertAttributeEquals(FilterToken token, String expectedChannelGroup, + String expectedChannelName, String expectedFilter, int expectedPosition) { + assertThat(token, is(instanceOf(ChannelNameEquals.class))); + ChannelNameEquals actual = (ChannelNameEquals) token; + assertThat(actual.getChannelGroup(), is(expectedChannelGroup)); + assertThat(actual.getChannelName(), is(expectedChannelName)); + assertThat(actual.getFilterValue().toString(), is(expectedFilter)); + assertThat(actual.getPosition(), is(expectedPosition)); + } + + private static void assertOperator(FilterToken token, OperatorToken expected) { + assertThat(token.getClass(), is(expected.getClass())); + assertThat(token.getPosition(), is(expected.getPosition())); + } + + private static List processInput(String input, int expectedCount) throws FilterScannerException { + final List tokens = new FilterScanner().processInput(input); + assertThat(tokens, hasSize(expectedCount)); + return tokens; + } + + @Test + public void testSimpleAttributEquals() throws FilterScannerException { + String input = "trip#number=\"20\""; + List tokens = processInput(input, 1); + assertAttributeEquals(tokens.get(0), "trip", "number", "20", 1); + } + + @Test + public void testAttributeEqualsWithWhitespace() throws FilterScannerException { + String input = "departure#planned-path=\"Hannover Hbf\""; + List tokens = processInput(input, 1); + assertAttributeEquals(tokens.get(0), "departure", "planned-path", "Hannover Hbf", 1); + } + + @Test + public void testInvalidAttributEquals() { + try { + new FilterScanner().processInput("trip#number=20"); + fail(); + } catch (FilterScannerException e) { + } + + try { + new FilterScanner().processInput("trip#number"); + fail(); + } catch (FilterScannerException e) { + } + + try { + new FilterScanner().processInput("trip#number="); + fail(); + } catch (FilterScannerException e) { + } + + try { + new FilterScanner().processInput("=abc"); + fail(); + } catch (FilterScannerException e) { + } + + try { + new FilterScanner().processInput("train#number=\"abc\""); + fail(); + } catch (FilterScannerException e) { + } + } + + @Test + public void testComplexExample() throws FilterScannerException { + String input = "trip#category=\"RE\" & (departure#line=\"17\" | departure#line=\"57\") & departure#planned-path=\"Cologne\""; + List tokens = processInput(input, 9); + assertAttributeEquals(tokens.get(0), "trip", "category", "RE", 1); + assertOperator(tokens.get(1), new AndOperator(20)); + assertOperator(tokens.get(2), new BracketOpenToken(22)); + assertAttributeEquals(tokens.get(3), "departure", "line", "17", 23); + assertOperator(tokens.get(4), new OrOperator(43)); + assertAttributeEquals(tokens.get(5), "departure", "line", "57", 45); + assertOperator(tokens.get(6), new BracketCloseToken(64)); + assertOperator(tokens.get(7), new AndOperator(66)); + assertAttributeEquals(tokens.get(8), "departure", "planned-path", "Cologne", 68); + } +} diff --git a/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/TimetableByStringEventAttributeFilterTest.java b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/TimetableByStringEventAttributeFilterTest.java new file mode 100644 index 0000000000000..3a799be43b687 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/test/java/org/openhab/binding/deutschebahn/internal/filter/TimetableByStringEventAttributeFilterTest.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.deutschebahn.internal.filter; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.deutschebahn.internal.EventAttribute; +import org.openhab.binding.deutschebahn.internal.EventAttributeSelection; +import org.openhab.binding.deutschebahn.internal.EventType; +import org.openhab.binding.deutschebahn.internal.TripLabelAttribute; +import org.openhab.binding.deutschebahn.internal.timetable.dto.Event; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TimetableStop; +import org.openhab.binding.deutschebahn.internal.timetable.dto.TripLabel; + +/** + * Tests for {@link TimetableStopByStringEventAttributeFilter} + * + * @author Sönke Küper - Initial contribution. + */ +@NonNullByDefault +public final class TimetableByStringEventAttributeFilterTest { + + @Test + public void testFilterTripLabelAttribute() { + final TimetableStopByStringEventAttributeFilter filter = new TimetableStopByStringEventAttributeFilter( + TripLabelAttribute.C, Pattern.compile("IC.*")); + final TimetableStop stop = new TimetableStop(); + + // TripLabel is not set -> does not match + assertFalse(filter.test(stop)); + + final TripLabel label = new TripLabel(); + stop.setTl(label); + + // Attribute is not set -> does not match + assertFalse(filter.test(stop)); + + // Set attribute -> matches depending on value + label.setC("RE"); + assertFalse(filter.test(stop)); + label.setC("ICE"); + assertTrue(filter.test(stop)); + label.setC("IC"); + assertTrue(filter.test(stop)); + } + + @Test + public void testFilterEventAttribute() { + final EventAttributeSelection eventAttribute = new EventAttributeSelection(EventType.DEPARTURE, + EventAttribute.L); + final TimetableStopByStringEventAttributeFilter filter = new TimetableStopByStringEventAttributeFilter( + eventAttribute, Pattern.compile("RE.*")); + final TimetableStop stop = new TimetableStop(); + + // Event is not set -> does not match + assertFalse(filter.test(stop)); + + Event event = new Event(); + stop.setDp(event); + + // Attribute is not set -> does not match + assertFalse(filter.test(stop)); + + // Set attribute -> matches depending on value + event.setL("S5"); + assertFalse(filter.test(stop)); + event.setL("5"); + assertFalse(filter.test(stop)); + event.setL("RE60"); + assertTrue(filter.test(stop)); + + // Set wrong event + stop.setAr(event); + stop.setDp(null); + assertFalse(filter.test(stop)); + } + + @Test + public void testFilterEventAttributeList() { + final EventAttributeSelection eventAttribute = new EventAttributeSelection(EventType.DEPARTURE, + EventAttribute.PPTH); + final TimetableStopByStringEventAttributeFilter filter = new TimetableStopByStringEventAttributeFilter( + eventAttribute, Pattern.compile("Hannover.*")); + final TimetableStop stop = new TimetableStop(); + Event event = new Event(); + stop.setDp(event); + + event.setPpth("Hannover Hbf|Hannover-Kleefeld|Hannover Karl-Wiechert-Allee|Hannover Anderten-Misburg|Ahlten"); + assertTrue(filter.test(stop)); + event.setPpth( + "Ahlten|Hannover Hbf|Hannover-Kleefeld|Hannover Karl-Wiechert-Allee|Hannover Anderten-Misburg|Ahlten"); + assertTrue(filter.test(stop)); + event.setPpth( + "Wolfsburg Hbf|Fallersleben|Calberlah|Gifhorn|Leiferde(b Gifhorn)|Meinersen|Dedenhausen|Dollbergen|Immensen-Arpke"); + assertFalse(filter.test(stop)); + } +} From 0dca2594b5d47e9913ec035e5169a068bd3fd330 Mon Sep 17 00:00:00 2001 From: pali Date: Sun, 12 Dec 2021 23:09:36 +0200 Subject: [PATCH 224/361] [js-transform] inline java script support (#11473) * [js-transform] inline java script support Signed-off-by: Pauli Anttila Signed-off-by: Michael Schmidt --- .../README.md | 8 +++ .../internal/JavaScriptEngineManager.java | 45 ++++++++++++++- .../JavaScriptTransformationService.java | 56 +++++++++++-------- .../OH-INF/config/javascriptProfile.xml | 6 +- .../JavaScriptTransformationServiceTest.java | 18 ++++++ 5 files changed, 105 insertions(+), 28 deletions(-) diff --git a/bundles/org.openhab.transform.javascript/README.md b/bundles/org.openhab.transform.javascript/README.md index a0d7d0ce84726..1ca1c5c9624e4 100644 --- a/bundles/org.openhab.transform.javascript/README.md +++ b/bundles/org.openhab.transform.javascript/README.md @@ -5,6 +5,10 @@ Transform an input to an output using JavaScript. It expects the transformation rule to be read from a file which is stored under the `transform` folder. To organize the various transformations, one should use subfolders. +Simple transformation rules can also be given as a inline script. +Inline script should be start by `|` character following the JavaScript. +Beware that complex inline script could cause issues to e.g. item file parsing. + ## Examples Let's assume we have received a string containing `foo bar baz` and we're looking for a length of the last word (`baz`). @@ -37,6 +41,10 @@ transform/scale.js: Following example will return value `23.54` when `input` data is `214`. +### Inline script example: + +Normally JavaScript transformation is given by filename, e.g. `JS(transform/getValue.js)`. +Inline script can be given by `|` character following the JavaScript, e.g. `JS(| input / 10)`. ## Test JavaScript diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java index 97ec03dad3ab4..d7dd93d657157 100644 --- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java +++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptEngineManager.java @@ -17,6 +17,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.util.Base64; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -27,6 +32,7 @@ import javax.script.ScriptException; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.cache.ExpiringCacheMap; import org.openhab.core.transform.TransformationException; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; @@ -46,6 +52,8 @@ public class JavaScriptEngineManager { private final ScriptEngineManager manager = new ScriptEngineManager(); /* keep memory foot print low. max 2 concurrent threads are estimated */ private final Map compiledScriptMap = new ConcurrentHashMap<>(4, 0.5f, 2); + private final ExpiringCacheMap cacheForInlineScripts = new ExpiringCacheMap<>( + Duration.ofDays(1)); /** * Get a pre compiled script {@link CompiledScript} from cache. If it is not in the cache, then load it from @@ -55,7 +63,7 @@ public class JavaScriptEngineManager { * @return a pre compiled script {@link CompiledScript} * @throws TransformationException if compile of JavaScript failed */ - protected CompiledScript getScript(final String filename) throws TransformationException { + protected CompiledScript getCompiledScriptByFilename(final String filename) throws TransformationException { synchronized (compiledScriptMap) { CompiledScript compiledScript = compiledScriptMap.get(filename); if (compiledScript != null) { @@ -78,6 +86,35 @@ protected CompiledScript getScript(final String filename) throws TransformationE } } + /** + * Get a pre compiled script {@link CompiledScript} from cache. If it is not in the cache, then compile + * it and put a pre compiled version into the cache. + * + * @param script JavaScript which should be returned as a pre compiled + * @return a pre compiled script {@link CompiledScript} + * @throws TransformationException if compile of JavaScript failed + */ + protected CompiledScript getCompiledScriptByInlineScript(final String script) throws TransformationException { + synchronized (cacheForInlineScripts) { + try { + final String hash = calcHash(script); + final CompiledScript compiledScript = cacheForInlineScripts.get(hash); + if (compiledScript != null) { + logger.debug("Loading JavaScript from cache."); + return compiledScript; + } else { + logger.debug("Compiling script {}", script); + final ScriptEngine engine = manager.getEngineByName("javascript"); + final CompiledScript cScript = ((Compilable) engine).compile(script); + cacheForInlineScripts.put(hash, () -> cScript); + return cScript; + } + } catch (ScriptException | NoSuchAlgorithmException e) { + throw new TransformationException("An error occurred while compiling JavaScript. " + e.getMessage(), e); + } + } + } + /** * remove a pre compiled script from cache. * @@ -87,4 +124,10 @@ protected void removeFromCache(String fileName) { logger.debug("Removing JavaScript {} from cache.", fileName); compiledScriptMap.remove(fileName); } + + private String calcHash(final String script) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(script.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(hash); + } } diff --git a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java index 7a712568c2449..2294d11bf1b83 100644 --- a/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java +++ b/bundles/org.openhab.transform.javascript/src/main/java/org/openhab/transform/javascript/internal/JavaScriptTransformationService.java @@ -71,47 +71,55 @@ public JavaScriptTransformationService(final @Reference JavaScriptEngineManager } /** - * Transforms the input source by Java Script. It expects the + * Transforms the input source by Java Script. If script is a filename, it expects the * transformation rule to be read from a file which is stored under the * 'configurations/transform' folder. To organize the various * transformations one should use subfolders. * - * @param filename the name of the file which contains the Java script + * @param filenameOrInlineScript parameter can be 1) the name of the file which contains the Java script * transformation rule. Filename can also include additional * variables in URI query variable format which will be injected - * to script engine. Transformation service inject input (source) - * to 'input' variable. + * to script engine. 2) inline script when starting with '|' character. + * Transformation service inject input (source) to 'input' variable. * @param source the input to transform */ @Override - public @Nullable String transform(String filename, String source) throws TransformationException { + public @Nullable String transform(String filenameOrInlineScript, String source) throws TransformationException { final long startTime = System.currentTimeMillis(); - logger.debug("about to transform '{}' by the JavaScript '{}'", source, filename); + logger.debug("about to transform '{}' by the JavaScript '{}'", source, filenameOrInlineScript); Map vars = Collections.emptyMap(); - String fn = filename; + String result = ""; - if (filename.contains("?")) { - String[] parts = filename.split("\\?"); - if (parts.length > 2) { - throw new TransformationException("Questionmark should be defined only once in the filename"); - } - fn = parts[0]; - try { - vars = splitQuery(parts[1]); - } catch (UnsupportedEncodingException e) { - throw new TransformationException("Illegal filename syntax"); - } - if (isReservedWordUsed(vars)) { - throw new TransformationException( - "'" + SCRIPT_DATA_WORD + "' word is reserved and can't be used in additional parameters"); + CompiledScript cScript; + + if (filenameOrInlineScript.startsWith("|")) { + // inline java script + cScript = manager.getCompiledScriptByInlineScript(filenameOrInlineScript.substring(1)); + } else { + String filename = filenameOrInlineScript; + + if (filename.contains("?")) { + String[] parts = filename.split("\\?"); + if (parts.length > 2) { + throw new TransformationException("Questionmark should be defined only once in the filename"); + } + filename = parts[0]; + try { + vars = splitQuery(parts[1]); + } catch (UnsupportedEncodingException e) { + throw new TransformationException("Illegal filename syntax"); + } + if (isReservedWordUsed(vars)) { + throw new TransformationException( + "'" + SCRIPT_DATA_WORD + "' word is reserved and can't be used in additional parameters"); + } } - } - String result = ""; + cScript = manager.getCompiledScriptByFilename(filename); + } try { - final CompiledScript cScript = manager.getScript(fn); final Bindings bindings = cScript.getEngine().createBindings(); bindings.put(SCRIPT_DATA_WORD, source); vars.forEach((k, v) -> bindings.put(k, v)); diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml index 9bae0c235c660..ad4f046ce11dc 100644 --- a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/config/javascriptProfile.xml @@ -6,9 +6,9 @@ - - Filename of the JavaScript in the transform folder. The state will be available in the variable - \"input\". + + Filename of the JavaScript in the transform folder or inline script starting with "|" character. The + state will be available in the variable "input". false diff --git a/bundles/org.openhab.transform.javascript/src/test/java/org/openhab/transform/javascript/internal/JavaScriptTransformationServiceTest.java b/bundles/org.openhab.transform.javascript/src/test/java/org/openhab/transform/javascript/internal/JavaScriptTransformationServiceTest.java index f379b7e6c4dd2..33751571c666b 100644 --- a/bundles/org.openhab.transform.javascript/src/test/java/org/openhab/transform/javascript/internal/JavaScriptTransformationServiceTest.java +++ b/bundles/org.openhab.transform.javascript/src/test/java/org/openhab/transform/javascript/internal/JavaScriptTransformationServiceTest.java @@ -78,6 +78,24 @@ private void copyDirectory(String from, String to) throws IOException { }); } + @Test + public void testInlineScript() throws Exception { + final String DATA = "100"; + final String SCRIPT = "| input / 10"; + + String transformedResponse = processor.transform(SCRIPT, DATA); + assertEquals("10.0", transformedResponse); + } + + @Test + public void testInlineScriptIncludingPipe() throws Exception { + final String DATA = "1"; + final String SCRIPT = "| false || (input == '1')"; + + String transformedResponse = processor.transform(SCRIPT, DATA); + assertEquals("true", transformedResponse); + } + @Test public void testReadmeExampleWithoutSubFolder() throws Exception { final String DATA = "foo bar baz"; From 96174b7111eb0622f564972c07d59c7243587ac1 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 12 Dec 2021 22:10:51 +0100 Subject: [PATCH 225/361] [miio] Improve Viomi vacuums, add docking and route channel & mapping (#11763) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 60 ++-- .../resources/OH-INF/i18n/basic.properties | 62 +++- .../resources/database/viomi.vacuum.v8.json | 326 +++++++++++++++++- 3 files changed, 408 insertions(+), 40 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 11ef52ce5fc98..c8710106f295d 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -2415,60 +2415,63 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | -| state | Number | State | | -| mode | Number | Mode | | -| err_state | Number | Error | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause","3"="Dock"]` | +| state | Number | State | Value mapping `["0"="Idle Undocked","1"="Idle","2"="Paused","3"="Sweeping","4"="Go Charging","5"="Charging","6"="Sweeping and Mopping","7"="Mopping"]` | +| mode | Number | Clean Mode | Value mapping `["0"="Everywhere","1"="Edges","2"="Surface","3"="Fixed Location"]` | +| err_state | Number | Error | Value mapping `["0"="Sleeping and not charging","500"="Radar timed out","501"="Wheels stuck","502"="Low battery","503"="Dust bin missing","508"="Uneven ground","509"="Cliff sensor erro","510"="Collision sensor error","511"="Could not return to dock","512"="Could not return to dock","513"="Could not navigate","514"="Vacuum stuck","515"="Charging erro","516"="Mop temperature error","521"="Water tank is not installed","522"="Mop is not installed","525"="Insufficient water in water tank","527"="Remove mop","528"="Dust bin missing","529"="Mop and water tank missing","530"="Mop and water tank missin","531"="Water tank is not installed","2101"="Unsufficient battery, continuing cleaning after recharge","2103"="Charging","2104"="Fully charged"]` | | battery_life | Number | Battery | | -| box_type | Number | Box type | | +| box_type | Number | Box type | Value mapping `["0"="No Bin","1"="Sweep","2"="Mop","3"="Sweep and Mop"]` | | mop_type | Number | mop_type | | +| mop_route | Number | Mop Route | Value mapping `["0"="S-Pattern","1"="Y-Pattern"]` | | s_time | Number | Clean time | | | s_area | Number | Clean Area | | -| suction_grade | Number | suction_grade | | -| water_grade | Number | water_grade | | +| suction_grade | Number | suction_grade | Value mapping `["0"="Silent","1"="Basic","2"="Medium","3"="Strong"]` | +| water_grade | Number | water_grade | Value mapping `["11"="Low","12"="Medium","13"="High"]` | | remember_map | Number | remember_map | | | has_map | Number | has_map | | -| is_mop | Number | is_mop | | +| is_mop | Number | is_mop | Value mapping `["0"="Vacuum","1"="Vacuum And Mop","2"="Mop","3"="CleanZone","4"="CleanSpot"]` | | has_newmap | Number | has_newmap | | ### Mi Robot Vacuum-Mop P (viomi.vacuum.v7) Channels | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | -| state | Number | State | | -| mode | Number | Mode | | -| err_state | Number | Error | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause","3"="Dock"]` | +| state | Number | State | Value mapping `["0"="Idle Undocked","1"="Idle","2"="Paused","3"="Sweeping","4"="Go Charging","5"="Charging","6"="Sweeping and Mopping","7"="Mopping"]` | +| mode | Number | Clean Mode | Value mapping `["0"="Everywhere","1"="Edges","2"="Surface","3"="Fixed Location"]` | +| err_state | Number | Error | Value mapping `["0"="Sleeping and not charging","500"="Radar timed out","501"="Wheels stuck","502"="Low battery","503"="Dust bin missing","508"="Uneven ground","509"="Cliff sensor erro","510"="Collision sensor error","511"="Could not return to dock","512"="Could not return to dock","513"="Could not navigate","514"="Vacuum stuck","515"="Charging erro","516"="Mop temperature error","521"="Water tank is not installed","522"="Mop is not installed","525"="Insufficient water in water tank","527"="Remove mop","528"="Dust bin missing","529"="Mop and water tank missing","530"="Mop and water tank missin","531"="Water tank is not installed","2101"="Unsufficient battery, continuing cleaning after recharge","2103"="Charging","2104"="Fully charged"]` | | battery_life | Number | Battery | | -| box_type | Number | Box type | | +| box_type | Number | Box type | Value mapping `["0"="No Bin","1"="Sweep","2"="Mop","3"="Sweep and Mop"]` | | mop_type | Number | mop_type | | +| mop_route | Number | Mop Route | Value mapping `["0"="S-Pattern","1"="Y-Pattern"]` | | s_time | Number | Clean time | | | s_area | Number | Clean Area | | -| suction_grade | Number | suction_grade | | -| water_grade | Number | water_grade | | +| suction_grade | Number | suction_grade | Value mapping `["0"="Silent","1"="Basic","2"="Medium","3"="Strong"]` | +| water_grade | Number | water_grade | Value mapping `["11"="Low","12"="Medium","13"="High"]` | | remember_map | Number | remember_map | | | has_map | Number | has_map | | -| is_mop | Number | is_mop | | +| is_mop | Number | is_mop | Value mapping `["0"="Vacuum","1"="Vacuum And Mop","2"="Mop","3"="CleanZone","4"="CleanSpot"]` | | has_newmap | Number | has_newmap | | ### Mi Robot Vacuum-Mop P (viomi.vacuum.v8) Channels | Channel | Type | Description | Comment | |----------------------|----------------------|------------------------------------------|------------| -| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause"]` | -| state | Number | State | | -| mode | Number | Mode | | -| err_state | Number | Error | | +| vacuumaction | Number | Vacuum Action | Value mapping `["1"="Start","0"="Stop","2"="Pause","3"="Dock"]` | +| state | Number | State | Value mapping `["0"="Idle Undocked","1"="Idle","2"="Paused","3"="Sweeping","4"="Go Charging","5"="Charging","6"="Sweeping and Mopping","7"="Mopping"]` | +| mode | Number | Clean Mode | Value mapping `["0"="Everywhere","1"="Edges","2"="Surface","3"="Fixed Location"]` | +| err_state | Number | Error | Value mapping `["0"="Sleeping and not charging","500"="Radar timed out","501"="Wheels stuck","502"="Low battery","503"="Dust bin missing","508"="Uneven ground","509"="Cliff sensor erro","510"="Collision sensor error","511"="Could not return to dock","512"="Could not return to dock","513"="Could not navigate","514"="Vacuum stuck","515"="Charging erro","516"="Mop temperature error","521"="Water tank is not installed","522"="Mop is not installed","525"="Insufficient water in water tank","527"="Remove mop","528"="Dust bin missing","529"="Mop and water tank missing","530"="Mop and water tank missin","531"="Water tank is not installed","2101"="Unsufficient battery, continuing cleaning after recharge","2103"="Charging","2104"="Fully charged"]` | | battery_life | Number | Battery | | -| box_type | Number | Box type | | +| box_type | Number | Box type | Value mapping `["0"="No Bin","1"="Sweep","2"="Mop","3"="Sweep and Mop"]` | | mop_type | Number | mop_type | | +| mop_route | Number | Mop Route | Value mapping `["0"="S-Pattern","1"="Y-Pattern"]` | | s_time | Number | Clean time | | | s_area | Number | Clean Area | | -| suction_grade | Number | suction_grade | | -| water_grade | Number | water_grade | | +| suction_grade | Number | suction_grade | Value mapping `["0"="Silent","1"="Basic","2"="Medium","3"="Strong"]` | +| water_grade | Number | water_grade | Value mapping `["11"="Low","12"="Medium","13"="High"]` | | remember_map | Number | remember_map | | | has_map | Number | has_map | | -| is_mop | Number | is_mop | | +| is_mop | Number | is_mop | Value mapping `["0"="Vacuum","1"="Vacuum And Mop","2"="Mop","3"="CleanZone","4"="CleanSpot"]` | | has_newmap | Number | has_newmap | | ### Viomi S9 (viomi.vacuum.v18) Channels @@ -7716,11 +7719,12 @@ note: Autogenerated example. Replace the id (vacuum) in the channel with your ow Group G_vacuum "Viomi Cleaning Robot V-RVCLM21B" Number vacuumaction "Vacuum Action" (G_vacuum) {channel="miio:basic:vacuum:vacuumaction"} Number state "State" (G_vacuum) {channel="miio:basic:vacuum:state"} -Number mode "Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number mode "Clean Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} Number err_state "Error" (G_vacuum) {channel="miio:basic:vacuum:err_state"} Number battery_life "Battery" (G_vacuum) {channel="miio:basic:vacuum:battery_life"} Number box_type "Box type" (G_vacuum) {channel="miio:basic:vacuum:box_type"} Number mop_type "mop_type" (G_vacuum) {channel="miio:basic:vacuum:mop_type"} +Number mop_route "Mop Route" (G_vacuum) {channel="miio:basic:vacuum:mop_route"} Number s_time "Clean time" (G_vacuum) {channel="miio:basic:vacuum:s_time"} Number s_area "Clean Area" (G_vacuum) {channel="miio:basic:vacuum:s_area"} Number suction_grade "suction_grade" (G_vacuum) {channel="miio:basic:vacuum:suction_grade"} @@ -7739,11 +7743,12 @@ note: Autogenerated example. Replace the id (vacuum) in the channel with your ow Group G_vacuum "Mi Robot Vacuum-Mop P" Number vacuumaction "Vacuum Action" (G_vacuum) {channel="miio:basic:vacuum:vacuumaction"} Number state "State" (G_vacuum) {channel="miio:basic:vacuum:state"} -Number mode "Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number mode "Clean Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} Number err_state "Error" (G_vacuum) {channel="miio:basic:vacuum:err_state"} Number battery_life "Battery" (G_vacuum) {channel="miio:basic:vacuum:battery_life"} Number box_type "Box type" (G_vacuum) {channel="miio:basic:vacuum:box_type"} Number mop_type "mop_type" (G_vacuum) {channel="miio:basic:vacuum:mop_type"} +Number mop_route "Mop Route" (G_vacuum) {channel="miio:basic:vacuum:mop_route"} Number s_time "Clean time" (G_vacuum) {channel="miio:basic:vacuum:s_time"} Number s_area "Clean Area" (G_vacuum) {channel="miio:basic:vacuum:s_area"} Number suction_grade "suction_grade" (G_vacuum) {channel="miio:basic:vacuum:suction_grade"} @@ -7762,11 +7767,12 @@ note: Autogenerated example. Replace the id (vacuum) in the channel with your ow Group G_vacuum "Mi Robot Vacuum-Mop P" Number vacuumaction "Vacuum Action" (G_vacuum) {channel="miio:basic:vacuum:vacuumaction"} Number state "State" (G_vacuum) {channel="miio:basic:vacuum:state"} -Number mode "Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number mode "Clean Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} Number err_state "Error" (G_vacuum) {channel="miio:basic:vacuum:err_state"} Number battery_life "Battery" (G_vacuum) {channel="miio:basic:vacuum:battery_life"} Number box_type "Box type" (G_vacuum) {channel="miio:basic:vacuum:box_type"} Number mop_type "mop_type" (G_vacuum) {channel="miio:basic:vacuum:mop_type"} +Number mop_route "Mop Route" (G_vacuum) {channel="miio:basic:vacuum:mop_route"} Number s_time "Clean time" (G_vacuum) {channel="miio:basic:vacuum:s_time"} Number s_area "Clean Area" (G_vacuum) {channel="miio:basic:vacuum:s_area"} Number suction_grade "suction_grade" (G_vacuum) {channel="miio:basic:vacuum:suction_grade"} diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties index 124919afdbec3..e5ae9d8e859af 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties @@ -955,7 +955,8 @@ ch.viomi.vacuum.v8.err_state = Error ch.viomi.vacuum.v8.has_map = has_map ch.viomi.vacuum.v8.has_newmap = has_newmap ch.viomi.vacuum.v8.is_mop = is_mop -ch.viomi.vacuum.v8.mode = Mode +ch.viomi.vacuum.v8.mode = Clean Mode +ch.viomi.vacuum.v8.mop_route = Mop Route ch.viomi.vacuum.v8.mop_type = mop_type ch.viomi.vacuum.v8.remember_map = remember_map ch.viomi.vacuum.v8.s_area = Clean Area @@ -2074,6 +2075,65 @@ option.viomi.vacuum.v18-miot.water-grade-2 = 3 Blocks option.viomi.vacuum.v18-miot.wdr-mode-0 = Mode 0 option.viomi.vacuum.v18-miot.wdr-mode-1 = Mode 1 option.viomi.vacuum.v18-miot.wdr-mode-2 = Mode 2 +option.viomi.vacuum.v8.box_type-0 = No Bin +option.viomi.vacuum.v8.box_type-1 = Sweep +option.viomi.vacuum.v8.box_type-2 = Mop +option.viomi.vacuum.v8.box_type-3 = Sweep and Mop +option.viomi.vacuum.v8.err_state-0 = Sleeping and not charging +option.viomi.vacuum.v8.err_state-2101 = Unsufficient battery, continuing cleaning after recharge +option.viomi.vacuum.v8.err_state-2103 = Charging +option.viomi.vacuum.v8.err_state-2104 = Fully charged +option.viomi.vacuum.v8.err_state-500 = Radar timed out +option.viomi.vacuum.v8.err_state-501 = Wheels stuck +option.viomi.vacuum.v8.err_state-502 = Low battery +option.viomi.vacuum.v8.err_state-503 = Dust bin missing +option.viomi.vacuum.v8.err_state-508 = Uneven ground +option.viomi.vacuum.v8.err_state-509 = Cliff sensor erro +option.viomi.vacuum.v8.err_state-510 = Collision sensor error +option.viomi.vacuum.v8.err_state-511 = Could not return to dock +option.viomi.vacuum.v8.err_state-512 = Could not return to dock +option.viomi.vacuum.v8.err_state-513 = Could not navigate +option.viomi.vacuum.v8.err_state-514 = Vacuum stuck +option.viomi.vacuum.v8.err_state-515 = Charging erro +option.viomi.vacuum.v8.err_state-516 = Mop temperature error +option.viomi.vacuum.v8.err_state-521 = Water tank is not installed +option.viomi.vacuum.v8.err_state-522 = Mop is not installed +option.viomi.vacuum.v8.err_state-525 = Insufficient water in water tank +option.viomi.vacuum.v8.err_state-527 = Remove mop +option.viomi.vacuum.v8.err_state-528 = Dust bin missing +option.viomi.vacuum.v8.err_state-529 = Mop and water tank missing +option.viomi.vacuum.v8.err_state-530 = Mop and water tank missin +option.viomi.vacuum.v8.err_state-531 = Water tank is not installed +option.viomi.vacuum.v8.is_mop-0 = Vacuum +option.viomi.vacuum.v8.is_mop-1 = Vacuum And Mop +option.viomi.vacuum.v8.is_mop-2 = Mop +option.viomi.vacuum.v8.is_mop-3 = CleanZone +option.viomi.vacuum.v8.is_mop-4 = CleanSpot +option.viomi.vacuum.v8.mode-0 = Everywhere +option.viomi.vacuum.v8.mode-1 = Edges +option.viomi.vacuum.v8.mode-2 = Surface +option.viomi.vacuum.v8.mode-3 = Fixed Location +option.viomi.vacuum.v8.mop_route-0 = S-Pattern +option.viomi.vacuum.v8.mop_route-1 = Y-Pattern +option.viomi.vacuum.v8.state-0 = Idle Undocked +option.viomi.vacuum.v8.state-1 = Idle +option.viomi.vacuum.v8.state-2 = Paused +option.viomi.vacuum.v8.state-3 = Sweeping +option.viomi.vacuum.v8.state-4 = Go Charging +option.viomi.vacuum.v8.state-5 = Charging +option.viomi.vacuum.v8.state-6 = Sweeping and Mopping +option.viomi.vacuum.v8.state-7 = Mopping +option.viomi.vacuum.v8.suction_grade-0 = Silent +option.viomi.vacuum.v8.suction_grade-1 = Basic +option.viomi.vacuum.v8.suction_grade-2 = Medium +option.viomi.vacuum.v8.suction_grade-3 = Strong +option.viomi.vacuum.v8.vacuumaction-0 = Stop +option.viomi.vacuum.v8.vacuumaction-1 = Start +option.viomi.vacuum.v8.vacuumaction-2 = Pause +option.viomi.vacuum.v8.vacuumaction-3 = Dock +option.viomi.vacuum.v8.water_grade-11 = Low +option.viomi.vacuum.v8.water_grade-12 = Medium +option.viomi.vacuum.v8.water_grade-13 = High option.xiaomi.aircondition.ma1-miot.fan-level-0 = Auto option.xiaomi.aircondition.ma1-miot.fan-level-1 = Level1 option.xiaomi.aircondition.ma1-miot.fan-level-2 = Level2 diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json index 1a7de8e576dff..3c101f9ffbad3 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v8.json @@ -24,6 +24,10 @@ { "value": "2", "label": "Pause" + }, + { + "value": "3", + "label": "Dock" } ] }, @@ -36,24 +40,110 @@ 0, "$value$", 0 - ] + ], + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "0" + }, + { + "matchValue": "1" + }, + { + "matchValue": "2" + } + ] + } + }, + { + "command": "set_charge", + "parameterType": "NUMBER", + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "3", + "returnValue": 1 + } + ] + } } ], - "readmeComment": "Value mapping `[\"1\"\u003d\"Start\",\"0\"\u003d\"Stop\",\"2\"\u003d\"Pause\"]`" + "readmeComment": "Value mapping `[\"1\"\u003d\"Start\",\"0\"\u003d\"Stop\",\"2\"\u003d\"Pause\",\"3\"\u003d\"Dock\"]`" }, { "property": "run_state", "friendlyName": "State", "channel": "state", "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Idle Undocked" + }, + { + "value": "1", + "label": "Idle" + }, + { + "value": "2", + "label": "Paused" + }, + { + "value": "3", + "label": "Sweeping" + }, + { + "value": "4", + "label": "Go Charging" + }, + { + "value": "5", + "label": "Charging" + }, + { + "value": "6", + "label": "Sweeping and Mopping" + }, + { + "value": "7", + "label": "Mopping" + } + ] + }, "refresh": true, - "actions": [] + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Idle Undocked\",\"1\"\u003d\"Idle\",\"2\"\u003d\"Paused\",\"3\"\u003d\"Sweeping\",\"4\"\u003d\"Go Charging\",\"5\"\u003d\"Charging\",\"6\"\u003d\"Sweeping and Mopping\",\"7\"\u003d\"Mopping\"]`" }, { "property": "mode", - "friendlyName": "Mode", + "friendlyName": "Clean Mode", "channel": "mode", "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Everywhere" + }, + { + "value": "1", + "label": "Edges" + }, + { + "value": "2", + "label": "Surface" + }, + { + "value": "3", + "label": "Fixed Location" + } + ] + }, "refresh": true, "actions": [ { @@ -63,15 +153,122 @@ ], "tags": [ "Control" - ] + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Everywhere\",\"1\"\u003d\"Edges\",\"2\"\u003d\"Surface\",\"3\"\u003d\"Fixed Location\"]`" }, { "property": "err_state", "friendlyName": "Error", "channel": "err_state", "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "Sleeping and not charging" + }, + { + "value": "500", + "label": "Radar timed out" + }, + { + "value": "501", + "label": "Wheels stuck" + }, + { + "value": "502", + "label": "Low battery" + }, + { + "value": "503", + "label": "Dust bin missing" + }, + { + "value": "508", + "label": "Uneven ground" + }, + { + "value": "509", + "label": "Cliff sensor erro" + }, + { + "value": "510", + "label": "Collision sensor error" + }, + { + "value": "511", + "label": "Could not return to dock" + }, + { + "value": "512", + "label": "Could not return to dock" + }, + { + "value": "513", + "label": "Could not navigate" + }, + { + "value": "514", + "label": "Vacuum stuck" + }, + { + "value": "515", + "label": "Charging erro" + }, + { + "value": "516", + "label": "Mop temperature error" + }, + { + "value": "521", + "label": "Water tank is not installed" + }, + { + "value": "522", + "label": "Mop is not installed" + }, + { + "value": "525", + "label": "Insufficient water in water tank" + }, + { + "value": "527", + "label": "Remove mop" + }, + { + "value": "528", + "label": "Dust bin missing" + }, + { + "value": "529", + "label": "Mop and water tank missing" + }, + { + "value": "530", + "label": "Mop and water tank missin" + }, + { + "value": "531", + "label": "Water tank is not installed" + }, + { + "value": "2101", + "label": "Unsufficient battery, continuing cleaning after recharge" + }, + { + "value": "2103", + "label": "Charging" + }, + { + "value": "2104", + "label": "Fully charged" + } + ] + }, "refresh": true, - "actions": [] + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Sleeping and not charging\",\"500\"\u003d\"Radar timed out\",\"501\"\u003d\"Wheels stuck\",\"502\"\u003d\"Low battery\",\"503\"\u003d\"Dust bin missing\",\"508\"\u003d\"Uneven ground\",\"509\"\u003d\"Cliff sensor erro\",\"510\"\u003d\"Collision sensor error\",\"511\"\u003d\"Could not return to dock\",\"512\"\u003d\"Could not return to dock\",\"513\"\u003d\"Could not navigate\",\"514\"\u003d\"Vacuum stuck\",\"515\"\u003d\"Charging erro\",\"516\"\u003d\"Mop temperature error\",\"521\"\u003d\"Water tank is not installed\",\"522\"\u003d\"Mop is not installed\",\"525\"\u003d\"Insufficient water in water tank\",\"527\"\u003d\"Remove mop\",\"528\"\u003d\"Dust bin missing\",\"529\"\u003d\"Mop and water tank missing\",\"530\"\u003d\"Mop and water tank missin\",\"531\"\u003d\"Water tank is not installed\",\"2101\"\u003d\"Unsufficient battery, continuing cleaning after recharge\",\"2103\"\u003d\"Charging\",\"2104\"\u003d\"Fully charged\"]`" }, { "property": "battary_life", @@ -86,25 +283,67 @@ "friendlyName": "Box type", "channel": "box_type", "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Bin" + }, + { + "value": "1", + "label": "Sweep" + }, + { + "value": "2", + "label": "Mop" + }, + { + "value": "3", + "label": "Sweep and Mop" + } + ] + }, "refresh": true, "actions": [ { "parameterType": "EMPTY" } - ] + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Bin\",\"1\"\u003d\"Sweep\",\"2\"\u003d\"Mop\",\"3\"\u003d\"Sweep and Mop\"]`" }, { "property": "mop_type", "friendlyName": "mop_type", "channel": "mop_type", "type": "Number", + "actions": [] + }, + { + "property": "mop_route", + "friendlyName": "Mop Route", + "channel": "mop_route", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "S-Pattern" + }, + { + "value": "1", + "label": "Y-Pattern" + } + ] + }, "refresh": true, "actions": [ { - "command": "set_mode", + "command": "set_moproute", "parameterType": "NUMBER" } - ] + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"S-Pattern\",\"1\"\u003d\"Y-Pattern\"]`" }, { "property": "s_time", @@ -137,26 +376,64 @@ "friendlyName": "suction_grade", "channel": "suction_grade", "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Silent" + }, + { + "value": "1", + "label": "Basic" + }, + { + "value": "2", + "label": "Medium" + }, + { + "value": "3", + "label": "Strong" + } + ] + }, "refresh": true, "actions": [ { "command": "set_suction", "parameterType": "NUMBER" } - ] + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Silent\",\"1\"\u003d\"Basic\",\"2\"\u003d\"Medium\",\"3\"\u003d\"Strong\"]`" }, { "property": "water_grade", "friendlyName": "water_grade", "channel": "water_grade", "type": "Number", + "stateDescription": { + "options": [ + { + "value": "11", + "label": "Low" + }, + { + "value": "12", + "label": "Medium" + }, + { + "value": "13", + "label": "High" + } + ] + }, "refresh": true, "actions": [ { "command": "set_suction", "parameterType": "NUMBER" } - ] + ], + "readmeComment": "Value mapping `[\"11\"\u003d\"Low\",\"12\"\u003d\"Medium\",\"13\"\u003d\"High\"]`" }, { "property": "remember_map", @@ -179,8 +456,33 @@ "friendlyName": "is_mop", "channel": "is_mop", "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Vacuum" + }, + { + "value": "1", + "label": "Vacuum And Mop" + }, + { + "value": "2", + "label": "Mop" + }, + { + "value": "3", + "label": "CleanZone" + }, + { + "value": "4", + "label": "CleanSpot" + } + ] + }, "refresh": true, - "actions": [] + "actions": [], + "readmeComment": "Value mapping `[\"0\"\u003d\"Vacuum\",\"1\"\u003d\"Vacuum And Mop\",\"2\"\u003d\"Mop\",\"3\"\u003d\"CleanZone\",\"4\"\u003d\"CleanSpot\"]`" }, { "property": "has_newmap", From 361aa9dbd720cacd14b8edf74ec217c4707e8a88 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 12 Dec 2021 22:13:11 +0100 Subject: [PATCH 226/361] [miio] Add support for Roidmi EVE roidmi.vacuum.v60 (#11727) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 110 ++ .../binding/miio/internal/MiIoDevices.java | 1 + .../resources/OH-INF/i18n/basic.properties | 590 ++++++- .../database/roidmi.vacuum.v60-miot.json | 1566 +++++++++++++++++ 4 files changed, 2262 insertions(+), 5 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/main/resources/database/roidmi.vacuum.v60-miot.json diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index c8710106f295d..a0adc3d9ee225 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -341,6 +341,7 @@ Currently the miio binding supports more than 310 different models. | Roborock Vacuum T7 v3 | miio:vacuum | [roborock.vacuum.t7v3](#roborock-vacuum-t7v3) | Yes | | | Roborock Vacuum S6 | miio:vacuum | [rockrobo.vacuum.s6](#rockrobo-vacuum-s6) | Yes | | | Mi Robot Vacuum | miio:vacuum | [rockrobo.vacuum.v1](#rockrobo-vacuum-v1) | Yes | | +| ROIDMI EVE vacuum | miio:basic | [roidmi.vacuum.v60](#roidmi-vacuum-v60) | Yes | | | PTX OneKey Switch (WIFI) | miio:basic | [090615.switch.xswitch01](#090615-switch-xswitch01) | Yes | | | PTX Twokey switch(wifi) | miio:basic | [090615.switch.xswitch02](#090615-switch-xswitch02) | Yes | | | PTX ThreeKey Switch (WIFI) | miio:basic | [090615.switch.xswitch03](#090615-switch-xswitch03) | Yes | | @@ -2364,6 +2365,59 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | elec_leakage | Number:ElectricCurrent | Electic Leakage | | | temperature | Number:Temperature | Temperature | | +### ROIDMI EVE vacuum (roidmi.vacuum.v60) Channels + +| Channel | Type | Description | Comment | +|----------------------|----------------------|------------------------------------------|------------| +| actions | String | Actions | Value mapping `["vacuum-start-sweep"="Vacuum Start Sweep","vacuum-stop-sweeping"="Vacuum Stop Sweeping","vacuum-start-room-sweep"="Vacuum Start Room Sweep","battery-start-charge"="Battery Start Charge","filter-reset-filter-life"="Filter Reset Filter Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","brush-cleaner-reset-brush-life"="Brush Cleaner Reset Brush Life","custom-find-robot"="Custom Find Robot","custom-stop-find-charge"="Custom Stop Find Charge","custom-continue-sweep"="Custom Continue Sweep","custom-start-dust"="Custom Start Dust","custom-pause"="Custom Pause","custom-pause-find-charge"="Custom Pause Find Charge","custom-continue-find-charge"="Custom Continue Find Charge","custom-update-audio"="Custom Update Audio","custom-set-voice"="Custom Set Voice","map-request-path"="Map Request Path","map-change-area-name"="Map Change Area Name","map-set-auto-area"="Map Set Auto Area","map-local-map"="Map Local Map","map-area-custom"="Map Area Custom","map-area-order"="Map Area Order","sweep-start-sweep"="Sweep Start Sweep"]` | +| status | Number | Robot Cleaner - Status | Value mapping `["1"="Dormant","2"="Idle","3"="Paused","4"="Sweeping","5"="Go Charging","6"="Charging","7"="Error","8"="Rfctrl","9"="Fullcharge","10"="Shutdown","11"="Findchargerpause"]` | +| fault | Number | Robot Cleaner - Device Fault | Value mapping `["0"="No Faults","1"="Low Battery Find Charger","2"="Low Battery And Poweroff","3"="Wheel Trap","4"="Collision Error","5"="Tile Do Task","6"="Lidar Point Error","7"="Front Wall Error","8"="Psd Dirty","9"="Middle Brush Fatal","10"="Sid Brush","11"="Fan Speed Error","12"="Lidar Cover","13"="Garbage Box Full","14"="Garbage Box Out","15"="Garbage Box Full Out","16"="Physical Trapped","17"="Pick Up Do Task","18"="No Water Box Do Task","19"="Water Box Empty","20"="Clean Cannot Arrive","21"="Start Form Forbid","22"="Drop","23"="Kit Water Pump","24"="Find Charger Failed","25"="Low Power Clean"]` | +| mode | Number | Robot Cleaner - Mode | Value mapping `["1"="Silent","2"="Basic","3"="Strong","4"="Full Speed","0"="Sweep"]` | +| sweep_type | Number | Robot Cleaner - Sweep Type | Value mapping `["0"="Sweep","1"="Mop","2"="Mop And Sweep"]` | +| on | Number | Robot Cleaner - Switch Status | Value mapping `["1"="Open"]` | +| battery_level | Number:Dimensionless | Battery - Battery Level | | +| charging_state | Number | Battery - Charging State | Value mapping `["1"="Charging","2"="Not charging","3"="Not chargeable"]` | +| volume | Number:Dimensionless | Speaker - Volume | | +| mute | Switch | Speaker - Mute | | +| filter_life_level | Number:Dimensionless | Filter - Filter Life Level | | +| filter_left_time | Number:Time | Filter - Filter Left Time | | +| brush_left_time | Number:Time | Brush Cleaner - Brush Left Time | | +| brush_life_level | Number:Dimensionless | Brush Cleaner - Brush Life Level | | +| brush_left_time1 | Number:Time | Brush Cleaner - Brush Left Time | | +| brush_life_level1 | Number:Dimensionless | Brush Cleaner - Brush Life Level | | +| brush_left_time2 | Number:Time | Brush Cleaner - Brush Left Time | | +| brush_life_level2 | Number:Dimensionless | Brush Cleaner - Brush Life Level | | +| mop | Switch | Custom - Mop | | +| work_station_freq | Number | Custom - Work Station Freq | | +| timing | String | Custom - Timing | | +| clean_area | Number | Custom - Clean Area | | +| uid | String | Custom - Uid | | +| auto_boost | Switch | Custom - Auto Boost | | +| forbid_mode | String | Custom - Forbid Mode | | +| water_level | Number | Custom - Water Level | Value mapping `["1"="First","2"="Second","3"="Three","4"="Fourth","0"="Mop"]` | +| total_clean_time | Number:Time | Custom - Total Clean Time | | +| total_clean_areas | Number | Custom - Total Clean Areas | | +| clean_counts | Number | Custom - Clean Counts | | +| clean_time | Number:Time | Custom - Clean Time | | +| double_clean | Switch | Custom - Double Clean | | +| edge_sweep | Switch | Custom - Edge Sweep | | +| led_switch | Switch | Custom - Led Switch | | +| lidar_collision | Switch | Custom - Lidar Collision | | +| station_key | Switch | Custom - Station Key | | +| station_led | Switch | Custom - Station Led | | +| current_audio | String | Custom - Current Audio | | +| progress | String | Custom - Progress | | +| station_type | Number | Custom - Station Type | | +| voice_conf | String | Custom - Voice Conf | | +| clean_path | String | Map - Clean Path | | +| restricted_zone | String | Map - Restricted Zone | | +| auto_area | String | Map - Auto Area | | +| map_memory | Switch | Map - Map Memory | | +| map_name | String | Map - Map Name | | +| use_auto_area | Switch | Map - Use Auto Area | | +| path_type | Number | Map - Path Type | Value mapping `["0"="Normal","1"="Y-Mopping","2"="Repeat-Mopping"]` | +| sweep_mode | Number | Sweep - Sweep Mode | Value mapping `["1"="Total","2"="Area","3"="Curpoint","4"="Point","7"="Smart","8"="AmartArea","9"="DepthTotal","10"="AlongWall","0"="Idle"]` | + ### PTX OneKey Switch (WIFI) (090615.switch.xswitch01) Channels | Channel | Type | Description | Comment | @@ -7649,6 +7703,62 @@ Number:ElectricCurrent elec_leakage "Electic Leakage" (G_powerstrip) {channel="m Number:Temperature temperature "Temperature" (G_powerstrip) {channel="miio:basic:powerstrip:temperature"} ``` +### ROIDMI EVE vacuum (roidmi.vacuum.v60) item file lines + +note: Autogenerated example. Replace the id (vacuum) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. + +``` +Group G_vacuum "ROIDMI EVE vacuum" +String actions "Actions" (G_vacuum) {channel="miio:basic:vacuum:actions"} +Number status "Robot Cleaner - Status" (G_vacuum) {channel="miio:basic:vacuum:status"} +Number fault "Robot Cleaner - Device Fault" (G_vacuum) {channel="miio:basic:vacuum:fault"} +Number mode "Robot Cleaner - Mode" (G_vacuum) {channel="miio:basic:vacuum:mode"} +Number sweep_type "Robot Cleaner - Sweep Type" (G_vacuum) {channel="miio:basic:vacuum:sweep_type"} +Number on "Robot Cleaner - Switch Status" (G_vacuum) {channel="miio:basic:vacuum:on"} +Number:Dimensionless battery_level "Battery - Battery Level" (G_vacuum) {channel="miio:basic:vacuum:battery_level"} +Number charging_state "Battery - Charging State" (G_vacuum) {channel="miio:basic:vacuum:charging_state"} +Number:Dimensionless volume "Speaker - Volume" (G_vacuum) {channel="miio:basic:vacuum:volume"} +Switch mute "Speaker - Mute" (G_vacuum) {channel="miio:basic:vacuum:mute"} +Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_vacuum) {channel="miio:basic:vacuum:filter_life_level"} +Number:Time filter_left_time "Filter - Filter Left Time" (G_vacuum) {channel="miio:basic:vacuum:filter_left_time"} +Number:Time brush_left_time "Brush Cleaner - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time"} +Number:Dimensionless brush_life_level "Brush Cleaner - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level"} +Number:Time brush_left_time1 "Brush Cleaner - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time1"} +Number:Dimensionless brush_life_level1 "Brush Cleaner - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level1"} +Number:Time brush_left_time2 "Brush Cleaner - Brush Left Time" (G_vacuum) {channel="miio:basic:vacuum:brush_left_time2"} +Number:Dimensionless brush_life_level2 "Brush Cleaner - Brush Life Level" (G_vacuum) {channel="miio:basic:vacuum:brush_life_level2"} +Switch mop "Custom - Mop" (G_vacuum) {channel="miio:basic:vacuum:mop"} +Number work_station_freq "Custom - Work Station Freq" (G_vacuum) {channel="miio:basic:vacuum:work_station_freq"} +String timing "Custom - Timing" (G_vacuum) {channel="miio:basic:vacuum:timing"} +Number clean_area "Custom - Clean Area" (G_vacuum) {channel="miio:basic:vacuum:clean_area"} +String uid "Custom - Uid" (G_vacuum) {channel="miio:basic:vacuum:uid"} +Switch auto_boost "Custom - Auto Boost" (G_vacuum) {channel="miio:basic:vacuum:auto_boost"} +String forbid_mode "Custom - Forbid Mode" (G_vacuum) {channel="miio:basic:vacuum:forbid_mode"} +Number water_level "Custom - Water Level" (G_vacuum) {channel="miio:basic:vacuum:water_level"} +Number:Time total_clean_time "Custom - Total Clean Time" (G_vacuum) {channel="miio:basic:vacuum:total_clean_time"} +Number total_clean_areas "Custom - Total Clean Areas" (G_vacuum) {channel="miio:basic:vacuum:total_clean_areas"} +Number clean_counts "Custom - Clean Counts" (G_vacuum) {channel="miio:basic:vacuum:clean_counts"} +Number:Time clean_time "Custom - Clean Time" (G_vacuum) {channel="miio:basic:vacuum:clean_time"} +Switch double_clean "Custom - Double Clean" (G_vacuum) {channel="miio:basic:vacuum:double_clean"} +Switch edge_sweep "Custom - Edge Sweep" (G_vacuum) {channel="miio:basic:vacuum:edge_sweep"} +Switch led_switch "Custom - Led Switch" (G_vacuum) {channel="miio:basic:vacuum:led_switch"} +Switch lidar_collision "Custom - Lidar Collision" (G_vacuum) {channel="miio:basic:vacuum:lidar_collision"} +Switch station_key "Custom - Station Key" (G_vacuum) {channel="miio:basic:vacuum:station_key"} +Switch station_led "Custom - Station Led" (G_vacuum) {channel="miio:basic:vacuum:station_led"} +String current_audio "Custom - Current Audio" (G_vacuum) {channel="miio:basic:vacuum:current_audio"} +String progress "Custom - Progress" (G_vacuum) {channel="miio:basic:vacuum:progress"} +Number station_type "Custom - Station Type" (G_vacuum) {channel="miio:basic:vacuum:station_type"} +String voice_conf "Custom - Voice Conf" (G_vacuum) {channel="miio:basic:vacuum:voice_conf"} +String clean_path "Map - Clean Path" (G_vacuum) {channel="miio:basic:vacuum:clean_path"} +String restricted_zone "Map - Restricted Zone" (G_vacuum) {channel="miio:basic:vacuum:restricted_zone"} +String auto_area "Map - Auto Area" (G_vacuum) {channel="miio:basic:vacuum:auto_area"} +Switch map_memory "Map - Map Memory" (G_vacuum) {channel="miio:basic:vacuum:map_memory"} +String map_name "Map - Map Name" (G_vacuum) {channel="miio:basic:vacuum:map_name"} +Switch use_auto_area "Map - Use Auto Area" (G_vacuum) {channel="miio:basic:vacuum:use_auto_area"} +Number path_type "Map - Path Type" (G_vacuum) {channel="miio:basic:vacuum:path_type"} +Number sweep_mode "Sweep - Sweep Mode" (G_vacuum) {channel="miio:basic:vacuum:sweep_mode"} +``` + ### PTX OneKey Switch (WIFI) (090615.switch.xswitch01) item file lines note: Autogenerated example. Replace the id (switch) in the channel with your own. Replace `basic` with `generic` in the thing UID depending on how your thing was discovered. diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java index 603d2f7c016f7..bb6899193e77c 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoDevices.java @@ -188,6 +188,7 @@ public enum MiIoDevices { ROBOROCK_VACUUM_T7V3("roborock.vacuum.t7v3", "Roborock Vacuum T7 v3", THING_TYPE_VACUUM), ROCKROBO_VACUUM_S6("rockrobo.vacuum.s6", "Roborock Vacuum S6", THING_TYPE_VACUUM), ROCKROBO_VACUUM_V1("rockrobo.vacuum.v1", "Mi Robot Vacuum", THING_TYPE_VACUUM), + ROIDMI_VACUUM_V60("roidmi.vacuum.v60", "ROIDMI EVE vacuum", THING_TYPE_BASIC), S090615_SWITCH_XSWITCH01("090615.switch.xswitch01", "PTX OneKey Switch (WIFI)", THING_TYPE_BASIC), S090615_SWITCH_XSWITCH02("090615.switch.xswitch02", "PTX Twokey switch(wifi)", THING_TYPE_BASIC), S090615_SWITCH_XSWITCH03("090615.switch.xswitch03", "PTX ThreeKey Switch (WIFI)", THING_TYPE_BASIC), diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties index e5ae9d8e859af..65659da0c429a 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties @@ -28,6 +28,8 @@ thing.chunmi.cooker.press2 = Mi IH Pressure Rice Cooker thing.cuco.plug.cp1 = Gosund Smart Plug thing.deerma.humidifier.jsq = Mi Smart Antibacterial Humidifier thing.deerma.humidifier.jsq1 = Mi S Smart Humidifer +thing.deerma.humidifier.jsq5 = Mi Smart Antibacterial Humidifier +thing.deerma.humidifier.jsqs = Mi Smart Humidifer S thing.deerma.humidifier.mjjsq = Mi Smart Humidifier thing.dmaker.airfresh.a1 = Mi Fresh Air Ventilator A1-150 thing.dmaker.airfresh.t2017 = Mi Fresh Air Ventilator @@ -41,10 +43,13 @@ thing.dmaker.fan.p18 = Mi Smart Standing Fan 2 thing.dreame.vacuum.mc1808 = Mi Robot Vacuum Mop 1C STYTJ01ZHM thing.dreame.vacuum.p2008 = Dreame Robot Vacuum-Mop F9 thing.dreame.vacuum.p2009 = Dreame Robot Vacuum D9 +thing.dreame.vacuum.p2027 = Dreame Bot W10 +thing.dreame.vacuum.p2028 = Dreame Bot Z10 Pro thing.dreame.vacuum.p2036 = Trouver Robot LDS Vacuum-Mop Finder thing.dreame.vacuum.p2041o = Mi Robot Vacuum-Mop 2 Pro+ thing.dreame.vacuum.p2156o = MOVA Z500 Robot Vacuum and Mop Cleaner thing.dreame.vacuum.p2157 = MOVA L600 Robot Vacuum and Mop Cleaner +thing.dreame.vacuum.p2259 = Dreame Bot D9 Max thing.huayi.light.ari013 = HUIZUO ARIES For Bedroom thing.huayi.light.aries = HUIZUO ARIES For Living Room thing.huayi.light.fanwy = HUIZUO Fan Light @@ -158,6 +163,7 @@ thing.roborock.vacuum.t7v2 = Roborock Vacuum T7 v2 thing.roborock.vacuum.t7v3 = Roborock Vacuum T7 v3 thing.rockrobo.vacuum.s6 = Roborock Vacuum S6 thing.rockrobo.vacuum.v1 = Mi Robot Vacuum +thing.roidmi.vacuum.v60 = ROIDMI EVE vacuum thing.090615.switch.xswitch01 = PTX OneKey Switch (WIFI) thing.090615.switch.xswitch02 = PTX Twokey switch(wifi) thing.090615.switch.xswitch03 = PTX ThreeKey Switch (WIFI) @@ -288,6 +294,7 @@ thing.yunmi.waterpurifier.v3 = Mi Water Purifier (Under sink) v3 thing.yunmi.waterpurifier.v4 = Mi Water Purifier v4 thing.zhimi.airfresh.va2 = Smartmi Ventilation System thing.zhimi.airfresh.va4 = Smartmi Fresh Air System (Heating) +thing.zhimi.airfresh.ua1 = Mi Fresh Air Ventilator C1-80 thing.zhimi.airmonitor.v1 = Mi PM2.5 Air Quality Monitor thing.zhimi.airpurifier.m1 = Mi Air Purifier 2 (mini) thing.zhimi.airpurifier.m2 = Mi Air Purifier 2 @@ -406,6 +413,7 @@ ch.cgllc.airmonitor.s1.humidity = Humidity ch.cgllc.airmonitor.s1.pm25 = PM2.5 ch.cgllc.airmonitor.s1.temperature = Temperature ch.cgllc.airmonitor.s1.tvoc = tVOC +ch.chuangmi.plug.212a01-miot.bt-gw = BT Gateway ch.chuangmi.plug.212a01-miot.countdown = Imilab Timer - Countdown ch.chuangmi.plug.212a01-miot.countdown-info = Imilab Timer - Countdown Info ch.chuangmi.plug.212a01-miot.electric-current = Power Consumption - Electric Current @@ -444,6 +452,16 @@ ch.deerma.humidifier.jsq1.power = Power ch.deerma.humidifier.jsq1.sound = Notification Sounds ch.deerma.humidifier.jsq1.watertankstatus = Watertank Status ch.deerma.humidifier.jsq1.wet_and_protect = Wet and Protect +ch.deerma.humidifier.jsq5.alarm = Alarm - Alarm +ch.deerma.humidifier.jsq5.fan_level = Humidifier - Fan Level +ch.deerma.humidifier.jsq5.fault = Humidifier - Device Fault +ch.deerma.humidifier.jsq5.on = Humidifier - Switch Status +ch.deerma.humidifier.jsq5.on1 = Indicator Light - Switch Status +ch.deerma.humidifier.jsq5.relative_humidity = Environment - Relative Humidity +ch.deerma.humidifier.jsq5.target_humidity = Humidifier - Target Humidity +ch.deerma.humidifier.jsq5.temperature = Environment - Temperature +ch.deerma.humidifier.jsq5.the_tank_filed = Custom - The Tank Filed +ch.deerma.humidifier.jsq5.water_shortage_fault = Custom - Water Shortage Fault ch.deerma.humidifier.mjjsq.humidity = Humidity ch.deerma.humidifier.mjjsq.humidity_set = Humidity Setting ch.deerma.humidifier.mjjsq.led = LED indicator Light @@ -640,6 +658,101 @@ ch.dreame.vacuum.p2009-miot.voice-packet-id = Audio - Voice Packet Id ch.dreame.vacuum.p2009-miot.volume = Audio - Volume ch.dreame.vacuum.p2009-miot.waterbox-status = Vacuum Extend - Waterbox Status ch.dreame.vacuum.p2009-miot.work-mode = Vacuum Extend - Work Mode +ch.dreame.vacuum.p2027-miot.actions = Actions +ch.dreame.vacuum.p2027-miot.battery_level = Battery - Battery Level +ch.dreame.vacuum.p2027-miot.break_point_restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2027-miot.brush_left_time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2027-miot.brush_left_time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2027-miot.brush_life_level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2027-miot.brush_life_level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2027-miot.carpet_press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2027-miot.charging_state = Battery - Charging State +ch.dreame.vacuum.p2027-miot.child_lock = Vacuum Extend - Child Lock +ch.dreame.vacuum.p2027-miot.clean_cancel = Vacuum Extend - Clean Cancel +ch.dreame.vacuum.p2027-miot.clean_extend_data = Vacuum Extend - Clean Extend Data +ch.dreame.vacuum.p2027-miot.clean_rags_tip = Vacuum Extend - Clean Rags Tip +ch.dreame.vacuum.p2027-miot.cleaning-area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2027-miot.cleaning_mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2027-miot.cleaning_time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2027-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2027-miot.end_time = Do Not Disturb - End Time +ch.dreame.vacuum.p2027-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2027-miot.faults = Vacuum Extend - Faults +ch.dreame.vacuum.p2027-miot.filter_left_time = Filter - Filter Left Time +ch.dreame.vacuum.p2027-miot.filter_life_level = Filter - Filter Life Level +ch.dreame.vacuum.p2027-miot.first_clean_time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2027-miot.frame_info = Map - Frame Info +ch.dreame.vacuum.p2027-miot.keep_sweeper_time = Vacuum Extend - Keep Sweeper Time +ch.dreame.vacuum.p2027-miot.map_extend_data = Map - Map Extend Data +ch.dreame.vacuum.p2027-miot.mode = Robot Cleaner - Mode +ch.dreame.vacuum.p2027-miot.mop_mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2027-miot.mop_status = Vacuum Extend - Mop Status +ch.dreame.vacuum.p2027-miot.mult_map_info = Map - Mult Map Info +ch.dreame.vacuum.p2027-miot.mult_map_state = Map - Mult Map State +ch.dreame.vacuum.p2027-miot.nation_matched = Vacuum Extend - Nation Matched +ch.dreame.vacuum.p2027-miot.relocation_status = Vacuum Extend - Relocation Status +ch.dreame.vacuum.p2027-miot.remote_state = Vacuum Extend - Remote State +ch.dreame.vacuum.p2027-miot.set_voice = Audio - Set Voice +ch.dreame.vacuum.p2027-miot.start_time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2027-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2027-miot.task_status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2027-miot.time_zone = Time - Time Zone +ch.dreame.vacuum.p2027-miot.timer_clean = Time - Timer Clean +ch.dreame.vacuum.p2027-miot.total_clean_area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2027-miot.total_clean_time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2027-miot.total_clean_times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2027-miot.voice_change_state = Audio - Voice Change State +ch.dreame.vacuum.p2027-miot.voice_packet_id = Audio - Voice Packet Id +ch.dreame.vacuum.p2027-miot.volume = Audio - Volume +ch.dreame.vacuum.p2027-miot.waterbox_status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2027-miot.work_mode = Vacuum Extend - Work Mode +ch.dreame.vacuum.p2028-miot.actions = Actions +ch.dreame.vacuum.p2028-miot.auto_collect = Collect Dust - Auto Collect +ch.dreame.vacuum.p2028-miot.battery_level = Battery - Battery Level +ch.dreame.vacuum.p2028-miot.break_point_restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2028-miot.brush_left_time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2028-miot.brush_left_time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2028-miot.brush_life_level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2028-miot.brush_life_level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2028-miot.carpet_press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2028-miot.charging_state = Battery - Charging State +ch.dreame.vacuum.p2028-miot.clean_extend_data = Vacuum Extend - Clean Extend Data +ch.dreame.vacuum.p2028-miot.clean_rags_tip = Vacuum Extend - Clean Rags Tip +ch.dreame.vacuum.p2028-miot.clean_times = Collect Dust - Clean Times +ch.dreame.vacuum.p2028-miot.cleaning-area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2028-miot.cleaning_mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2028-miot.cleaning_time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2028-miot.dust_enable = Collect Dust - Dust Enable +ch.dreame.vacuum.p2028-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2028-miot.end_time = Do Not Disturb - End Time +ch.dreame.vacuum.p2028-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2028-miot.faults = Vacuum Extend - Faults +ch.dreame.vacuum.p2028-miot.filter_left_time = Filter - Filter Left Time +ch.dreame.vacuum.p2028-miot.filter_life_level = Filter - Filter Life Level +ch.dreame.vacuum.p2028-miot.first_clean_time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2028-miot.frame_info = Map - Frame Info +ch.dreame.vacuum.p2028-miot.keep_sweeper_time = Vacuum Extend - Keep Sweeper Time +ch.dreame.vacuum.p2028-miot.map_extend_data = Map - Map Extend Data +ch.dreame.vacuum.p2028-miot.mop_mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2028-miot.mult_map_info = Map - Mult Map Info +ch.dreame.vacuum.p2028-miot.mult_map_state = Map - Mult Map State +ch.dreame.vacuum.p2028-miot.nation_matched = Vacuum Extend - Nation Matched +ch.dreame.vacuum.p2028-miot.relocation_status = Vacuum Extend - Relocation Status +ch.dreame.vacuum.p2028-miot.remote_state = Vacuum Extend - Remote State +ch.dreame.vacuum.p2028-miot.set_voice = Audio - Set Voice +ch.dreame.vacuum.p2028-miot.start_time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2028-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2028-miot.task_status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2028-miot.time_zone = Time - Time Zone +ch.dreame.vacuum.p2028-miot.timer_clean = Time - Timer Clean +ch.dreame.vacuum.p2028-miot.total_clean_area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2028-miot.total_clean_time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2028-miot.total_clean_times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2028-miot.voice_change_state = Audio - Voice Change State +ch.dreame.vacuum.p2028-miot.voice_packet_id = Audio - Voice Packet Id +ch.dreame.vacuum.p2028-miot.volume = Audio - Volume +ch.dreame.vacuum.p2028-miot.waterbox_status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2028-miot.work_mode = Vacuum Extend - Work Mode ch.dreame.vacuum.p2156o-miot.actions = Actions ch.dreame.vacuum.p2156o-miot.battery_level = Battery - Battery Level ch.dreame.vacuum.p2156o-miot.break_point_restart = Vacuum Extend - Break Point Restart @@ -677,6 +790,49 @@ ch.dreame.vacuum.p2156o-miot.voice_packet_id = Audio - Voice Packet Id ch.dreame.vacuum.p2156o-miot.volume = Audio - Volume ch.dreame.vacuum.p2156o-miot.waterbox_status = Vacuum Extend - Waterbox Status ch.dreame.vacuum.p2156o-miot.work_mode = Vacuum Extend - Work Mode +ch.dreame.vacuum.p2259-miot.actions = Actions +ch.dreame.vacuum.p2259-miot.battery_level = Battery - Battery Level +ch.dreame.vacuum.p2259-miot.break_point_restart = Vacuum Extend - Break Point Restart +ch.dreame.vacuum.p2259-miot.brush_left_time = Main Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2259-miot.brush_left_time1 = Side Cleaning Brush - Brush Left Time +ch.dreame.vacuum.p2259-miot.brush_life_level = Main Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2259-miot.brush_life_level1 = Side Cleaning Brush - Brush Life Level +ch.dreame.vacuum.p2259-miot.carpet_press = Vacuum Extend - Carpet Press +ch.dreame.vacuum.p2259-miot.charging_state = Battery - Charging State +ch.dreame.vacuum.p2259-miot.clean_extend_data = Vacuum Extend - Clean Extend Data +ch.dreame.vacuum.p2259-miot.clean_rags_tip = Vacuum Extend - Clean Rags Tip +ch.dreame.vacuum.p2259-miot.cleaning_area = Vacuum Extend - Cleaning Area +ch.dreame.vacuum.p2259-miot.cleaning_mode = Vacuum Extend - Cleaning Mode +ch.dreame.vacuum.p2259-miot.cleaning_time = Vacuum Extend - Cleaning Time +ch.dreame.vacuum.p2259-miot.enable = Do Not Disturb - Enable +ch.dreame.vacuum.p2259-miot.end_time = Do Not Disturb - End Time +ch.dreame.vacuum.p2259-miot.fault = Robot Cleaner - Device Fault +ch.dreame.vacuum.p2259-miot.faults = Vacuum Extend - Faults +ch.dreame.vacuum.p2259-miot.filter_left_time = Filter - Filter Left Time +ch.dreame.vacuum.p2259-miot.filter_life_level = Filter - Filter Life Level +ch.dreame.vacuum.p2259-miot.first_clean_time = Clean Logs - First Clean Time +ch.dreame.vacuum.p2259-miot.frame_info = Map - Frame Info +ch.dreame.vacuum.p2259-miot.keep_sweeper_time = Vacuum Extend - Keep Sweeper Time +ch.dreame.vacuum.p2259-miot.map_extend_data = Map - Map Extend Data +ch.dreame.vacuum.p2259-miot.mode = Robot Cleaner - Mode +ch.dreame.vacuum.p2259-miot.mop_mode = Vacuum Extend - Mop Mode +ch.dreame.vacuum.p2259-miot.mult_map_info = Map - Mult Map Info +ch.dreame.vacuum.p2259-miot.mult_map_state = Map - Mult Map State +ch.dreame.vacuum.p2259-miot.remote_state = Vacuum Extend - Remote State +ch.dreame.vacuum.p2259-miot.set_voice = Audio - Set Voice +ch.dreame.vacuum.p2259-miot.start_time = Do Not Disturb - Start Time +ch.dreame.vacuum.p2259-miot.status = Robot Cleaner - Status +ch.dreame.vacuum.p2259-miot.task_status = Vacuum Extend - Task Status +ch.dreame.vacuum.p2259-miot.time_zone = Time - Time Zone +ch.dreame.vacuum.p2259-miot.timer_clean = Time - Timer Clean +ch.dreame.vacuum.p2259-miot.total_clean_area = Clean Logs - Total Clean Area +ch.dreame.vacuum.p2259-miot.total_clean_time = Clean Logs - Total Clean Time +ch.dreame.vacuum.p2259-miot.total_clean_times = Clean Logs - Total Clean Times +ch.dreame.vacuum.p2259-miot.voice_change_state = Audio - Voice Change State +ch.dreame.vacuum.p2259-miot.voice_packet_id = Audio - Voice Packet Id +ch.dreame.vacuum.p2259-miot.volume = Audio - Volume +ch.dreame.vacuum.p2259-miot.waterbox_status = Vacuum Extend - Waterbox Status +ch.dreame.vacuum.p2259-miot.work_mode = Vacuum Extend - Work Mode ch.huayi.light.fanwy-miot.brightness = Light - Brightness ch.huayi.light.fanwy-miot.color-temperature = Light - Color Temperature ch.huayi.light.fanwy-miot.fan-level = Fan - Fan Level @@ -710,13 +866,15 @@ ch.huayi.light.wyheat-miot.heat-level = Heater - Heat Level ch.huayi.light.wyheat-miot.on = Light - Power ch.huayi.light.wyheat-miot.on1 = Heater - Power ch.huayi.light.wyheat-miot.screenshow = Other - Screenshow +ch.lumi.curtain.hagl05-miot.adjust_value = Motor_controller - Adjust_value ch.lumi.curtain.hagl05-miot.current-position = Curtain - Current Position -ch.lumi.curtain.hagl05-miot.en-night-tip-light = Set Night Tip Light +ch.lumi.curtain.hagl05-miot.en_night_tip_light = Curtain_cfg - En_night_tip_light ch.lumi.curtain.hagl05-miot.fault = Curtain - Device Fault ch.lumi.curtain.hagl05-miot.manual-enabled = curtain_cfg - Manual Enabled -ch.lumi.curtain.hagl05-miot.polarity = curtain_cfg - Polarity +ch.lumi.curtain.hagl05-miot.motor_control = Curtain - Motor Control +ch.lumi.curtain.hagl05-miot.polarity = Curtain_cfg - Polarity ch.lumi.curtain.hagl05-miot.pos-limit = curtain_cfg - Position Limit -ch.lumi.curtain.hagl05-miot.run-time = curtain_cfg - Run-time +ch.lumi.curtain.hagl05-miot.run-time = Curtain_cfg - Run-time ch.lumi.curtain.hagl05-miot.status = Curtain - Status ch.lumi.curtain.hagl05-miot.target-position = Curtain - Target Position ch.lumi.gateway.alarmingVol = Alarming Volume @@ -839,6 +997,7 @@ ch.philips.light.cbulb.switchscene = Switch Scene ch.philips.light.ceil-miot.MibandStatus = Mi Band Status ch.philips.light.ceil-miot.WallScene = Wall Scene ch.philips.light.ceil-miot.WallSceneEn = Wall Scene Enable +ch.philips.light.ceil-miot.actions = Actions ch.philips.light.ceil-miot.autoCct = Auto CCT ch.philips.light.ceil-miot.brightness = Brightness ch.philips.light.ceil-miot.cct = Color Temperature @@ -885,6 +1044,54 @@ ch.qmi.powerstrip.v1.power_factor = Power Factor ch.qmi.powerstrip.v1.power_price = Power Price ch.qmi.powerstrip.v1.temperature = Temperature ch.qmi.powerstrip.v1.voltage = Voltage +ch.roidmi.vacuum.v60-miot.actions = Actions +ch.roidmi.vacuum.v60-miot.auto_area = Map - Auto Area +ch.roidmi.vacuum.v60-miot.auto_boost = Custom - Auto Boost +ch.roidmi.vacuum.v60-miot.battery_level = Battery - Battery Level +ch.roidmi.vacuum.v60-miot.brush_left_time = Brush Cleaner - Brush Left Time +ch.roidmi.vacuum.v60-miot.brush_left_time1 = Brush Cleaner - Brush Left Time +ch.roidmi.vacuum.v60-miot.brush_left_time2 = Brush Cleaner - Brush Left Time +ch.roidmi.vacuum.v60-miot.brush_life_level = Brush Cleaner - Brush Life Level +ch.roidmi.vacuum.v60-miot.brush_life_level1 = Brush Cleaner - Brush Life Level +ch.roidmi.vacuum.v60-miot.brush_life_level2 = Brush Cleaner - Brush Life Level +ch.roidmi.vacuum.v60-miot.charging_state = Battery - Charging State +ch.roidmi.vacuum.v60-miot.clean_area = Custom - Clean Area +ch.roidmi.vacuum.v60-miot.clean_counts = Custom - Clean Counts +ch.roidmi.vacuum.v60-miot.clean_path = Map - Clean Path +ch.roidmi.vacuum.v60-miot.clean_time = Custom - Clean Time +ch.roidmi.vacuum.v60-miot.current_audio = Custom - Current Audio +ch.roidmi.vacuum.v60-miot.double_clean = Custom - Double Clean +ch.roidmi.vacuum.v60-miot.edge_sweep = Custom - Edge Sweep +ch.roidmi.vacuum.v60-miot.fault = Robot Cleaner - Device Fault +ch.roidmi.vacuum.v60-miot.filter_left_time = Filter - Filter Left Time +ch.roidmi.vacuum.v60-miot.filter_life_level = Filter - Filter Life Level +ch.roidmi.vacuum.v60-miot.forbid_mode = Custom - Forbid Mode +ch.roidmi.vacuum.v60-miot.led_switch = Custom - Led Switch +ch.roidmi.vacuum.v60-miot.lidar_collision = Custom - Lidar Collision +ch.roidmi.vacuum.v60-miot.map_memory = Map - Map Memory +ch.roidmi.vacuum.v60-miot.map_name = Map - Map Name +ch.roidmi.vacuum.v60-miot.mode = Robot Cleaner - Mode +ch.roidmi.vacuum.v60-miot.mop = Custom - Mop +ch.roidmi.vacuum.v60-miot.mute = Speaker - Mute +ch.roidmi.vacuum.v60-miot.on = Robot Cleaner - Switch Status +ch.roidmi.vacuum.v60-miot.path_type = Map - Path Type +ch.roidmi.vacuum.v60-miot.progress = Custom - Progress +ch.roidmi.vacuum.v60-miot.restricted_zone = Map - Restricted Zone +ch.roidmi.vacuum.v60-miot.station_key = Custom - Station Key +ch.roidmi.vacuum.v60-miot.station_led = Custom - Station Led +ch.roidmi.vacuum.v60-miot.station_type = Custom - Station Type +ch.roidmi.vacuum.v60-miot.status = Robot Cleaner - Status +ch.roidmi.vacuum.v60-miot.sweep_mode = Sweep - Sweep Mode +ch.roidmi.vacuum.v60-miot.sweep_type = Robot Cleaner - Sweep Type +ch.roidmi.vacuum.v60-miot.timing = Custom - Timing +ch.roidmi.vacuum.v60-miot.total_clean_areas = Custom - Total Clean Areas +ch.roidmi.vacuum.v60-miot.total_clean_time = Custom - Total Clean Time +ch.roidmi.vacuum.v60-miot.uid = Custom - Uid +ch.roidmi.vacuum.v60-miot.use_auto_area = Map - Use Auto Area +ch.roidmi.vacuum.v60-miot.voice_conf = Custom - Voice Conf +ch.roidmi.vacuum.v60-miot.volume = Speaker - Volume +ch.roidmi.vacuum.v60-miot.water_level = Custom - Water Level +ch.roidmi.vacuum.v60-miot.work_station_freq = Custom - Work Station Freq ch.scishare.coffee.s1102.Status = status ch.scishare.coffee.s1102.boil = Boil water ch.scishare.coffee.s1102.expresso = Brew Americano @@ -1130,6 +1337,19 @@ ch.yunmi.waterpurifier.tds_out = TDS out ch.yunmi.waterpurifier.tds_out_avg = Average TDS out ch.yunmi.waterpurifier.tds_warn_thd = TDS Warn Threshold ch.yunmi.waterpurifier.temperature = Temperature +ch.zhimi.airfresh.ua1-miot.actions = Actions +ch.zhimi.airfresh.ua1-miot.alarm = Alarm - Alarm +ch.zhimi.airfresh.ua1-miot.brightness = Indicator Light - Brightness +ch.zhimi.airfresh.ua1-miot.fan_level = Air Fresh - Fan Level +ch.zhimi.airfresh.ua1-miot.fault = Device Fault +ch.zhimi.airfresh.ua1-miot.filter_life_level = Filter - Filter Life Level +ch.zhimi.airfresh.ua1-miot.filter_used_time = Filter - Filter Used Time +ch.zhimi.airfresh.ua1-miot.heater = Heater +ch.zhimi.airfresh.ua1-miot.motor_a_speed_rpm = Custom Serveice - Motor A Speed Rpm +ch.zhimi.airfresh.ua1-miot.motor_b_speed_rpm = Custom Serveice - Motor B Speed Rpm +ch.zhimi.airfresh.ua1-miot.on = Air Fresh - Switch Status +ch.zhimi.airfresh.ua1-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked +ch.zhimi.airfresh.ua1-miot.temperature = Custom Serveice - Temperature ch.zhimi.airfresh.va4.aqi = Air Quality Index ch.zhimi.airfresh.va4.averageaqi = Average Air Quality Index ch.zhimi.airfresh.va4.buzzer = Buzzer @@ -1683,14 +1903,35 @@ option.cgllc.airm.cgdn1-miot.screen_off-15 = Second option.cgllc.airm.cgdn1-miot.screen_off-30 = Second option.cgllc.airm.cgdn1-miot.screen_off-300 = Second option.cgllc.airm.cgdn1-miot.screen_off-60 = Second +option.chuangmi.plug.212a01-miot.bt-gw-disable = Disable +option.chuangmi.plug.212a01-miot.bt-gw-enable = Enable option.deerma.humidifier.jsq1.mode-1 = Low option.deerma.humidifier.jsq1.mode-2 = Medium option.deerma.humidifier.jsq1.mode-3 = High option.deerma.humidifier.jsq1.mode-4 = Humidity +option.deerma.humidifier.jsq5.fan_level-1 = Level1 +option.deerma.humidifier.jsq5.fan_level-2 = Level2 +option.deerma.humidifier.jsq5.fan_level-3 = Level3 +option.deerma.humidifier.jsq5.fan_level-4 = Humidity +option.deerma.humidifier.jsq5.fault-0 = No Faults +option.deerma.humidifier.jsq5.fault-1 = Insufficient Water +option.deerma.humidifier.jsq5.fault-2 = Water Separation option.deerma.humidifier.mjjsq.mode-1 = Low option.deerma.humidifier.mjjsq.mode-2 = Medium option.deerma.humidifier.mjjsq.mode-3 = High option.deerma.humidifier.mjjsq.mode-4 = Humidity +option.dmaker.airfresh.a1.airFreshMode-auto = Auto +option.dmaker.airfresh.a1.airFreshMode-favourite = Favorite +option.dmaker.airfresh.a1.airFreshMode-sleep = Sleep +option.dmaker.airfresh.t2017.airFreshDisplayDirection-forward = Normal +option.dmaker.airfresh.t2017.airFreshDisplayDirection-left = Left +option.dmaker.airfresh.t2017.airFreshDisplayDirection-right = Right +option.dmaker.airfresh.t2017.airFreshMode-auto = Auto +option.dmaker.airfresh.t2017.airFreshMode-favourite = Favorite +option.dmaker.airfresh.t2017.airFreshMode-sleep = Sleep +option.dmaker.airfresh.t2017.airFreshPtcLevel-high = High +option.dmaker.airfresh.t2017.airFreshPtcLevel-low = Low +option.dmaker.airfresh.t2017.airFreshPtcLevel-medium = Medium option.dmaker.fan.p15-miot.actions-off-delay-time-toggle = Off Delay Time Toggle option.dmaker.fan.p15-miot.fan_level-1 = Level1 option.dmaker.fan.p15-miot.fan_level-2 = Level2 @@ -1856,6 +2097,166 @@ option.dreame.vacuum.p2009-miot.vacuumaction-sweep = Sweep option.dreame.vacuum.p2009-miot.vacuumaction-testsound = Test Sound option.dreame.vacuum.p2009-miot.waterbox-status-0 = Status 0 option.dreame.vacuum.p2009-miot.waterbox-status-1 = Status 1 +option.dreame.vacuum.p2027-miot.actions-audio-play-sound = Audio Play Sound +option.dreame.vacuum.p2027-miot.actions-audio-position = Audio Position +option.dreame.vacuum.p2027-miot.actions-battery-start-charge = Battery Start Charge +option.dreame.vacuum.p2027-miot.actions-brush-cleaner-reset-brush-life = Brush Cleaner Reset Brush Life +option.dreame.vacuum.p2027-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.dreame.vacuum.p2027-miot.actions-map-map-req = Map Map Req +option.dreame.vacuum.p2027-miot.actions-map-update-map = Map Update Map +option.dreame.vacuum.p2027-miot.actions-time-delete-timer = Time Delete Timer +option.dreame.vacuum.p2027-miot.actions-vacuum-extend-start-clean = Vacuum Extend Start Clean +option.dreame.vacuum.p2027-miot.actions-vacuum-extend-stop-clean = Vacuum Extend Stop Clean +option.dreame.vacuum.p2027-miot.actions-vacuum-start-room-sweep = Vacuum Start Room Sweep +option.dreame.vacuum.p2027-miot.actions-vacuum-start-sweep = Vacuum Start Sweep +option.dreame.vacuum.p2027-miot.actions-vacuum-stop-sweeping = Vacuum Stop Sweeping +option.dreame.vacuum.p2027-miot.break_point_restart-0 = Off +option.dreame.vacuum.p2027-miot.break_point_restart-1 = On +option.dreame.vacuum.p2027-miot.carpet_press-0 = Off +option.dreame.vacuum.p2027-miot.carpet_press-1 = On +option.dreame.vacuum.p2027-miot.charging_state-1 = Charging +option.dreame.vacuum.p2027-miot.charging_state-2 = Not Charging +option.dreame.vacuum.p2027-miot.charging_state-5 = Go Charging +option.dreame.vacuum.p2027-miot.child_lock-0 = Close +option.dreame.vacuum.p2027-miot.child_lock-1 = Open +option.dreame.vacuum.p2027-miot.cleaning_mode-0 = mode 0 +option.dreame.vacuum.p2027-miot.cleaning_mode-1 = mode 1 +option.dreame.vacuum.p2027-miot.cleaning_mode-2 = mode 2 +option.dreame.vacuum.p2027-miot.cleaning_mode-3 = mode 3 +option.dreame.vacuum.p2027-miot.fault-0 = No Error +option.dreame.vacuum.p2027-miot.fault-1 = Drop +option.dreame.vacuum.p2027-miot.fault-10 = Waterbox Empty +option.dreame.vacuum.p2027-miot.fault-11 = Box full +option.dreame.vacuum.p2027-miot.fault-12 = Brush +option.dreame.vacuum.p2027-miot.fault-13 = Side Brush +option.dreame.vacuum.p2027-miot.fault-14 = Fan +option.dreame.vacuum.p2027-miot.fault-15 = Left Wheel motor +option.dreame.vacuum.p2027-miot.fault-16 = Right Wheel motor +option.dreame.vacuum.p2027-miot.fault-17 = Turn suffocate +option.dreame.vacuum.p2027-miot.fault-18 = Forward suffocate +option.dreame.vacuum.p2027-miot.fault-19 = Charger get +option.dreame.vacuum.p2027-miot.fault-2 = Cliff +option.dreame.vacuum.p2027-miot.fault-20 = Battery low +option.dreame.vacuum.p2027-miot.fault-21 = Charge fault +option.dreame.vacuum.p2027-miot.fault-22 = Battery percentage +option.dreame.vacuum.p2027-miot.fault-23 = Heart +option.dreame.vacuum.p2027-miot.fault-24 = Camera occlusion +option.dreame.vacuum.p2027-miot.fault-25 = Camera fault +option.dreame.vacuum.p2027-miot.fault-26 = Event battery +option.dreame.vacuum.p2027-miot.fault-27 = Forward looking +option.dreame.vacuum.p2027-miot.fault-28 = Gyroscope +option.dreame.vacuum.p2027-miot.fault-3 = Bumper +option.dreame.vacuum.p2027-miot.fault-4 = Gesture +option.dreame.vacuum.p2027-miot.fault-5 = Bumper Repeat +option.dreame.vacuum.p2027-miot.fault-6 = Drop Repeat +option.dreame.vacuum.p2027-miot.fault-7 = Optical Flow +option.dreame.vacuum.p2027-miot.fault-8 = No Box +option.dreame.vacuum.p2027-miot.fault-9 = No Tankbox +option.dreame.vacuum.p2027-miot.mode-0 = Silent +option.dreame.vacuum.p2027-miot.mode-1 = Basic +option.dreame.vacuum.p2027-miot.mode-2 = Strong +option.dreame.vacuum.p2027-miot.mode-3 = Full Speed +option.dreame.vacuum.p2027-miot.mop_mode-1 = low water +option.dreame.vacuum.p2027-miot.mop_mode-2 = medium water +option.dreame.vacuum.p2027-miot.mop_mode-3 = high water +option.dreame.vacuum.p2027-miot.mult_map_state-0 = Close +option.dreame.vacuum.p2027-miot.mult_map_state-1 = Open +option.dreame.vacuum.p2027-miot.status-1 = Sweeping +option.dreame.vacuum.p2027-miot.status-10 = Go Washing +option.dreame.vacuum.p2027-miot.status-11 = Building +option.dreame.vacuum.p2027-miot.status-12 = Sweeping and Mopping +option.dreame.vacuum.p2027-miot.status-13 = Charging Completed +option.dreame.vacuum.p2027-miot.status-2 = Idle +option.dreame.vacuum.p2027-miot.status-3 = Paused +option.dreame.vacuum.p2027-miot.status-4 = Error +option.dreame.vacuum.p2027-miot.status-5 = Go Charging +option.dreame.vacuum.p2027-miot.status-6 = Charging +option.dreame.vacuum.p2027-miot.status-7 = Mopping +option.dreame.vacuum.p2027-miot.status-8 = Drying +option.dreame.vacuum.p2027-miot.status-9 = Washing +option.dreame.vacuum.p2027-miot.task_status-0 = Notask +option.dreame.vacuum.p2027-miot.task_status-1 = AutoClean +option.dreame.vacuum.p2027-miot.task_status-2 = CustomClean +option.dreame.vacuum.p2027-miot.task_status-3 = SelectAreanClean +option.dreame.vacuum.p2027-miot.task_status-4 = SpotArea +option.dreame.vacuum.p2027-miot.waterbox_status-0 = Status 0 +option.dreame.vacuum.p2027-miot.waterbox_status-1 = Status 1 +option.dreame.vacuum.p2028-miot.actions-audio-play-sound = Audio Play Sound +option.dreame.vacuum.p2028-miot.actions-audio-position = Audio Position +option.dreame.vacuum.p2028-miot.actions-battery-start-charge = Battery Start Charge +option.dreame.vacuum.p2028-miot.actions-brush-cleaner-reset-brush-life = Brush Cleaner Reset Brush Life +option.dreame.vacuum.p2028-miot.actions-collect-dust-start-collect = Collect Dust Start Collect +option.dreame.vacuum.p2028-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.dreame.vacuum.p2028-miot.actions-map-map-req = Map Map Req +option.dreame.vacuum.p2028-miot.actions-map-update-map = Map Update Map +option.dreame.vacuum.p2028-miot.actions-time-delete-timer = Time Delete Timer +option.dreame.vacuum.p2028-miot.actions-vacuum-extend-start-clean = Vacuum Extend Start Clean +option.dreame.vacuum.p2028-miot.actions-vacuum-extend-stop-clean = Vacuum Extend Stop Clean +option.dreame.vacuum.p2028-miot.actions-vacuum-start-sweep = Vacuum Start Sweep +option.dreame.vacuum.p2028-miot.actions-vacuum-stop-sweeping = Vacuum Stop Sweeping +option.dreame.vacuum.p2028-miot.auto_collect-0 = Close-auto-collect +option.dreame.vacuum.p2028-miot.auto_collect-1 = Open-auto-collect +option.dreame.vacuum.p2028-miot.break_point_restart-0 = Off +option.dreame.vacuum.p2028-miot.break_point_restart-1 = On +option.dreame.vacuum.p2028-miot.carpet_press-0 = Off +option.dreame.vacuum.p2028-miot.carpet_press-1 = On +option.dreame.vacuum.p2028-miot.charging_state-1 = Charging +option.dreame.vacuum.p2028-miot.charging_state-2 = Not Charging +option.dreame.vacuum.p2028-miot.charging_state-5 = Go Charging +option.dreame.vacuum.p2028-miot.cleaning_mode-0 = mode 0 +option.dreame.vacuum.p2028-miot.cleaning_mode-1 = mode 1 +option.dreame.vacuum.p2028-miot.cleaning_mode-2 = mode 2 +option.dreame.vacuum.p2028-miot.cleaning_mode-3 = mode 3 +option.dreame.vacuum.p2028-miot.dust_enable-0 = Disable +option.dreame.vacuum.p2028-miot.dust_enable-1 = Enable +option.dreame.vacuum.p2028-miot.fault-0 = No Error +option.dreame.vacuum.p2028-miot.fault-1 = Drop +option.dreame.vacuum.p2028-miot.fault-10 = Waterbox Empty +option.dreame.vacuum.p2028-miot.fault-11 = Box full +option.dreame.vacuum.p2028-miot.fault-12 = Brush +option.dreame.vacuum.p2028-miot.fault-13 = Side Brush +option.dreame.vacuum.p2028-miot.fault-14 = Fan +option.dreame.vacuum.p2028-miot.fault-15 = Left Wheel motor +option.dreame.vacuum.p2028-miot.fault-16 = Right Wheel motor +option.dreame.vacuum.p2028-miot.fault-17 = Turn suffocate +option.dreame.vacuum.p2028-miot.fault-18 = Forward suffocate +option.dreame.vacuum.p2028-miot.fault-19 = Charger get +option.dreame.vacuum.p2028-miot.fault-2 = Cliff +option.dreame.vacuum.p2028-miot.fault-20 = Battery low +option.dreame.vacuum.p2028-miot.fault-21 = Charge fault +option.dreame.vacuum.p2028-miot.fault-22 = Battery percentage +option.dreame.vacuum.p2028-miot.fault-23 = Heart +option.dreame.vacuum.p2028-miot.fault-24 = Camera occlusion +option.dreame.vacuum.p2028-miot.fault-25 = Camera fault +option.dreame.vacuum.p2028-miot.fault-26 = Event battery +option.dreame.vacuum.p2028-miot.fault-27 = Forward looking +option.dreame.vacuum.p2028-miot.fault-28 = Gyroscope +option.dreame.vacuum.p2028-miot.fault-3 = Bumper +option.dreame.vacuum.p2028-miot.fault-4 = Gesture +option.dreame.vacuum.p2028-miot.fault-5 = Bumper Repeat +option.dreame.vacuum.p2028-miot.fault-6 = Drop Repeat +option.dreame.vacuum.p2028-miot.fault-7 = Optical Flow +option.dreame.vacuum.p2028-miot.fault-8 = No Box +option.dreame.vacuum.p2028-miot.fault-9 = No Tankbox +option.dreame.vacuum.p2028-miot.mop_mode-1 = low water +option.dreame.vacuum.p2028-miot.mop_mode-2 = medium water +option.dreame.vacuum.p2028-miot.mop_mode-3 = high water +option.dreame.vacuum.p2028-miot.mult_map_state-0 = Close +option.dreame.vacuum.p2028-miot.mult_map_state-1 = Open +option.dreame.vacuum.p2028-miot.status-1 = Sweeping +option.dreame.vacuum.p2028-miot.status-2 = Idle +option.dreame.vacuum.p2028-miot.status-3 = Paused +option.dreame.vacuum.p2028-miot.status-4 = Error +option.dreame.vacuum.p2028-miot.status-5 = Go Charging +option.dreame.vacuum.p2028-miot.status-6 = Charging +option.dreame.vacuum.p2028-miot.status-7 = Mopping +option.dreame.vacuum.p2028-miot.task_status-0 = Notask +option.dreame.vacuum.p2028-miot.task_status-1 = AutoClean +option.dreame.vacuum.p2028-miot.task_status-2 = CustomClean +option.dreame.vacuum.p2028-miot.task_status-3 = SelectAreanClean +option.dreame.vacuum.p2028-miot.task_status-4 = SpotArea +option.dreame.vacuum.p2028-miot.waterbox_status-0 = Status 0 +option.dreame.vacuum.p2028-miot.waterbox_status-1 = Status 1 option.dreame.vacuum.p2156o-miot.actions-audio-play-sound = Audio Play Sound option.dreame.vacuum.p2156o-miot.actions-audio-position = Audio Position option.dreame.vacuum.p2156o-miot.actions-battery-start-charge = Start Charge @@ -1902,6 +2303,82 @@ option.dreame.vacuum.p2156o-miot.task_status-3 = SelectAreanClean option.dreame.vacuum.p2156o-miot.task_status-4 = SpotArea option.dreame.vacuum.p2156o-miot.waterbox_status-0 = Status 0 option.dreame.vacuum.p2156o-miot.waterbox_status-1 = Status 1 +option.dreame.vacuum.p2259-miot.actions-audio-play-sound = Audio Play Sound +option.dreame.vacuum.p2259-miot.actions-audio-position = Audio Position +option.dreame.vacuum.p2259-miot.actions-battery-start-charge = Battery Start Charge +option.dreame.vacuum.p2259-miot.actions-brush-cleaner-reset-brush-life = Brush Cleaner Reset Brush Life +option.dreame.vacuum.p2259-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.dreame.vacuum.p2259-miot.actions-map-map-req = Map Map Req +option.dreame.vacuum.p2259-miot.actions-map-update-map = Map Update Map +option.dreame.vacuum.p2259-miot.actions-time-delete-timer = Time Delete Timer +option.dreame.vacuum.p2259-miot.actions-vacuum-extend-start-clean = Vacuum Extend Start Clean +option.dreame.vacuum.p2259-miot.actions-vacuum-extend-stop-clean = Vacuum Extend Stop Clean +option.dreame.vacuum.p2259-miot.actions-vacuum-start-room-sweep = Vacuum Start Room Sweep +option.dreame.vacuum.p2259-miot.actions-vacuum-start-sweep = Vacuum Start Sweep +option.dreame.vacuum.p2259-miot.actions-vacuum-stop-sweeping = Vacuum Stop Sweeping +option.dreame.vacuum.p2259-miot.break_point_restart-0 = Off +option.dreame.vacuum.p2259-miot.break_point_restart-1 = On +option.dreame.vacuum.p2259-miot.carpet_press-0 = Off +option.dreame.vacuum.p2259-miot.carpet_press-1 = On +option.dreame.vacuum.p2259-miot.charging_state-1 = Charging +option.dreame.vacuum.p2259-miot.charging_state-2 = Not Charging +option.dreame.vacuum.p2259-miot.charging_state-5 = Go Charging +option.dreame.vacuum.p2259-miot.cleaning_mode-0 = mode 0 +option.dreame.vacuum.p2259-miot.cleaning_mode-1 = mode 1 +option.dreame.vacuum.p2259-miot.cleaning_mode-2 = mode 2 +option.dreame.vacuum.p2259-miot.cleaning_mode-3 = mode 3 +option.dreame.vacuum.p2259-miot.fault-0 = No Error +option.dreame.vacuum.p2259-miot.fault-1 = Drop +option.dreame.vacuum.p2259-miot.fault-10 = Waterbox Empty +option.dreame.vacuum.p2259-miot.fault-11 = Box full +option.dreame.vacuum.p2259-miot.fault-12 = Brush +option.dreame.vacuum.p2259-miot.fault-13 = Side Brush +option.dreame.vacuum.p2259-miot.fault-14 = Fan +option.dreame.vacuum.p2259-miot.fault-15 = Left Wheel motor +option.dreame.vacuum.p2259-miot.fault-16 = Right Wheel motor +option.dreame.vacuum.p2259-miot.fault-17 = Turn suffocate +option.dreame.vacuum.p2259-miot.fault-18 = Forward suffocate +option.dreame.vacuum.p2259-miot.fault-19 = Charger get +option.dreame.vacuum.p2259-miot.fault-2 = Cliff +option.dreame.vacuum.p2259-miot.fault-20 = Battery low +option.dreame.vacuum.p2259-miot.fault-21 = Charge fault +option.dreame.vacuum.p2259-miot.fault-22 = Battery percentage +option.dreame.vacuum.p2259-miot.fault-23 = Heart +option.dreame.vacuum.p2259-miot.fault-24 = Camera occlusion +option.dreame.vacuum.p2259-miot.fault-25 = Camera fault +option.dreame.vacuum.p2259-miot.fault-26 = Event battery +option.dreame.vacuum.p2259-miot.fault-27 = Forward looking +option.dreame.vacuum.p2259-miot.fault-28 = Gyroscope +option.dreame.vacuum.p2259-miot.fault-3 = Bumper +option.dreame.vacuum.p2259-miot.fault-4 = Gesture +option.dreame.vacuum.p2259-miot.fault-5 = Bumper Repeat +option.dreame.vacuum.p2259-miot.fault-6 = Drop Repeat +option.dreame.vacuum.p2259-miot.fault-7 = Optical Flow +option.dreame.vacuum.p2259-miot.fault-8 = No Box +option.dreame.vacuum.p2259-miot.fault-9 = No Tankbox +option.dreame.vacuum.p2259-miot.mode-0 = Silent +option.dreame.vacuum.p2259-miot.mode-1 = Basic +option.dreame.vacuum.p2259-miot.mode-2 = Strong +option.dreame.vacuum.p2259-miot.mode-3 = Full Speed +option.dreame.vacuum.p2259-miot.mop_mode-1 = low water +option.dreame.vacuum.p2259-miot.mop_mode-2 = medium water +option.dreame.vacuum.p2259-miot.mop_mode-3 = high water +option.dreame.vacuum.p2259-miot.mult_map_state-0 = Close +option.dreame.vacuum.p2259-miot.mult_map_state-1 = Open +option.dreame.vacuum.p2259-miot.status-1 = Sweeping +option.dreame.vacuum.p2259-miot.status-2 = Idle +option.dreame.vacuum.p2259-miot.status-3 = Paused +option.dreame.vacuum.p2259-miot.status-4 = Error +option.dreame.vacuum.p2259-miot.status-5 = Go Charging +option.dreame.vacuum.p2259-miot.status-6 = Charging +option.dreame.vacuum.p2259-miot.status-7 = Mopping +option.dreame.vacuum.p2259-miot.task_status-0 = Notask +option.dreame.vacuum.p2259-miot.task_status-1 = AutoClean +option.dreame.vacuum.p2259-miot.task_status-2 = CustomClean +option.dreame.vacuum.p2259-miot.task_status-3 = SelectAreanClean +option.dreame.vacuum.p2259-miot.task_status-4 = SpotArea +option.dreame.vacuum.p2259-miot.waterbox_status-0 = Status 0 +option.dreame.vacuum.p2259-miot.waterbox_status-1 = Status 1 option.huayi.light.fanwy-miot.mode-1 = Normal Wind option.huayi.light.fanwy-miot.mode-2 = Natural Wind option.huayi.light.fanwy2-miot.mode-0 = Basic @@ -1911,11 +2388,15 @@ option.huayi.light.fanwy2-miot.pre-custom-1 = Open option.huayi.light.fanwy2-miot.reversal-0 = Postitive option.huayi.light.fanwy2-miot.reversal-1 = Reverse option.huayi.light.wyheat-miot.fault-0 = No Faults -option.lumi.curtain.hagl05-miot.en-night-tip-light-0 = Disable -option.lumi.curtain.hagl05-miot.en-night-tip-light-1 = Enable +option.lumi.curtain.hagl05-miot.en_night_tip_light-0 = Disable +option.lumi.curtain.hagl05-miot.en_night_tip_light-1 = Enable option.lumi.curtain.hagl05-miot.fault-0 = No faults option.lumi.curtain.hagl05-miot.manual-enabled-0 = Disable option.lumi.curtain.hagl05-miot.manual-enabled-1 = Enable +option.lumi.curtain.hagl05-miot.motor_control-0 = Pause +option.lumi.curtain.hagl05-miot.motor_control-1 = Open +option.lumi.curtain.hagl05-miot.motor_control-2 = Close +option.lumi.curtain.hagl05-miot.motor_control-3 = auto option.lumi.curtain.hagl05-miot.polarity-0 = Positive option.lumi.curtain.hagl05-miot.polarity-1 = Reverse option.lumi.curtain.hagl05-miot.pos-limit-0 = Unlimit @@ -1983,8 +2464,99 @@ option.mmgg.pet_waterer.s2-miot.mode-2 = Smart option.mmgg.pet_waterer.s2-miot.resetConsumable-filter-cotton-reset-cotton-life = Reset Cotton Time option.mmgg.pet_waterer.s2-miot.resetConsumable-filter-reset-filter-life = Reset Filter Life option.mmgg.pet_waterer.s2-miot.resetConsumable-remain-clean-time-reset-clean-time = Reset Clean Time +option.philips.light.ceil-miot.actions-light-brightness-down = Light Brightness Down +option.philips.light.ceil-miot.actions-light-brightness-up = Light Brightness Up +option.philips.light.ceil-miot.actions-light-toggle = Light Toggle option.qmi.powerstrip.v1.mode-green = Green option.qmi.powerstrip.v1.mode-normal = Normal +option.roidmi.vacuum.v60-miot.actions-battery-start-charge = Battery Start Charge +option.roidmi.vacuum.v60-miot.actions-brush-cleaner-reset-brush-life = Brush Cleaner Reset Brush Life +option.roidmi.vacuum.v60-miot.actions-custom-continue-find-charge = Custom Continue Find Charge +option.roidmi.vacuum.v60-miot.actions-custom-continue-sweep = Custom Continue Sweep +option.roidmi.vacuum.v60-miot.actions-custom-find-robot = Custom Find Robot +option.roidmi.vacuum.v60-miot.actions-custom-pause = Custom Pause +option.roidmi.vacuum.v60-miot.actions-custom-pause-find-charge = Custom Pause Find Charge +option.roidmi.vacuum.v60-miot.actions-custom-set-voice = Custom Set Voice +option.roidmi.vacuum.v60-miot.actions-custom-start-dust = Custom Start Dust +option.roidmi.vacuum.v60-miot.actions-custom-stop-find-charge = Custom Stop Find Charge +option.roidmi.vacuum.v60-miot.actions-custom-update-audio = Custom Update Audio +option.roidmi.vacuum.v60-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.roidmi.vacuum.v60-miot.actions-map-area-custom = Map Area Custom +option.roidmi.vacuum.v60-miot.actions-map-area-order = Map Area Order +option.roidmi.vacuum.v60-miot.actions-map-change-area-name = Map Change Area Name +option.roidmi.vacuum.v60-miot.actions-map-local-map = Map Local Map +option.roidmi.vacuum.v60-miot.actions-map-request-path = Map Request Path +option.roidmi.vacuum.v60-miot.actions-map-set-auto-area = Map Set Auto Area +option.roidmi.vacuum.v60-miot.actions-sweep-start-sweep = Sweep Start Sweep +option.roidmi.vacuum.v60-miot.actions-vacuum-start-room-sweep = Vacuum Start Room Sweep +option.roidmi.vacuum.v60-miot.actions-vacuum-start-sweep = Vacuum Start Sweep +option.roidmi.vacuum.v60-miot.actions-vacuum-stop-sweeping = Vacuum Stop Sweeping +option.roidmi.vacuum.v60-miot.charging_state-1 = Charging +option.roidmi.vacuum.v60-miot.charging_state-2 = Not charging +option.roidmi.vacuum.v60-miot.charging_state-3 = Not chargeable +option.roidmi.vacuum.v60-miot.fault-0 = No Faults +option.roidmi.vacuum.v60-miot.fault-1 = Low Battery Find Charger +option.roidmi.vacuum.v60-miot.fault-10 = Sid Brush +option.roidmi.vacuum.v60-miot.fault-11 = Fan Speed Error +option.roidmi.vacuum.v60-miot.fault-12 = Lidar Cover +option.roidmi.vacuum.v60-miot.fault-13 = Garbage Box Full +option.roidmi.vacuum.v60-miot.fault-14 = Garbage Box Out +option.roidmi.vacuum.v60-miot.fault-15 = Garbage Box Full Out +option.roidmi.vacuum.v60-miot.fault-16 = Physical Trapped +option.roidmi.vacuum.v60-miot.fault-17 = Pick Up Do Task +option.roidmi.vacuum.v60-miot.fault-18 = No Water Box Do Task +option.roidmi.vacuum.v60-miot.fault-19 = Water Box Empty +option.roidmi.vacuum.v60-miot.fault-2 = Low Battery And Poweroff +option.roidmi.vacuum.v60-miot.fault-20 = Clean Cannot Arrive +option.roidmi.vacuum.v60-miot.fault-21 = Start Form Forbid +option.roidmi.vacuum.v60-miot.fault-22 = Drop +option.roidmi.vacuum.v60-miot.fault-23 = Kit Water Pump +option.roidmi.vacuum.v60-miot.fault-24 = Find Charger Failed +option.roidmi.vacuum.v60-miot.fault-25 = Low Power Clean +option.roidmi.vacuum.v60-miot.fault-3 = Wheel Trap +option.roidmi.vacuum.v60-miot.fault-4 = Collision Error +option.roidmi.vacuum.v60-miot.fault-5 = Tile Do Task +option.roidmi.vacuum.v60-miot.fault-6 = Lidar Point Error +option.roidmi.vacuum.v60-miot.fault-7 = Front Wall Error +option.roidmi.vacuum.v60-miot.fault-8 = Psd Dirty +option.roidmi.vacuum.v60-miot.fault-9 = Middle Brush Fatal +option.roidmi.vacuum.v60-miot.mode-0 = Sweep +option.roidmi.vacuum.v60-miot.mode-1 = Silent +option.roidmi.vacuum.v60-miot.mode-2 = Basic +option.roidmi.vacuum.v60-miot.mode-3 = Strong +option.roidmi.vacuum.v60-miot.mode-4 = Full Speed +option.roidmi.vacuum.v60-miot.on-1 = Open +option.roidmi.vacuum.v60-miot.path_type-0 = Normal +option.roidmi.vacuum.v60-miot.path_type-1 = Y-Mopping +option.roidmi.vacuum.v60-miot.path_type-2 = Repeat-Mopping +option.roidmi.vacuum.v60-miot.status-1 = Dormant +option.roidmi.vacuum.v60-miot.status-10 = Shutdown +option.roidmi.vacuum.v60-miot.status-11 = Findchargerpause +option.roidmi.vacuum.v60-miot.status-2 = Idle +option.roidmi.vacuum.v60-miot.status-3 = Paused +option.roidmi.vacuum.v60-miot.status-4 = Sweeping +option.roidmi.vacuum.v60-miot.status-5 = Go Charging +option.roidmi.vacuum.v60-miot.status-6 = Charging +option.roidmi.vacuum.v60-miot.status-7 = Error +option.roidmi.vacuum.v60-miot.status-8 = Rfctrl +option.roidmi.vacuum.v60-miot.status-9 = Fullcharge +option.roidmi.vacuum.v60-miot.sweep_mode-0 = Idle +option.roidmi.vacuum.v60-miot.sweep_mode-1 = Total +option.roidmi.vacuum.v60-miot.sweep_mode-10 = AlongWall +option.roidmi.vacuum.v60-miot.sweep_mode-2 = Area +option.roidmi.vacuum.v60-miot.sweep_mode-3 = Curpoint +option.roidmi.vacuum.v60-miot.sweep_mode-4 = Point +option.roidmi.vacuum.v60-miot.sweep_mode-7 = Smart +option.roidmi.vacuum.v60-miot.sweep_mode-8 = AmartArea +option.roidmi.vacuum.v60-miot.sweep_mode-9 = DepthTotal +option.roidmi.vacuum.v60-miot.sweep_type-0 = Sweep +option.roidmi.vacuum.v60-miot.sweep_type-1 = Mop +option.roidmi.vacuum.v60-miot.sweep_type-2 = Mop And Sweep +option.roidmi.vacuum.v60-miot.water_level-0 = Mop +option.roidmi.vacuum.v60-miot.water_level-1 = First +option.roidmi.vacuum.v60-miot.water_level-2 = Second +option.roidmi.vacuum.v60-miot.water_level-3 = Three +option.roidmi.vacuum.v60-miot.water_level-4 = Fourth option.viomi.vacuum.v18-miot.clean-mode-0 = Everywhere option.viomi.vacuum.v18-miot.clean-mode-1 = Edges option.viomi.vacuum.v18-miot.clean-mode-2 = Surface @@ -2202,6 +2774,11 @@ option.yunmi.waterpurifier.lightMode-0 = Simple Mode option.yunmi.waterpurifier.lightMode-1 = Special Mode option.yunmi.waterpurifier.lx8.lightMode-0 = Simple Mode option.yunmi.waterpurifier.lx8.lightMode-1 = Special Mode +option.zhimi.airfresh.ua1-miot.actions-filter-reset-filter-life = Filter Reset Filter Life +option.zhimi.airfresh.ua1-miot.fan_level-1 = Level1 +option.zhimi.airfresh.ua1-miot.fan_level-2 = Level2 +option.zhimi.airfresh.ua1-miot.fan_level-3 = Level3 +option.zhimi.airfresh.ua1-miot.fault-0 = No Faults option.zhimi.airfresh.va4.led_level-0 = High option.zhimi.airfresh.va4.led_level-1 = Low option.zhimi.airfresh.va4.led_level-2 = Idle @@ -2400,6 +2977,9 @@ option.zhimi.fan.v3.led_b-2 = Off option.zhimi.fan.v3.move- = None option.zhimi.fan.v3.move-left = Left option.zhimi.fan.v3.move-right = Right +option.zhimi.fan.za4.move- = None +option.zhimi.fan.za4.move-left = Left +option.zhimi.fan.za4.move-right = Right option.zhimi.fan.za5-miot.button_press-0 = No Button Pressed option.zhimi.fan.za5-miot.button_press-1 = power option.zhimi.fan.za5-miot.button_press-2 = swing diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/roidmi.vacuum.v60-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/roidmi.vacuum.v60-miot.json new file mode 100644 index 0000000000000..fbe1ac6820713 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/roidmi.vacuum.v60-miot.json @@ -0,0 +1,1566 @@ +{ + "deviceMapping": { + "id": [ + "roidmi.vacuum.v60" + ], + "propertyMethod": "get_properties", + "maxProperties": 1, + "channels": [ + { + "property": "", + "friendlyName": "Actions", + "channel": "actions", + "type": "String", + "stateDescription": { + "options": [ + { + "value": "vacuum-start-sweep", + "label": "Vacuum Start Sweep" + }, + { + "value": "vacuum-stop-sweeping", + "label": "Vacuum Stop Sweeping" + }, + { + "value": "vacuum-start-room-sweep", + "label": "Vacuum Start Room Sweep" + }, + { + "value": "battery-start-charge", + "label": "Battery Start Charge" + }, + { + "value": "filter-reset-filter-life", + "label": "Filter Reset Filter Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "brush-cleaner-reset-brush-life", + "label": "Brush Cleaner Reset Brush Life" + }, + { + "value": "custom-find-robot", + "label": "Custom Find Robot" + }, + { + "value": "custom-stop-find-charge", + "label": "Custom Stop Find Charge" + }, + { + "value": "custom-continue-sweep", + "label": "Custom Continue Sweep" + }, + { + "value": "custom-start-dust", + "label": "Custom Start Dust" + }, + { + "value": "custom-pause", + "label": "Custom Pause" + }, + { + "value": "custom-pause-find-charge", + "label": "Custom Pause Find Charge" + }, + { + "value": "custom-continue-find-charge", + "label": "Custom Continue Find Charge" + }, + { + "value": "custom-update-audio", + "label": "Custom Update Audio" + }, + { + "value": "custom-set-voice", + "label": "Custom Set Voice" + }, + { + "value": "map-request-path", + "label": "Map Request Path" + }, + { + "value": "map-change-area-name", + "label": "Map Change Area Name" + }, + { + "value": "map-set-auto-area", + "label": "Map Set Auto Area" + }, + { + "value": "map-local-map", + "label": "Map Local Map" + }, + { + "value": "map-area-custom", + "label": "Map Area Custom" + }, + { + "value": "map-area-order", + "label": "Map Area Order" + }, + { + "value": "sweep-start-sweep", + "label": "Sweep Start Sweep" + } + ] + }, + "refresh": false, + "actions": [ + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 2, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-stop-sweeping" + } + ] + } + }, + { + "command": "action", + "parameterType": "UNKNOWN", + "parameters": [ + 9.0 + ], + "siid": 2, + "aiid": 3, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "vacuum-start-room-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 3, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "battery-start-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 10, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "filter-reset-filter-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 11, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 12, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 15, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "brush-cleaner-reset-brush-life" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-find-robot" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 4, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-stop-find-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 5, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-continue-sweep" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 6, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-start-dust" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 8, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-pause" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 9, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-pause-find-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "EMPTY", + "siid": 8, + "aiid": 10, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-continue-find-charge" + } + ] + } + }, + { + "command": "action", + "parameterType": "UNKNOWN", + "parameters": [ + 27.0 + ], + "siid": 8, + "aiid": 11, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-update-audio" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 27.0 + ], + "siid": 8, + "aiid": 12, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "custom-set-voice" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 2.0 + ], + "siid": 13, + "aiid": 2, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-request-path" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 6.0 + ], + "siid": 13, + "aiid": 4, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-change-area-name" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 4.0 + ], + "siid": 13, + "aiid": 6, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-set-auto-area" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 6.0 + ], + "siid": 13, + "aiid": 9, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-local-map" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 4.0 + ], + "siid": 13, + "aiid": 10, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-area-custom" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 4.0 + ], + "siid": 13, + "aiid": 11, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "map-area-order" + } + ] + } + }, + { + "command": "action", + "parameterType": "NONE", + "parameters": [ + 1, + 2.0 + ], + "siid": 14, + "aiid": 1, + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "sweep-start-sweep" + } + ] + } + } + ], + "category": "switch", + "tags": [ + "Switch" + ], + "readmeComment": "Value mapping `[\"vacuum-start-sweep\"\u003d\"Vacuum Start Sweep\",\"vacuum-stop-sweeping\"\u003d\"Vacuum Stop Sweeping\",\"vacuum-start-room-sweep\"\u003d\"Vacuum Start Room Sweep\",\"battery-start-charge\"\u003d\"Battery Start Charge\",\"filter-reset-filter-life\"\u003d\"Filter Reset Filter Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"brush-cleaner-reset-brush-life\"\u003d\"Brush Cleaner Reset Brush Life\",\"custom-find-robot\"\u003d\"Custom Find Robot\",\"custom-stop-find-charge\"\u003d\"Custom Stop Find Charge\",\"custom-continue-sweep\"\u003d\"Custom Continue Sweep\",\"custom-start-dust\"\u003d\"Custom Start Dust\",\"custom-pause\"\u003d\"Custom Pause\",\"custom-pause-find-charge\"\u003d\"Custom Pause Find Charge\",\"custom-continue-find-charge\"\u003d\"Custom Continue Find Charge\",\"custom-update-audio\"\u003d\"Custom Update Audio\",\"custom-set-voice\"\u003d\"Custom Set Voice\",\"map-request-path\"\u003d\"Map Request Path\",\"map-change-area-name\"\u003d\"Map Change Area Name\",\"map-set-auto-area\"\u003d\"Map Set Auto Area\",\"map-local-map\"\u003d\"Map Local Map\",\"map-area-custom\"\u003d\"Map Area Custom\",\"map-area-order\"\u003d\"Map Area Order\",\"sweep-start-sweep\"\u003d\"Sweep Start Sweep\"]`" + }, + { + "property": "status", + "siid": 2, + "piid": 1, + "friendlyName": "Robot Cleaner - Status", + "channel": "status", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Dormant" + }, + { + "value": "2", + "label": "Idle" + }, + { + "value": "3", + "label": "Paused" + }, + { + "value": "4", + "label": "Sweeping" + }, + { + "value": "5", + "label": "Go Charging" + }, + { + "value": "6", + "label": "Charging" + }, + { + "value": "7", + "label": "Error" + }, + { + "value": "8", + "label": "Rfctrl" + }, + { + "value": "9", + "label": "Fullcharge" + }, + { + "value": "10", + "label": "Shutdown" + }, + { + "value": "11", + "label": "Findchargerpause" + } + ] + }, + "refresh": true, + "actions": [], + "category": "Switch", + "tags": [ + "Switch" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Dormant\",\"2\"\u003d\"Idle\",\"3\"\u003d\"Paused\",\"4\"\u003d\"Sweeping\",\"5\"\u003d\"Go Charging\",\"6\"\u003d\"Charging\",\"7\"\u003d\"Error\",\"8\"\u003d\"Rfctrl\",\"9\"\u003d\"Fullcharge\",\"10\"\u003d\"Shutdown\",\"11\"\u003d\"Findchargerpause\"]`" + }, + { + "property": "fault", + "siid": 2, + "piid": 2, + "friendlyName": "Robot Cleaner - Device Fault", + "channel": "fault", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "0", + "label": "No Faults" + }, + { + "value": "1", + "label": "Low Battery Find Charger" + }, + { + "value": "2", + "label": "Low Battery And Poweroff" + }, + { + "value": "3", + "label": "Wheel Trap" + }, + { + "value": "4", + "label": "Collision Error" + }, + { + "value": "5", + "label": "Tile Do Task" + }, + { + "value": "6", + "label": "Lidar Point Error" + }, + { + "value": "7", + "label": "Front Wall Error" + }, + { + "value": "8", + "label": "Psd Dirty" + }, + { + "value": "9", + "label": "Middle Brush Fatal" + }, + { + "value": "10", + "label": "Sid Brush" + }, + { + "value": "11", + "label": "Fan Speed Error" + }, + { + "value": "12", + "label": "Lidar Cover" + }, + { + "value": "13", + "label": "Garbage Box Full" + }, + { + "value": "14", + "label": "Garbage Box Out" + }, + { + "value": "15", + "label": "Garbage Box Full Out" + }, + { + "value": "16", + "label": "Physical Trapped" + }, + { + "value": "17", + "label": "Pick Up Do Task" + }, + { + "value": "18", + "label": "No Water Box Do Task" + }, + { + "value": "19", + "label": "Water Box Empty" + }, + { + "value": "20", + "label": "Clean Cannot Arrive" + }, + { + "value": "21", + "label": "Start Form Forbid" + }, + { + "value": "22", + "label": "Drop" + }, + { + "value": "23", + "label": "Kit Water Pump" + }, + { + "value": "24", + "label": "Find Charger Failed" + }, + { + "value": "25", + "label": "Low Power Clean" + } + ] + }, + "refresh": true, + "actions": [], + "category": "error", + "tags": [ + "Status" + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"No Faults\",\"1\"\u003d\"Low Battery Find Charger\",\"2\"\u003d\"Low Battery And Poweroff\",\"3\"\u003d\"Wheel Trap\",\"4\"\u003d\"Collision Error\",\"5\"\u003d\"Tile Do Task\",\"6\"\u003d\"Lidar Point Error\",\"7\"\u003d\"Front Wall Error\",\"8\"\u003d\"Psd Dirty\",\"9\"\u003d\"Middle Brush Fatal\",\"10\"\u003d\"Sid Brush\",\"11\"\u003d\"Fan Speed Error\",\"12\"\u003d\"Lidar Cover\",\"13\"\u003d\"Garbage Box Full\",\"14\"\u003d\"Garbage Box Out\",\"15\"\u003d\"Garbage Box Full Out\",\"16\"\u003d\"Physical Trapped\",\"17\"\u003d\"Pick Up Do Task\",\"18\"\u003d\"No Water Box Do Task\",\"19\"\u003d\"Water Box Empty\",\"20\"\u003d\"Clean Cannot Arrive\",\"21\"\u003d\"Start Form Forbid\",\"22\"\u003d\"Drop\",\"23\"\u003d\"Kit Water Pump\",\"24\"\u003d\"Find Charger Failed\",\"25\"\u003d\"Low Power Clean\"]`" + }, + { + "property": "mode", + "siid": 2, + "piid": 4, + "friendlyName": "Robot Cleaner - Mode", + "channel": "mode", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "Silent" + }, + { + "value": "2", + "label": "Basic" + }, + { + "value": "3", + "label": "Strong" + }, + { + "value": "4", + "label": "Full Speed" + }, + { + "value": "0", + "label": "Sweep" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "category": "setting", + "readmeComment": "Value mapping `[\"1\"\u003d\"Silent\",\"2\"\u003d\"Basic\",\"3\"\u003d\"Strong\",\"4\"\u003d\"Full Speed\",\"0\"\u003d\"Sweep\"]`" + }, + { + "property": "sweep-type", + "siid": 2, + "piid": 8, + "friendlyName": "Robot Cleaner - Sweep Type", + "channel": "sweep_type", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Sweep" + }, + { + "value": "1", + "label": "Mop" + }, + { + "value": "2", + "label": "Mop And Sweep" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "category": "setting", + "readmeComment": "Value mapping `[\"0\"\u003d\"Sweep\",\"1\"\u003d\"Mop\",\"2\"\u003d\"Mop And Sweep\"]`" + }, + { + "property": "on", + "siid": 2, + "piid": 10, + "friendlyName": "Robot Cleaner - Switch Status", + "channel": "on", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "Open" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "category": "switch", + "tags": [ + "Switch" + ], + "readmeComment": "Value mapping `[\"1\"\u003d\"Open\"]`" + }, + { + "property": "battery-level", + "siid": 3, + "piid": 1, + "friendlyName": "Battery - Battery Level", + "channel": "battery_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "batterylevel" + }, + { + "property": "charging-state", + "siid": 3, + "piid": 2, + "friendlyName": "Battery - Charging State", + "channel": "charging_state", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Charging" + }, + { + "value": "2", + "label": "Not charging" + }, + { + "value": "3", + "label": "Not chargeable" + } + ] + }, + "refresh": true, + "actions": [], + "category": "batterylevel", + "readmeComment": "Value mapping `[\"1\"\u003d\"Charging\",\"2\"\u003d\"Not charging\",\"3\"\u003d\"Not chargeable\"]`" + }, + { + "property": "volume", + "siid": 9, + "piid": 1, + "friendlyName": "Speaker - Volume", + "channel": "volume", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 1, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "category": "soundvolume", + "tags": [ + "Setpoint", + "SoundVolume" + ] + }, + { + "property": "mute", + "siid": 9, + "piid": 2, + "friendlyName": "Speaker - Mute", + "channel": "mute", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ], + "category": "soundvolume_mute" + }, + { + "property": "filter-life-level", + "siid": 10, + "piid": 1, + "friendlyName": "Filter - Filter Life Level", + "channel": "filter_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "filter-left-time", + "siid": 10, + "piid": 2, + "friendlyName": "Filter - Filter Left Time", + "channel": "filter_left_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 10000, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "brush-left-time", + "siid": 11, + "piid": 1, + "friendlyName": "Brush Cleaner - Brush Left Time", + "channel": "brush_left_time", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 65535, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "brush-life-level", + "siid": 11, + "piid": 2, + "friendlyName": "Brush Cleaner - Brush Life Level", + "channel": "brush_life_level", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "brush-left-time1", + "siid": 12, + "piid": 1, + "friendlyName": "Brush Cleaner - Brush Left Time", + "channel": "brush_left_time1", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 10000, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "time" + }, + { + "property": "brush-life-level1", + "siid": 12, + "piid": 2, + "friendlyName": "Brush Cleaner - Brush Life Level", + "channel": "brush_life_level1", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 100, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "brush-left-time2", + "siid": 15, + "piid": 1, + "friendlyName": "Brush Cleaner - Brush Left Time", + "channel": "brush_left_time2", + "type": "Number:Time", + "unit": "minutes", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "time" + }, + { + "property": "brush-life-level2", + "siid": 15, + "piid": 2, + "friendlyName": "Brush Cleaner - Brush Life Level", + "channel": "brush_life_level2", + "type": "Number:Dimensionless", + "unit": "percentage", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [], + "category": "line" + }, + { + "property": "mop", + "siid": 8, + "piid": 1, + "friendlyName": "Custom - Mop", + "channel": "mop", + "type": "Switch", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "work-station-freq", + "siid": 8, + "piid": 2, + "friendlyName": "Custom - Work Station Freq", + "channel": "work_station_freq", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 3, + "step": 1, + "pattern": "%.0f" + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ] + }, + { + "property": "timing", + "siid": 8, + "piid": 6, + "friendlyName": "Custom - Timing", + "channel": "timing", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "clean-area", + "siid": 8, + "piid": 7, + "friendlyName": "Custom - Clean Area", + "channel": "clean_area", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": -1, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "uid", + "siid": 8, + "piid": 8, + "friendlyName": "Custom - Uid", + "channel": "uid", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "auto-boost", + "siid": 8, + "piid": 9, + "friendlyName": "Custom - Auto Boost", + "channel": "auto_boost", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "forbid-mode", + "siid": 8, + "piid": 10, + "friendlyName": "Custom - Forbid Mode", + "channel": "forbid_mode", + "type": "String", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "water-level", + "siid": 8, + "piid": 11, + "friendlyName": "Custom - Water Level", + "channel": "water_level", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "1", + "label": "First" + }, + { + "value": "2", + "label": "Second" + }, + { + "value": "3", + "label": "Three" + }, + { + "value": "4", + "label": "Fourth" + }, + { + "value": "0", + "label": "Mop" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "category": "water", + "readmeComment": "Value mapping `[\"1\"\u003d\"First\",\"2\"\u003d\"Second\",\"3\"\u003d\"Three\",\"4\"\u003d\"Fourth\",\"0\"\u003d\"Mop\"]`" + }, + { + "property": "total-clean-time", + "siid": 8, + "piid": 13, + "friendlyName": "Custom - Total Clean Time", + "channel": "total_clean_time", + "type": "Number:Time", + "unit": "seconds", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "total-clean-areas", + "siid": 8, + "piid": 14, + "friendlyName": "Custom - Total Clean Areas", + "channel": "total_clean_areas", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "clean-counts", + "siid": 8, + "piid": 18, + "friendlyName": "Custom - Clean Counts", + "channel": "clean_counts", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "clean-time", + "siid": 8, + "piid": 19, + "friendlyName": "Custom - Clean Time", + "channel": "clean_time", + "type": "Number:Time", + "unit": "seconds", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f %unit%", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "double-clean", + "siid": 8, + "piid": 20, + "friendlyName": "Custom - Double Clean", + "channel": "double_clean", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "edge-sweep", + "siid": 8, + "piid": 21, + "friendlyName": "Custom - Edge Sweep", + "channel": "edge_sweep", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "led-switch", + "siid": 8, + "piid": 22, + "friendlyName": "Custom - Led Switch", + "channel": "led_switch", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "lidar-collision", + "siid": 8, + "piid": 23, + "friendlyName": "Custom - Lidar Collision", + "channel": "lidar_collision", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "station-key", + "siid": 8, + "piid": 24, + "friendlyName": "Custom - Station Key", + "channel": "station_key", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "station-led", + "siid": 8, + "piid": 25, + "friendlyName": "Custom - Station Led", + "channel": "station_led", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "current-audio", + "siid": 8, + "piid": 26, + "friendlyName": "Custom - Current Audio", + "channel": "current_audio", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "progress", + "siid": 8, + "piid": 28, + "friendlyName": "Custom - Progress", + "channel": "progress", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "station-type", + "siid": 8, + "piid": 29, + "friendlyName": "Custom - Station Type", + "channel": "station_type", + "type": "Number", + "stateDescription": { + "minimum": 0, + "maximum": 2147483647, + "step": 1, + "pattern": "%.0f", + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "voice-conf", + "siid": 8, + "piid": 30, + "friendlyName": "Custom - Voice Conf", + "channel": "voice_conf", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "actions": [] + }, + { + "property": "clean-path", + "siid": 13, + "piid": 2, + "friendlyName": "Map - Clean Path", + "channel": "clean_path", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "restricted-zone", + "siid": 13, + "piid": 3, + "friendlyName": "Map - Restricted Zone", + "channel": "restricted_zone", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "auto-area", + "siid": 13, + "piid": 4, + "friendlyName": "Map - Auto Area", + "channel": "auto_area", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "map-memory", + "siid": 13, + "piid": 5, + "friendlyName": "Map - Map Memory", + "channel": "map_memory", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "map-name", + "siid": 13, + "piid": 6, + "friendlyName": "Map - Map Name", + "channel": "map_name", + "type": "String", + "refresh": false, + "actions": [ + { + "command": "set_properties", + "parameterType": "STRING" + } + ] + }, + { + "property": "use-auto-area", + "siid": 13, + "piid": 7, + "friendlyName": "Map - Use Auto Area", + "channel": "use_auto_area", + "type": "Switch", + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "ONOFFBOOL" + } + ] + }, + { + "property": "path-type", + "siid": 13, + "piid": 8, + "friendlyName": "Map - Path Type", + "channel": "path_type", + "type": "Number", + "stateDescription": { + "options": [ + { + "value": "0", + "label": "Normal" + }, + { + "value": "1", + "label": "Y-Mopping" + }, + { + "value": "2", + "label": "Repeat-Mopping" + } + ] + }, + "refresh": true, + "actions": [ + { + "command": "set_properties", + "parameterType": "NUMBER" + } + ], + "readmeComment": "Value mapping `[\"0\"\u003d\"Normal\",\"1\"\u003d\"Y-Mopping\",\"2\"\u003d\"Repeat-Mopping\"]`" + }, + { + "property": "sweep-mode", + "siid": 14, + "piid": 1, + "friendlyName": "Sweep - Sweep Mode", + "channel": "sweep_mode", + "type": "Number", + "stateDescription": { + "readOnly": true, + "options": [ + { + "value": "1", + "label": "Total" + }, + { + "value": "2", + "label": "Area" + }, + { + "value": "3", + "label": "Curpoint" + }, + { + "value": "4", + "label": "Point" + }, + { + "value": "7", + "label": "Smart" + }, + { + "value": "8", + "label": "AmartArea" + }, + { + "value": "9", + "label": "DepthTotal" + }, + { + "value": "10", + "label": "AlongWall" + }, + { + "value": "0", + "label": "Idle" + } + ] + }, + "refresh": true, + "actions": [], + "readmeComment": "Value mapping `[\"1\"\u003d\"Total\",\"2\"\u003d\"Area\",\"3\"\u003d\"Curpoint\",\"4\"\u003d\"Point\",\"7\"\u003d\"Smart\",\"8\"\u003d\"AmartArea\",\"9\"\u003d\"DepthTotal\",\"10\"\u003d\"AlongWall\",\"0\"\u003d\"Idle\"]`" + } + ], + "experimental": false + } +} From fa6ca6d0bbd29a46d615510d66142256a171f5b1 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 12 Dec 2021 22:21:20 +0100 Subject: [PATCH 227/361] [miio] add BT Devices channel to chuangmi plug (#11715) * [miio] add BT Devices channel to chuangmi plug * Shows the bluetooth devices connected to the plug (plug as BT gateway) * Add refresh interval functionality to reduce load on device * Change public to private for the private functions in conversions. * Add test for new conversion * Update miio.properties Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 2 + .../miio/internal/MiIoSendCommand.java | 2 +- .../miio/internal/basic/Conversions.java | 44 ++++++++++---- .../miio/internal/basic/MiIoBasicChannel.java | 57 +++++++++++++++++++ .../internal/handler/MiIoBasicHandler.java | 38 ++++++++++--- .../transport/MiIoAsyncCommunication.java | 5 +- .../resources/OH-INF/i18n/basic.properties | 1 + .../database/chuangmi.plug.212a01-miot.json | 22 +++++++ .../miio/internal/ConversionsTest.java | 48 ++++++++++++++-- 9 files changed, 191 insertions(+), 28 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index a0adc3d9ee225..7e4cd02b385a3 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -701,6 +701,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | task-switch | Switch | Imilab Timer - Task Switch | | | countdown-info | Switch | Imilab Timer - Countdown Info | | | bt-gw | String | BT Gateway | Value mapping `["disable"="Disable","enable"="Enable"]` | +| bt-gw-devices | String | Connected BT Gateway Devices | Note, refreshes every 2nd refresh. Channel requires cloud connectivity to function. Sample widget to visualise the (json) output available from the widget market | ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) Channels @@ -5720,6 +5721,7 @@ Number:Time countdown "Imilab Timer - Countdown" (G_plug) {channel="miio:basic:p Switch task_switch "Imilab Timer - Task Switch" (G_plug) {channel="miio:basic:plug:task-switch"} Switch countdown_info "Imilab Timer - Countdown Info" (G_plug) {channel="miio:basic:plug:countdown-info"} String bt_gw "BT Gateway" (G_plug) {channel="miio:basic:plug:bt-gw"} +String bt_gw_devices "Connected BT Gateway Devices" (G_plug) {channel="miio:basic:plug:bt-gw-devices"} ``` ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) item file lines diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoSendCommand.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoSendCommand.java index b26bd251d11fe..d552c8fc1e5bf 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoSendCommand.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoSendCommand.java @@ -74,7 +74,7 @@ public String getMethod() { } public JsonElement getParams() { - return commandJson.has("params") ? commandJson.get("params").getAsJsonArray() : new JsonArray(); + return commandJson.has("params") ? commandJson.get("params") : new JsonArray(); } public JsonObject getResponse() { diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java index e20487d09a0b8..ab17fdfdfe88c 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java @@ -44,7 +44,7 @@ public class Conversions { * @param RGB + brightness value (note brightness in the first byte) * @return HSV */ - public static JsonElement bRGBtoHSV(JsonElement bRGB) throws ClassCastException { + private static JsonElement bRGBtoHSV(JsonElement bRGB) throws ClassCastException { if (bRGB.isJsonPrimitive() && bRGB.getAsJsonPrimitive().isNumber()) { Color rgb = new Color(bRGB.getAsInt()); HSBType hsb = HSBType.fromRGB(rgb.getRed(), rgb.getGreen(), rgb.getBlue()); @@ -62,7 +62,7 @@ public static JsonElement bRGBtoHSV(JsonElement bRGB) throws ClassCastException * @param map with device variables containing the brightness info * @return HSV */ - public static JsonElement addBrightToHSV(JsonElement rgbValue, @Nullable Map deviceVariables) + private static JsonElement addBrightToHSV(JsonElement rgbValue, @Nullable Map deviceVariables) throws ClassCastException, IllegalStateException { int bright = 100; if (deviceVariables != null) { @@ -79,12 +79,12 @@ public static JsonElement addBrightToHSV(JsonElement rgbValue, @Nullable Map deviceVariables) { + String did = (String) deviceVariables.get("deviceId"); + if (did != null) { + return getJsonElement(did, responseValue); + } + LOGGER.debug("deviceId not Found, no conversion"); + return responseValue; + } + + /** + * Returns the element from the Json response. If not found, returns the input + * + * @param element to be found + * @param responseValue + * @return + */ + private static JsonElement getJsonElement(String element, JsonElement responseValue) { try { if (responseValue.isJsonPrimitive() || responseValue.isJsonObject()) { JsonElement jsonElement = responseValue.isJsonObject() ? responseValue @@ -143,8 +166,7 @@ public static JsonElement getJsonElement(String element, JsonElement responseVal return responseValue; } - public static JsonElement execute(String transformation, JsonElement value, - @Nullable Map deviceVariables) { + public static JsonElement execute(String transformation, JsonElement value, Map deviceVariables) { try { if (transformation.toUpperCase().startsWith("GETJSONELEMENT")) { if (transformation.length() > 15) { @@ -168,6 +190,8 @@ public static JsonElement execute(String transformation, JsonElement value, return addBrightToHSV(value, deviceVariables); case "BRGBTOHSV": return bRGBtoHSV(value); + case "GETDIDELEMENT": + return getDidElement(value, deviceVariables); default: LOGGER.debug("Transformation {} not found. Returning '{}'", transformation, value.toString()); return value; diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java index 33dc575743288..6190f075da6b1 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java @@ -22,6 +22,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import com.google.gson.JsonElement; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; @@ -66,12 +67,21 @@ public class MiIoBasicChannel { @SerializedName("refresh") @Expose private @Nullable Boolean refresh; + @SerializedName("refreshInterval") + @Expose + private @Nullable Integer refreshInterval; @SerializedName("customRefreshCommand") @Expose private @Nullable String channelCustomRefreshCommand; + @SerializedName("customRefreshParameters") + @Expose + private @Nullable JsonElement customRefreshParameters; @SerializedName("transformation") @Expose private @Nullable String transformation; + @SerializedName("transformations") + @Expose + private @Nullable List transformations; @SerializedName("ChannelGroup") @Expose private @Nullable String channelGroup; @@ -202,6 +212,23 @@ public void setRefresh(@Nullable Boolean refresh) { this.refresh = refresh; } + public Integer getRefreshInterval() { + Integer refreshInterval = this.refreshInterval; + if (refreshInterval != null) { + return refreshInterval; + } + return 1; + } + + public void setRefresh(@Nullable final Integer interval) { + final Integer refreshInterval = interval; + if (refreshInterval != null && refreshInterval.intValue() != 1) { + this.refreshInterval = refreshInterval; + } else { + this.refreshInterval = null; + } + } + public String getChannelCustomRefreshCommand() { final @Nullable String channelCustomRefreshCommand = this.channelCustomRefreshCommand; return channelCustomRefreshCommand != null ? channelCustomRefreshCommand : ""; @@ -211,6 +238,14 @@ public void setChannelCustomRefreshCommand(@Nullable String channelCustomRefresh this.channelCustomRefreshCommand = channelCustomRefreshCommand; } + public @Nullable final JsonElement getCustomRefreshParameters() { + return customRefreshParameters; + } + + public final void setCustomRefreshParameters(@Nullable JsonElement customRefreshParameters) { + this.customRefreshParameters = customRefreshParameters; + } + public String getChannelGroup() { final @Nullable String channelGroup = this.channelGroup; return channelGroup != null ? channelGroup : ""; @@ -237,6 +272,28 @@ public void setTransformation(@Nullable String transformation) { this.transformation = transformation; } + public final List getTransformations() { + List transformations = this.transformations; + if (transformations == null) { + transformations = new ArrayList<>(); + } + String transformation = this.transformation; + if (transformation != null) { + List allTransformation = new ArrayList<>(List.of(transformation)); + allTransformation.addAll(transformations); + return allTransformation; + } + return transformations; + } + + public final void setTransformations(@Nullable List transformations) { + if (transformations != null && !transformations.isEmpty()) { + this.transformations = transformations; + } else { + this.transformations = null; + } + } + public @Nullable String getCategory() { return category; } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java index d192889aad8a8..e51083b71ea6b 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java @@ -105,6 +105,7 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { private Map actions = new HashMap<>(); private ChannelTypeRegistry channelTypeRegistry; private BasicChannelTypeProvider basicChannelTypeProvider; + private Map customRefreshInterval = new HashMap<>(); public MiIoBasicHandler(Thing thing, MiIoDatabaseWatchService miIoDatabaseWatchService, CloudConnector cloudConnector, ChannelTypeRegistry channelTypeRegistry, @@ -352,16 +353,39 @@ protected synchronized void updateData() { } } + private boolean customRefreshIntervalCheck(MiIoBasicChannel miChannel) { + if (miChannel.getRefreshInterval() > 1) { + int iteration = customRefreshInterval.getOrDefault(miChannel.getChannel(), 0); + if (iteration < 1) { + customRefreshInterval.put(miChannel.getChannel(), miChannel.getRefreshInterval() - 1); + } else { + logger.debug("Skip refresh of channel {} for {}. Next refresh in {} cycles.", miChannel.getChannel(), + getThing().getUID(), iteration); + customRefreshInterval.put(miChannel.getChannel(), iteration - 1); + return true; + } + } + return false; + } + + private boolean linkedChannelCheck(MiIoBasicChannel miChannel) { + if (!isLinked(miChannel.getChannel())) { + logger.debug("Skip refresh of channel {} for {} as it is not linked", miChannel.getChannel(), + getThing().getUID()); + return false; + } + return true; + } + private void refreshCustomProperties(MiIoBasicDevice midevice) { for (MiIoBasicChannel miChannel : refreshListCustomCommands.values()) { - if (!isLinked(miChannel.getChannel())) { - logger.debug("Skip refresh of channel {} for {} as it is not linked", miChannel.getChannel(), - getThing().getUID()); + if (customRefreshIntervalCheck(miChannel) || !linkedChannelCheck(miChannel)) { continue; } - String cmd = miChannel.getChannelCustomRefreshCommand(); + final JsonElement para = miChannel.getCustomRefreshParameters(); + String cmd = miChannel.getChannelCustomRefreshCommand() + (para != null ? para.toString() : ""); if (!cmd.startsWith("/")) { - cmds.put(sendCommand(miChannel.getChannelCustomRefreshCommand()), miChannel.getChannel()); + cmds.put(sendCommand(cmd), miChannel.getChannel()); } else { if (cloudServer.isBlank()) { logger.debug("Cloudserver empty. Skipping refresh for {} channel '{}'", getThing().getUID(), @@ -378,9 +402,7 @@ private boolean refreshProperties(MiIoBasicDevice device) { int maxProperties = device.getDevice().getMaxProperties(); JsonArray getPropString = new JsonArray(); for (MiIoBasicChannel miChannel : refreshList) { - if (!isLinked(miChannel.getChannel())) { - logger.debug("Skip refresh of channel {} for {} as it is not linked", miChannel.getChannel(), - getThing().getUID()); + if (customRefreshIntervalCheck(miChannel) || !linkedChannelCheck(miChannel)) { continue; } JsonElement property; diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java index 1bb9018b4a92c..caa85b37b8bfb 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java @@ -182,10 +182,7 @@ MiIoSendCommand sendMiIoSendCommand(MiIoSendCommand miIoSendCommand) { miIoSendCommand.getCloudServer()); updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE); } else { - String data = miIoSendCommand.getParams().isJsonArray() - && miIoSendCommand.getParams().getAsJsonArray().size() > 0 - ? miIoSendCommand.getParams().getAsJsonArray().get(0).toString() - : ""; + String data = miIoSendCommand.getParams().toString(); logger.debug("Custom cloud request send to url '{}' with data '{}'", miIoSendCommand.getMethod(), data); decryptedResponse = cloudConnector.sendCloudCommand(miIoSendCommand.getMethod(), diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties index 65659da0c429a..ec7c8d67214a0 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties @@ -414,6 +414,7 @@ ch.cgllc.airmonitor.s1.pm25 = PM2.5 ch.cgllc.airmonitor.s1.temperature = Temperature ch.cgllc.airmonitor.s1.tvoc = tVOC ch.chuangmi.plug.212a01-miot.bt-gw = BT Gateway +ch.chuangmi.plug.212a01-miot.bt-gw-devices = Connected BT Gateway Devices ch.chuangmi.plug.212a01-miot.countdown = Imilab Timer - Countdown ch.chuangmi.plug.212a01-miot.countdown-info = Imilab Timer - Countdown Info ch.chuangmi.plug.212a01-miot.electric-current = Power Consumption - Electric Current diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json index 9ee47e5e69f3e..66f248fa283d8 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json @@ -322,7 +322,29 @@ } } ], + "category": "bluetooth", "readmeComment": "Value mapping `[\"disable\"\u003d\"Disable\",\"enable\"\u003d\"Enable\"]`" + }, + { + "property": "", + "friendlyName": "Connected BT Gateway Devices", + "channel": "bt-gw-devices", + "type": "String", + "stateDescription": { + "readOnly": true + }, + "refresh": true, + "refreshInterval": 2, + "customRefreshCommand": "/device/get_bledevice_by_gateway", + "customRefreshParameters": { + "dids": [ + "$deviceId$" + ] + }, + "transformation": "getDiDElement", + "actions": [], + "category": "bluetooth", + "readmeComment": "Note, refreshes every 2nd refresh. Channel requires cloud connectivity to function. Sample widget to visualise the (json) output available from the widget market" } ], "experimental": false diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java index 2ee46a065f5d4..aa83988d63cf3 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -15,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.*; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -35,6 +36,48 @@ @NonNullByDefault public class ConversionsTest { + @Test + public void getDidElementTest() { + Map deviceVariables = new HashMap<>(); + String transformation = "getDidElement"; + JsonElement validInput = new JsonPrimitive( + "{\"361185596\":\"{\\\"C812105B04000400\\\":\\\"-92\\\",\\\"blt.3.17q3si5345k00\\\":\\\"-54\\\",\\\"blt.4.10heul64og400\\\":\\\"-73\\\"}\"}"); + + // test no did in deviceVariables + JsonElement value = validInput; + JsonElement transformedResponse = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(transformedResponse); + assertEquals(value, transformedResponse); + + // test valid input & response + deviceVariables.put("deviceId", "361185596"); + value = validInput; + transformedResponse = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(transformedResponse); + assertEquals(new JsonPrimitive( + "{\"C812105B04000400\":\"-92\",\"blt.3.17q3si5345k00\":\"-54\",\"blt.4.10heul64og400\":\"-73\"}"), + transformedResponse); + + // test non json + value = new JsonPrimitive("some non json value"); + transformedResponse = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(transformedResponse); + assertEquals(value, transformedResponse); + + // test different did in deviceVariables + deviceVariables.put("deviceId", "ABC185596"); + value = validInput; + transformedResponse = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(transformedResponse); + assertEquals(value, transformedResponse); + + // test empty input + value = new JsonPrimitive(""); + transformedResponse = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(transformedResponse); + assertEquals(value, transformedResponse); + } + @Test public void getJsonElementTest() { @@ -55,11 +98,6 @@ public void getJsonElementTest() { transformation = "getJsonElement-test"; - // test without deviceVariables - resp = Conversions.execute(transformation, value, null); - assertNotNull(resp); - assertEquals(new JsonPrimitive("testresponse"), resp); - // test non json value = new JsonPrimitive("some non json value"); resp = Conversions.execute(transformation, value, deviceVariables); From e91a70c97b1ea4a24ba5f804b9de7ab9377adbca Mon Sep 17 00:00:00 2001 From: olivierkeke Date: Sun, 12 Dec 2021 22:58:36 +0100 Subject: [PATCH 228/361] [teleinfo] Add support for Standard tic mode (#11375) * Add a ticMode parameter to serial controller Signed-off-by: Olivier Marceau * Improve checksum verification Signed-off-by: Olivier Marceau * Add parameter to deactivate checksum verification Signed-off-by: Olivier Marceau * Add standard field labels Signed-off-by: Olivier Marceau * Add things and channels for standard tic mode Signed-off-by: Olivier Marceau * Add standard tic mode timestamp Signed-off-by: Olivier Marceau * Fix typo Signed-off-by: Olivier Marceau * Add some required null annotation Signed-off-by: Olivier Marceau * Add parser for relais states Signed-off-by: Olivier Marceau * Add relais channels and refactor standard mode channels Signed-off-by: Olivier Marceau * Add @NonNullByDefault on enum Signed-off-by: Olivier Marceau * Update documentation Signed-off-by: Olivier Marceau * Fix formula in documentation Signed-off-by: Olivier Marceau * Fix code issues Signed-off-by: Olivier Marceau * Move channel type description in same file than channel group type description Signed-off-by: Olivier Marceau * Add pattern specification to dateTime channel type Signed-off-by: Olivier Marceau * Add missing channelGroup id in channel UID Signed-off-by: Olivier Marceau * Add trace log Signed-off-by: Olivier Marceau * Fix group labels Signed-off-by: Olivier Marceau * Make labels uppercase Signed-off-by: Olivier Marceau * Make options lowercase Signed-off-by: Olivier Marceau * Simplify group label Signed-off-by: Olivier Marceau Signed-off-by: Michael Schmidt --- .../org.openhab.binding.teleinfo/README.md | 108 +++++- .../internal/TeleinfoBindingConstants.java | 114 +++++- .../internal/TeleinfoDiscoveryService.java | 17 +- .../teleinfo/internal/data/Evolution.java | 3 + .../binding/teleinfo/internal/data/Frame.java | 57 +++ .../teleinfo/internal/data/FrameType.java | 13 +- .../binding/teleinfo/internal/data/Phase.java | 3 + .../teleinfo/internal/data/Pricing.java | 3 + .../TeleinfoElectricityMeterHandler.java | 71 +++- .../handler/TeleinfoThingHandlerFactory.java | 4 +- .../reader/io/TeleinfoInputStream.java | 72 +++- .../reader/io/serialport/FrameUtil.java | 26 +- .../internal/reader/io/serialport/Label.java | 117 +++++- .../reader/io/serialport/ValueType.java | 3 + .../serial/TeleinfoReceiveThread.java | 8 +- ...TeleinfoSerialControllerConfiguration.java | 2 + .../TeleinfoSerialControllerHandler.java | 6 +- .../internal/serial/TeleinfoTicMode.java | 42 ++ .../OH-INF/config/config-description.xml | 2 +- .../OH-INF/thing/common-lsm-channel-group.xml | 362 ++++++++++++++++++ .../thing/common-lsm-prod-channel-group.xml | 133 +++++++ .../common-lsm-three-phase-channel-group.xml | 179 +++++++++ .../OH-INF/thing/lsmmElectricityMeter.xml | 23 ++ .../OH-INF/thing/lsmmProdElectricityMeter.xml | 24 ++ .../OH-INF/thing/lsmtElectricityMeter.xml | 24 ++ .../OH-INF/thing/lsmtProdElectricityMeter.xml | 25 ++ .../OH-INF/thing/serialController.xml | 16 + .../reader/io/TeleinfoInputStreamTest.java | 78 +++- .../reader/io/serialport/FrameUtilTest.java | 75 ++++ .../cbemm-evo-icc-tempo-option-1.raw | Bin 333 -> 331 bytes .../test/resources/cbetm-base-option-1.raw | 2 +- .../src/test/resources/cbetm-ejp-option-1.raw | 2 +- ...ky-tic-mode-standard-single-phase-prod.raw | 70 ++++ ...nky-tic-mode-standard-three-phase-prod.raw | 171 +++++++++ 34 files changed, 1765 insertions(+), 90 deletions(-) mode change 100644 => 100755 bundles/org.openhab.binding.teleinfo/README.md create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml create mode 100644 bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java create mode 100644 bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw create mode 100644 bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw diff --git a/bundles/org.openhab.binding.teleinfo/README.md b/bundles/org.openhab.binding.teleinfo/README.md old mode 100644 new mode 100755 index 4a2002a3bf9b3..7ebd4b22d555c --- a/bundles/org.openhab.binding.teleinfo/README.md +++ b/bundles/org.openhab.binding.teleinfo/README.md @@ -12,6 +12,10 @@ These values can be used to ## Supported Things +### Historical TIC mode + +Historical TIC mode is the only mode of all telemeters before Linky models and the default mode for Linky telemeters. + The Teleinfo binding provides support for both single-phase and three-phase connection, ICC evolution and the following pricing modes: - HCHP mode @@ -34,6 +38,19 @@ The Teleinfo binding provides support for both single-phase and three-phase conn | cbetm_hc_electricitymeter | three-phase | HCHP | | | cbetm_tempo_electricitymeter | three-phase | Tempo | | +### Standard TIC mode + +Linky telemeters add a new `Standard` mode with more detailed information but still provide information on the legacy format under the `Historical` denomination. + +Standard mode doesn't depend on the pricing options, but it adds some useful information for electricity producers. + +| Thing type | Connection | Producer mode | +|--------------------------------------------|--------------|--------------| +| lsmm_electricitymeter | single-phase | | +| lsmm_prod_electricitymeter | single-phase | [x] | +| lstm_electricitymeter | three-phase | | +| lstm_prod_electricitymeter | three-phase | [x] | + ## Discovery Before the binding can be used, a serial controller must be added. This needs to be done manually. Select __Teleinfo Serial Controller__ and enter the serial port. @@ -49,30 +66,33 @@ Once the serial controller added, electricity meters will automatically appear a |----------------------|--------------|---------------------------------------|---------------------------------| | `serialcontroller` | `serialport` | Path to the serial controller | /dev/ttyXXXX, rfc2217://ip:port | | `*_electricitymeter` | `adco` | Electricity meter identifier | 12 digits number | +| | `ticMode` | TIC mode | `STANDARD`, `HISTORICAL` (default) | ## Channels +### Historical TIC mode + Channel availability depends on the electricity connection (single or three-phase) and on the pricing mode (Base, HCHP, EJP or Tempo). -| Channel | Type | Description | Phase | Mode | +| Channel | Type | Description | Connection | Mode | |----------|---------------------------|----------------------------------------------------------|--------|-------| | isousc | `Number:ElectricCurrent` | Subscribed electric current | All | All | | ptec | `String` | Current pricing period | All | All | -| imax | `Number:ElectricCurrent` | Maximum consumed electric current | Single | All | -| imax1 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 1 | Three | All | -| imax2 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 2 | Three | All | -| imax3 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 3 | Three | All | -| adps | `Number:ElectricCurrent` | Excess electric current warning | Single | All | -| adir1 | `Number:ElectricCurrent` | Excess electric current on phase 1 warning | Three | All | -| adir2 | `Number:ElectricCurrent` | Excess electric current on phase 2 warning | Three | All | -| adir3 | `Number:ElectricCurrent` | Excess electric current on phase 3 warning | Three | All | -| iinst | `Number:ElectricCurrent` | Instantaneous electric current | Single | All | -| iinst1 | `Number:ElectricCurrent` | Instantaneous electric current on phase 1 | Three | All | -| iinst2 | `Number:ElectricCurrent` | Instantaneous electric current on phase 2 | Three | All | -| iinst3 | `Number:ElectricCurrent` | Instantaneous electric current on phase 3 | Three | All | -| ppot | `String` | Electrical potential presence | Three | All | -| pmax | `Number:Energy` | Maximum consumed electric power on all phases | Three | All | -| papp | `Number:Power` | Instantaneous apparent power | Three, single (ICC evolution only) | All | +| imax | `Number:ElectricCurrent` | Maximum consumed electric current | Single-phase | All | +| imax1 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 1 | Three-phase | All | +| imax2 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 2 | Three-phase | All | +| imax3 | `Number:ElectricCurrent` | Maximum consumed electric current on phase 3 | Three-phase | All | +| adps | `Number:ElectricCurrent` | Excess electric current warning | Single-phase | All | +| adir1 | `Number:ElectricCurrent` | Excess electric current on phase 1 warning | Three-phase | All | +| adir2 | `Number:ElectricCurrent` | Excess electric current on phase 2 warning | Three-phase | All | +| adir3 | `Number:ElectricCurrent` | Excess electric current on phase 3 warning | Three-phase | All | +| iinst | `Number:ElectricCurrent` | Instantaneous electric current | Single-phase | All | +| iinst1 | `Number:ElectricCurrent` | Instantaneous electric current on phase 1 | Three-phase | All | +| iinst2 | `Number:ElectricCurrent` | Instantaneous electric current on phase 2 | Three-phase | All | +| iinst3 | `Number:ElectricCurrent` | Instantaneous electric current on phase 3 | Three-phase | All | +| ppot | `String` | Electrical potential presence | Three-phase | All | +| pmax | `Number:Energy` | Maximum consumed electric power on all phases | Three-phase | All | +| papp | `Number:Power` | Instantaneous apparent power | Three-phase, single-phase (ICC evolution only) | All | | hhphc | `String` | Pricing schedule group | All | HCHP | | hchc | `Number:Energy` | Total consumed energy at low rate pricing | All | HCHP | | hchp | `Number:Energy` | Total consumed energy at high rate pricing | All | HCHP | @@ -88,8 +108,64 @@ Channel availability depends on the electricity connection (single or three-phas | pejp | `Number:Duration` | Prior notice to EJP start | All | EJP | | demain | `String` | Following day color | All | Tempo | +### Standard TIC mode + +| Channel | Type | Description | Connection | Mode | +|----------|---------------------------|----------------------------------------------------------|--------|-------| +| ngtf | `String` | Provider schedule name | All | All | +| ltarf | `String` | Current pricing label | All | All | +| east | `Number:Energy` | Total active energy withdrawn | All | All | +| easf*XX* | `Number:Energy` | Active energy withdrawn from provider on index | All | All | +| easd*XX* | `Number:Energy` | Active energy withdrawn from distributor on index | All | All | +| irms*X* | `Number:ElectricCurrent` | RMS Current on phase *X* | All for , Three-phase for | All | +| urms*X* | `Number:Potential` | RMS Voltage on phase *X* | All for , Three-phase for | All | +| pref | `Number:Power` | Reference apparent power | All | All | +| pcoup | `Number:Power` | Apparent power rupture capacity | All | All | +| sinsts | `Number:Power` | Instantaneous withdrawn apparent power | Single-phase | All | +| smaxsn | `Number:Power` | Maximum withdrawn apparent power of the day | Single-phase | All | +| smaxsnMinus1 | `Number:Power` | Maximum withdrawn apparent power of the previous day | Single-phase | All | +| ccasn | `Number:Power` | Active charge point N | All | All | +| ccasnMinus1 | `Number:Power` | Active charge point N-1 | All | All | +| umoy*X* | `Number:Potential` | Mean Voltage on phase *X* | All for , Three-phase for | All | +| dpm*X* | `String` | Start of mobile peak period | All | All | +| fpm*X* | `String` | End of mobile peak period | All | All | +| msg1 | `String` | Short message | All | All | +| msg2 | `String` | Very short message | All | All | +| ntarf | `String` | Index of current pricing | All | All | +| njourf | `String` | Number of current provider schedule | All | All | +| njourfPlus1 | `String` | Number of next day provider schedule | All | All | +| pjourfPlus1 | `String` | Profile of next day provider schedule | All | All | +| ppointe | `String` | Profile of next rush day | All | All | +| date | `DateTime` | Date and Time | All | All | +| smaxsnDate | `DateTime` | Timestamp of SMAXSN value | All | All | +| smaxsnMinus1Date | `DateTime` | Timestamp of SMAXSN-1 value | All | All | +| ccasnDate | `DateTime` | Timestamp of CCASN value | All | All | +| ccasnMinus1Date | `DateTime` | Timestamp of CCASN-1 value | All | All | +| umoy*X*Date | `DateTime` | Timestamp of UMOY*X* value | All for , Three-phase for | All | +| dpm*X*Date | `DateTime` | Date of DPM*X* | All | All | +| fpm*X*Date | `DateTime` | Date of FPM*X* | All | All | +| relais*X* | `Switch` | relais status ( ) | All | All | +| sinsts*X* | `Number:Power` | Instantaneous withdrawn apparent power on phase *X* | Three-phase | All | +| smaxsn*X* | `Number:Power` | Maximum withdrawn apparent power of the day on phase *X* | Three-phase | All | +| smaxsn*X*Minus1 | `Number:Power` | Maximum withdrawn apparent power on the previous day on phase *X* | Three-phase | All | +| smaxs*X*nDate | `DateTime` | Timestamp of SMAXSN*X* value | Three-phase | All | +| smaxsn*X*Minus1Date | `DateTime` | Timestamp of SMAXSN*X*-1 value | Three-phase | All | +| eait | `Number:Energy` | Total active energy withdrawn | All | All | +| erq*X* | `Number:Energy` | Active energy withdrawn from provider on index | All | All | +| sinsti | `Number:Energy` | Active energy withdrawn from distributor on index | All | All | +| smaxin | `Number:Power` | Maximum injected apparent power of the day | All for , Three-phase for | All | +| smaxinMinus1 | `Number:Power` | Maximum injected apparent power of the previous day | All for , Three-phase for | All | +| ccain | `Number:Power` | Injected active charge point N | All | Producer | +| ccainMinus1 | `Number:Power` | Injected active charge point N-1 | All | Producer | +| smaxinDate | `DateTime` | Timestamp of SMAXIN value | All | Producer | +| smaxinMinus1Date | `DateTime` | Timestamp of SMAXIN-1 value | All | Producer | +| ccainDate | `DateTime` | Timestamp of CCAIN value | All | Producer | +| ccainMinus1Date | `DateTime` | Timestamp of CCAIN-1 value | All | Producer | + ## Full Example +### Historical TIC mode + The following `things` file declare a serial USB controller on `/dev/ttyUSB0` for a Single-phase Electricity meter with HC/HP option - CBEMM Evolution ICC and adco `031528042289` : ``` diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java index 3b942d2c22c39..f2ab5e97e32d4 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoBindingConstants.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.teleinfo.internal; +import java.util.stream.IntStream; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; @@ -68,7 +70,6 @@ private TeleinfoBindingConstants() { public static final String CHANNEL_CBETM_IINST1 = "iinst1"; public static final String CHANNEL_CBETM_IINST2 = "iinst2"; public static final String CHANNEL_CBETM_IINST3 = "iinst3"; - public static final String CHANNEL_CBETM_FRAME_TYPE = "frameType"; public static final String CHANNEL_CBETM_LONG_IMAX1 = "imax1"; public static final String CHANNEL_CBETM_LONG_IMAX2 = "imax2"; public static final String CHANNEL_CBETM_LONG_IMAX3 = "imax3"; @@ -77,6 +78,105 @@ private TeleinfoBindingConstants() { public static final String CHANNEL_CBETM_SHORT_ADIR1 = "adir1"; public static final String CHANNEL_CBETM_SHORT_ADIR2 = "adir2"; public static final String CHANNEL_CBETM_SHORT_ADIR3 = "adir3"; + // List of Linky standard mode channel ids + public static final String CHANNEL_LSM_NGTF = "commonLSMGroup#ngtf"; + public static final String CHANNEL_LSM_LTARF = "commonLSMGroup#ltarf"; + public static final String CHANNEL_LSM_EAST = "commonLSMGroup#east"; + public static final String CHANNEL_LSM_EASF01 = "commonLSMGroup#easf01"; + public static final String CHANNEL_LSM_EASF02 = "commonLSMGroup#easf02"; + public static final String CHANNEL_LSM_EASF03 = "commonLSMGroup#easf03"; + public static final String CHANNEL_LSM_EASF04 = "commonLSMGroup#easf04"; + public static final String CHANNEL_LSM_EASF05 = "commonLSMGroup#easf05"; + public static final String CHANNEL_LSM_EASF06 = "commonLSMGroup#easf06"; + public static final String CHANNEL_LSM_EASF07 = "commonLSMGroup#easf07"; + public static final String CHANNEL_LSM_EASF08 = "commonLSMGroup#easf08"; + public static final String CHANNEL_LSM_EASF09 = "commonLSMGroup#easf09"; + public static final String CHANNEL_LSM_EASF10 = "commonLSMGroup#easf10"; + public static final String CHANNEL_LSM_EASD01 = "commonLSMGroup#easd01"; + public static final String CHANNEL_LSM_EASD02 = "commonLSMGroup#easd02"; + public static final String CHANNEL_LSM_EASD03 = "commonLSMGroup#easd03"; + public static final String CHANNEL_LSM_EASD04 = "commonLSMGroup#easd04"; + public static final String CHANNEL_LSM_IRMS1 = "commonLSMGroup#irms1"; + public static final String CHANNEL_LSM_URMS1 = "commonLSMGroup#urms1"; + public static final String CHANNEL_LSM_PREF = "commonLSMGroup#pref"; + public static final String CHANNEL_LSM_PCOUP = "commonLSMGroup#pcoup"; + public static final String CHANNEL_LSM_SINSTS = "commonLSMGroup#sinsts"; + public static final String CHANNEL_LSM_SMAXSN = "commonLSMGroup#smaxsn"; + public static final String CHANNEL_LSM_SMAXSN_MINUS_1 = "commonLSMGroup#smaxsnMinus1"; + public static final String CHANNEL_LSM_CCASN = "commonLSMGroup#ccasn"; + public static final String CHANNEL_LSM_CCASN_MINUS_1 = "commonLSMGroup#ccasnMinus1"; + public static final String CHANNEL_LSM_UMOY1 = "commonLSMGroup#umoy1"; + public static final String CHANNEL_LSM_STGE = "commonLSMGroup#stge"; + public static final String CHANNEL_LSM_DPM1 = "commonLSMGroup#dpm1"; + public static final String CHANNEL_LSM_FPM1 = "commonLSMGroup#fpm1"; + public static final String CHANNEL_LSM_DPM2 = "commonLSMGroup#dpm2"; + public static final String CHANNEL_LSM_FPM2 = "commonLSMGroup#fpm2"; + public static final String CHANNEL_LSM_DPM3 = "commonLSMGroup#dpm3"; + public static final String CHANNEL_LSM_FPM3 = "commonLSMGroup#fpm3"; + public static final String CHANNEL_LSM_MSG1 = "commonLSMGroup#msg1"; + public static final String CHANNEL_LSM_MSG2 = "commonLSMGroup#msg2"; + public static final String CHANNEL_LSM_PRM = "commonLSMGroup#prm"; + public static final String[] CHANNELS_LSM_RELAIS = IntStream.range(1, 9).mapToObj(i -> "commonLSMGroup#relais" + i) + .toArray(String[]::new); + public static final String CHANNEL_LSM_NTARF = "commonLSMGroup#ntarf"; + public static final String CHANNEL_LSM_NJOURF = "commonLSMGroup#njourf"; + public static final String CHANNEL_LSM_NJOURF_PLUS_1 = "commonLSMGroup#njourfPlus1"; + public static final String CHANNEL_LSM_PJOURF_PLUS_1 = "commonLSMGroup#pjourfPlus1"; + public static final String CHANNEL_LSM_PPOINTE = "commonLSMGroup#ppointe"; + + public static final String CHANNEL_LSM_IRMS2 = "threePhasedLSMGroup#irms2"; + public static final String CHANNEL_LSM_IRMS3 = "threePhasedLSMGroup#irms3"; + public static final String CHANNEL_LSM_URMS2 = "threePhasedLSMGroup#urms2"; + public static final String CHANNEL_LSM_URMS3 = "threePhasedLSMGroup#urms3"; + public static final String CHANNEL_LSM_SINSTS1 = "threePhasedLSMGroup#sinsts1"; + public static final String CHANNEL_LSM_SINSTS2 = "threePhasedLSMGroup#sinsts2"; + public static final String CHANNEL_LSM_SINSTS3 = "threePhasedLSMGroup#sinsts3"; + public static final String CHANNEL_LSM_SMAXSN1 = "threePhasedLSMGroup#smaxsn1"; + public static final String CHANNEL_LSM_SMAXSN2 = "threePhasedLSMGroup#smaxsn2"; + public static final String CHANNEL_LSM_SMAXSN3 = "threePhasedLSMGroup#smaxsn3"; + public static final String CHANNEL_LSM_SMAXSN1_MINUS_1 = "threePhasedLSMGroup#smaxsn1Minus1"; + public static final String CHANNEL_LSM_SMAXSN2_MINUS_1 = "threePhasedLSMGroup#smaxsn2Minus1"; + public static final String CHANNEL_LSM_SMAXSN3_MINUS_1 = "threePhasedLSMGroup#smaxsn3Minus1"; + public static final String CHANNEL_LSM_UMOY2 = "threePhasedLSMGroup#umoy2"; + public static final String CHANNEL_LSM_UMOY3 = "threePhasedLSMGroup#umoy3"; + + public static final String CHANNEL_LSM_EAIT = "producerLSMGroup#eait"; + public static final String CHANNEL_LSM_ERQ1 = "producerLSMGroup#erq1"; + public static final String CHANNEL_LSM_ERQ2 = "producerLSMGroup#erq2"; + public static final String CHANNEL_LSM_ERQ3 = "producerLSMGroup#erq3"; + public static final String CHANNEL_LSM_ERQ4 = "producerLSMGroup#erq4"; + public static final String CHANNEL_LSM_SINSTI = "producerLSMGroup#sinsti"; + public static final String CHANNEL_LSM_SMAXIN = "producerLSMGroup#smaxin"; + public static final String CHANNEL_LSM_SMAXIN_MINUS_1 = "producerLSMGroup#smaxinMinus1"; + public static final String CHANNEL_LSM_CCAIN = "producerLSMGroup#ccain"; + public static final String CHANNEL_LSM_CCAIN_MINUS_1 = "producerLSMGroup#ccainMinus1"; + + public static final String CHANNEL_LSM_DATE = "commonLSMGroup#date"; + public static final String CHANNEL_LSM_SMAXSN_DATE = "commonLSMGroup#smaxsnDate"; + public static final String CHANNEL_LSM_SMAXSN_MINUS_1_DATE = "commonLSMGroup#smaxsnMinus1Date"; + public static final String CHANNEL_LSM_CCASN_DATE = "commonLSMGroup#ccasnDate"; + public static final String CHANNEL_LSM_CCASN_MINUS_1_DATE = "commonLSMGroup#ccasnMinus1Date"; + public static final String CHANNEL_LSM_UMOY1_DATE = "commonLSMGroup#umoy1Date"; + public static final String CHANNEL_LSM_DPM1_DATE = "commonLSMGroup#dpm1Date"; + public static final String CHANNEL_LSM_FPM1_DATE = "commonLSMGroup#fpm1Date"; + public static final String CHANNEL_LSM_DPM2_DATE = "commonLSMGroup#dpm2Date"; + public static final String CHANNEL_LSM_FPM2_DATE = "commonLSMGroup#fpm2Date"; + public static final String CHANNEL_LSM_DPM3_DATE = "commonLSMGroup#dpm3Date"; + public static final String CHANNEL_LSM_FPM3_DATE = "commonLSMGroup#fpm3Date"; + + public static final String CHANNEL_LSM_SMAXIN_DATE = "producerLSMGroup#smaxinDate"; + public static final String CHANNEL_LSM_SMAXIN_MINUS_1_DATE = "producerLSMGroup#smaxinMinus1Date"; + public static final String CHANNEL_LSM_CCAIN_DATE = "producerLSMGroup#ccainDate"; + public static final String CHANNEL_LSM_CCAIN_MINUS_1_DATE = "producerLSMGroup#ccainMinus1Date"; + + public static final String CHANNEL_LSM_SMAXSN1_DATE = "threePhasedLSMGroup#smaxsn1Date"; + public static final String CHANNEL_LSM_SMAXSN2_DATE = "threePhasedLSMGroup#smaxsn2Date"; + public static final String CHANNEL_LSM_SMAXSN3_DATE = "threePhasedLSMGroup#smaxsn3Date"; + public static final String CHANNEL_LSM_SMAXSN1_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn1Minus1Date"; + public static final String CHANNEL_LSM_SMAXSN2_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn2Minus1Date"; + public static final String CHANNEL_LSM_SMAXSN3_MINUS_1_DATE = "threePhasedLSMGroup#smaxsn3Minus1Date"; + public static final String CHANNEL_LSM_UMOY2_DATE = "threePhasedLSMGroup#umoy2Date"; + public static final String CHANNEL_LSM_UMOY3_DATE = "threePhasedLSMGroup#umoy3Date"; public static final String NOT_A_CHANNEL = ""; @@ -118,6 +218,18 @@ private TeleinfoBindingConstants() { public static final ThingTypeUID THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID, "cbetm_tempo_electricitymeter"); + public static final ThingTypeUID THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID, + "lsmt_prod_electricitymeter"); + + public static final ThingTypeUID THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID, + "lsmm_prod_electricitymeter"); + + public static final ThingTypeUID THING_LSMT_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID, + "lsmt_electricitymeter"); + + public static final ThingTypeUID THING_LSMM_ELECTRICITY_METER_TYPE_UID = new ThingTypeUID(BINDING_ID, + "lsmm_electricitymeter"); + public static final String ERROR_OFFLINE_SERIAL_NOT_FOUND = "@text/teleinfo.thingstate.serial_notfound"; public static final String ERROR_OFFLINE_SERIAL_INUSE = "@text/teleinfo.thingstate.serial_inuse"; public static final String ERROR_OFFLINE_SERIAL_UNSUPPORTED = "@text/teleinfo.thingstate.serial_unsupported"; diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java index f3ff6c4bcac81..c6f59a4980e6f 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/TeleinfoDiscoveryService.java @@ -17,8 +17,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -47,13 +45,15 @@ public class TeleinfoDiscoveryService extends AbstractDiscoveryService implements TeleinfoControllerHandlerListener, ThingHandlerService, DiscoveryService { - private static final Set SUPPORTED_THING_TYPES = Stream.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID, + private static final Set SUPPORTED_THING_TYPES = Set.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID, - THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID).collect(Collectors.toSet()); + THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID, THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID, + THING_LSMT_ELECTRICITY_METER_TYPE_UID, THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID, + THING_LSMM_ELECTRICITY_METER_TYPE_UID); private static final int SCAN_DURATION_IN_S = 60; @@ -140,11 +140,12 @@ private void detectNewElectricityMeterFromReceivedFrame(final Frame frameSample) TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler; if (controllerHandlerRef != null) { logger.debug("New eletricity meter detection from frame {}", frameSample); - if (frameSample.get(Label.ADCO) == null) { - throw new IllegalStateException("Missing ADCO key"); + if (frameSample.get(Label.ADCO) == null && frameSample.get(Label.ADSC) == null) { + throw new IllegalStateException("Missing ADCO or ADSC key"); } - String adco = frameSample.get(Label.ADCO); + String adco = frameSample.get(Label.ADCO) != null ? frameSample.get(Label.ADCO) + : frameSample.get(Label.ADSC); if (adco != null) { ThingUID thingUID = new ThingUID(getThingTypeUID(frameSample), adco, controllerHandlerRef.getThing().getUID().getId()); @@ -152,7 +153,7 @@ private void detectNewElectricityMeterFromReceivedFrame(final Frame frameSample) final Map properties = getThingProperties(adco); final String representationProperty = THING_ELECTRICITY_METER_PROPERTY_ADCO; DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties) - .withLabel("Teleinfo ADCO " + adco).withThingType(getThingTypeUID(frameSample)) + .withLabel("Teleinfo ADCO/ADSC " + adco).withThingType(getThingTypeUID(frameSample)) .withBridge(controllerHandlerRef.getThing().getUID()) .withRepresentationProperty(representationProperty).build(); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java index 158d58a844783..4a51753f1dafa 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Evolution.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.teleinfo.internal.data; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Define the evolution option values * * @author Olivier MARCEAU - Initial contribution * */ +@NonNullByDefault public enum Evolution { ICC, NONE diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java index 3594885198abb..e83f83efa7747 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Frame.java @@ -20,6 +20,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException; import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; /** * The {@link Frame} class defines common attributes for any Teleinfo frames. @@ -32,11 +33,16 @@ public class Frame implements Serializable { private static final long serialVersionUID = -1934715078822532494L; private Map labelToValues = new EnumMap<>(Label.class); + private Map labelToTimestamp = new EnumMap<>(Label.class); public void put(Label label, String value) { labelToValues.put(label, value); } + public void putTimestamp(Label label, String timestamp) { + labelToTimestamp.put(label, timestamp); + } + public @Nullable String get(Label label) { return labelToValues.get(label); } @@ -49,11 +55,33 @@ public void put(Label label, String value) { return null; } + public String getAsDateTime(Label label) { + String timestamp = labelToTimestamp.get(label); + if (timestamp == null) { + return ""; + } + return "20" + timestamp.substring(1, 3) + "-" + timestamp.substring(3, 5) + "-" + timestamp.substring(5, 7) + + "T" + timestamp.substring(7, 9) + ":" + timestamp.substring(9, 11) + ":" + + timestamp.substring(11, 13); + } + public Frame() { // default constructor } public FrameType getType() throws InvalidFrameException { + TeleinfoTicMode ticMode = getTicMode(); + switch (ticMode) { + case HISTORICAL: + return getHistoricalType(); + case STANDARD: + return getStandardType(); + default: + throw new InvalidFrameException(); + } + } + + public FrameType getHistoricalType() throws InvalidFrameException { Phase phase = getPhase(); Pricing pricing = getPricing(); Evolution evolution = getEvolution(); @@ -152,14 +180,43 @@ public Pricing getPricing() throws InvalidFrameException { } } + public TeleinfoTicMode getTicMode() throws InvalidFrameException { + if (labelToValues.containsKey(Label.ADCO)) { + return TeleinfoTicMode.HISTORICAL; + } else if (labelToValues.containsKey(Label.ADSC)) { + return TeleinfoTicMode.STANDARD; + } + throw new InvalidFrameException(); + } + + public FrameType getStandardType() throws InvalidFrameException { + boolean isProd = labelToValues.containsKey(Label.EAIT); + boolean isThreePhase = labelToValues.containsKey(Label.IRMS2); + if (isProd && isThreePhase) { + return FrameType.LSMT_PROD; + } + if (isProd) { + return FrameType.LSMM_PROD; + } + if (isThreePhase) { + return FrameType.LSMT; + } + return FrameType.LSMM; + } + public void clear() { labelToValues.clear(); + labelToTimestamp.clear(); } public Map getLabelToValues() { return labelToValues; } + public Map getLabelToTimestamp() { + return labelToTimestamp; + } + private char getProgrammeChar() { String optarif = labelToValues.get(Label.OPTARIF); if (optarif == null) { diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java index a829805b37ffd..05a590d9831ad 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/FrameType.java @@ -14,6 +14,8 @@ import static org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants.*; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.thing.ThingTypeUID; /** @@ -22,6 +24,7 @@ * @author Olivier MARCEAU - Initial contribution * */ +@NonNullByDefault public enum FrameType { CBETM_SHORT(null), CBETM_LONG_BASE(THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID), @@ -36,15 +39,19 @@ public enum FrameType { CBEMM_ICC_EJP(THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID), CBEMM_ICC_TEMPO(THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID), CBEMM_ICC_HC(THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID), + LSMT_PROD(THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID), + LSMM_PROD(THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID), + LSMM(THING_LSMM_ELECTRICITY_METER_TYPE_UID), + LSMT(THING_LSMT_ELECTRICITY_METER_TYPE_UID), UNKNOWN(null); - private ThingTypeUID thingTypeUid; + private @Nullable ThingTypeUID thingTypeUid; - FrameType(ThingTypeUID thingTypeUid) { + FrameType(@Nullable ThingTypeUID thingTypeUid) { this.thingTypeUid = thingTypeUid; } - public ThingTypeUID getThingTypeUid() { + public @Nullable ThingTypeUID getThingTypeUid() { return thingTypeUid; } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java index 44edb6d0a4e25..dfe0c42d8d5f7 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Phase.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.teleinfo.internal.data; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Define all the phase values * * @author Olivier MARCEAU - Initial contribution * */ +@NonNullByDefault public enum Phase { ONE_PHASED, THREE_PHASED diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java index cef1a504f6e47..6bc6cabcb670c 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/data/Pricing.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.teleinfo.internal.data; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Define all the pricing option values * * @author Olivier MARCEAU - Initial contribution * */ +@NonNullByDefault public enum Pricing { BASE, TEMPO, diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java index 67a8bd8da717b..ee0a0c24b979c 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoElectricityMeterHandler.java @@ -21,10 +21,13 @@ import org.openhab.binding.teleinfo.internal.data.Frame; import org.openhab.binding.teleinfo.internal.data.Phase; import org.openhab.binding.teleinfo.internal.data.Pricing; +import org.openhab.binding.teleinfo.internal.reader.io.serialport.FrameUtil; import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException; import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label; import org.openhab.binding.teleinfo.internal.reader.io.serialport.ValueType; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Bridge; @@ -130,7 +133,7 @@ protected void updateStatus(ThingStatus status) { @Override public void onFrameReceived(Frame frame) { String adco = configuration.getAdco(); - if (adco.equalsIgnoreCase(frame.get(Label.ADCO))) { + if (adco.equalsIgnoreCase(frame.get(Label.ADCO)) || adco.equalsIgnoreCase(frame.get(Label.ADSC))) { updateStatesForChannels(frame); } } @@ -139,39 +142,65 @@ private void updateStatesForChannels(Frame frame) { for (Entry entry : frame.getLabelToValues().entrySet()) { Label label = entry.getKey(); if (!label.getChannelName().equals(NOT_A_CHANNEL)) { + logger.trace("Update channel {} to value {}", label.getChannelName(), entry.getValue()); if (label == Label.PTEC) { updateState(label.getChannelName(), StringType.valueOf(entry.getValue().replace(".", ""))); } else if (label.getType() == ValueType.STRING) { updateState(label.getChannelName(), StringType.valueOf(entry.getValue())); } else if (label.getType() == ValueType.INTEGER) { - updateState(label.getChannelName(), - QuantityType.valueOf(Integer.parseInt(entry.getValue()), label.getUnit())); + updateState(label.getChannelName(), QuantityType + .valueOf(label.getFactor() * Integer.parseInt(entry.getValue()), label.getUnit())); } } - } - try { - if (frame.getPricing() == Pricing.TEMPO) { - updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_1, StringType.valueOf(frame.getProgrammeCircuit1())); - updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_2, StringType.valueOf(frame.getProgrammeCircuit2())); + if (!label.getTimestampChannelName().equals(NOT_A_CHANNEL)) { + String timestamp = frame.getAsDateTime(label); + if (!timestamp.isEmpty()) { + logger.trace("Update channel {} to value {}", label.getTimestampChannelName(), timestamp); + updateState(label.getTimestampChannelName(), DateTimeType.valueOf(timestamp)); + } } - } catch (InvalidFrameException e) { - logger.warn("Can not find pricing option."); } - try { - Phase phase = frame.getPhase(); - if (phase == Phase.ONE_PHASED) { - updateStateForMissingAlert(frame, Label.ADPS); - } else if (phase == Phase.THREE_PHASED) { - if (!wasLastFrameShort) { - updateStateForMissingAlert(frame, Label.ADIR1); - updateStateForMissingAlert(frame, Label.ADIR2); - updateStateForMissingAlert(frame, Label.ADIR3); + if (frame.getTicMode() == TeleinfoTicMode.HISTORICAL) { + try { + if (frame.getPricing() == Pricing.TEMPO) { + updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_1, + StringType.valueOf(frame.getProgrammeCircuit1())); + updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_2, + StringType.valueOf(frame.getProgrammeCircuit2())); + } + } catch (InvalidFrameException e) { + logger.warn("Can not find pricing option."); + } + + try { + Phase phase = frame.getPhase(); + if (phase == Phase.ONE_PHASED) { + updateStateForMissingAlert(frame, Label.ADPS); + } else if (phase == Phase.THREE_PHASED) { + if (!wasLastFrameShort) { + updateStateForMissingAlert(frame, Label.ADIR1); + updateStateForMissingAlert(frame, Label.ADIR2); + updateStateForMissingAlert(frame, Label.ADIR3); + } + wasLastFrameShort = frame.isShortFrame(); + } + } catch (InvalidFrameException e) { + logger.warn("Can not find phase."); + } + } else { + if (frame.getLabelToValues().containsKey(Label.RELAIS)) { + String relaisString = frame.get(Label.RELAIS); + if (relaisString != null) { + boolean[] relaisStates = FrameUtil.parseRelaisStates(relaisString); + for (int i = 0; i <= 7; i++) { + updateState(CHANNELS_LSM_RELAIS[i], OnOffType.from(relaisStates[i])); + } + } } - wasLastFrameShort = frame.isShortFrame(); } } catch (InvalidFrameException e) { - logger.warn("Can not find phase."); + logger.warn("Can not find TIC mode."); } updateState(CHANNEL_LAST_UPDATE, new DateTimeType()); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java index bc7755c692ecb..2378dddd3b061 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/handler/TeleinfoThingHandlerFactory.java @@ -48,7 +48,9 @@ public class TeleinfoThingHandlerFactory extends BaseThingHandlerFactory { THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID, THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID, - THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID) + THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID, THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID, + THING_LSMM_ELECTRICITY_METER_TYPE_UID, THING_LSMM_PROD_ELECTRICITY_METER_TYPE_UID, + THING_LSMT_ELECTRICITY_METER_TYPE_UID, THING_LSMT_PROD_ELECTRICITY_METER_TYPE_UID) .collect(Collectors.toSet()); private final SerialPortManager serialPortManager; diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java index 270675054f918..7152be74dc8b5 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStream.java @@ -24,6 +24,7 @@ import org.openhab.binding.teleinfo.internal.reader.io.serialport.FrameUtil; import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException; import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,19 +44,32 @@ public class TeleinfoInputStream extends InputStream { private BufferedReader bufferedReader; private @Nullable String groupLine; private boolean autoRepairInvalidADPSgroupLine; + private final TeleinfoTicMode ticMode; + private final boolean verifyChecksum; private final Frame frame = new Frame(); - public TeleinfoInputStream(final InputStream teleinfoInputStream) { - this(teleinfoInputStream, false); + public TeleinfoInputStream(final InputStream teleinfoInputStream, TeleinfoTicMode ticMode) { + this(teleinfoInputStream, false, ticMode, true); } - public TeleinfoInputStream(final @Nullable InputStream teleinfoInputStream, - boolean autoRepairInvalidADPSgroupLine) { + public TeleinfoInputStream(final InputStream teleinfoInputStream, boolean autoRepairInvalidADPSgroupLine, + TeleinfoTicMode ticMode) { + this(teleinfoInputStream, autoRepairInvalidADPSgroupLine, ticMode, true); + } + + public TeleinfoInputStream(final InputStream teleinfoInputStream, TeleinfoTicMode ticMode, boolean verifyChecksum) { + this(teleinfoInputStream, false, ticMode, verifyChecksum); + } + + public TeleinfoInputStream(final @Nullable InputStream teleinfoInputStream, boolean autoRepairInvalidADPSgroupLine, + TeleinfoTicMode ticMode, boolean verifyChecksum) { if (teleinfoInputStream == null) { throw new IllegalArgumentException("Teleinfo inputStream is null"); } this.autoRepairInvalidADPSgroupLine = autoRepairInvalidADPSgroupLine; + this.ticMode = ticMode; + this.verifyChecksum = verifyChecksum; this.bufferedReader = new BufferedReader(new InputStreamReader(teleinfoInputStream, StandardCharsets.US_ASCII)); groupLine = null; @@ -96,29 +110,48 @@ public void close() throws IOException { logger.trace("groupLine = {}", groupLine); String groupLineRef = groupLine; if (groupLineRef != null) { - String[] groupLineTokens = groupLineRef.split("\\s"); - if (groupLineTokens.length != 2 && groupLineTokens.length != 3) { + String[] groupLineTokens = groupLineRef.split(ticMode.getSeparator()); + if (ticMode == TeleinfoTicMode.HISTORICAL && groupLineTokens.length != 2 && groupLineTokens.length != 3 + || ticMode == TeleinfoTicMode.STANDARD && groupLineTokens.length != 3 + && groupLineTokens.length != 4) { final String error = String.format("The groupLine '%1$s' is incomplete", groupLineRef); throw new InvalidFrameException(error); } String labelStr = groupLineTokens[0]; - String valueString = groupLineTokens[1]; + String valueString; + String timestampString = null; + switch (ticMode) { + default: + valueString = groupLineTokens[1]; + break; + case STANDARD: + if (groupLineTokens.length == 3) { + valueString = groupLineTokens[1]; + } else { + timestampString = groupLineTokens[1]; + valueString = groupLineTokens[2]; + } + break; + } // verify integrity (through checksum) - char checksum = (groupLineTokens.length == 3 ? groupLineTokens[2].charAt(0) : ' '); - char computedChecksum = FrameUtil.computeGroupLineChecksum(labelStr, valueString); - if (computedChecksum != checksum) { - logger.trace("computedChecksum = {}", computedChecksum); - logger.trace("checksum = {}", checksum); - final String error = String.format( - "The groupLine '%s' is corrupted (integrity not checked). Actual checksum: '%s' / Expected checksum: '%s'", - groupLineRef, checksum, computedChecksum); - throw new InvalidFrameException(error); + if (verifyChecksum) { + char checksum = groupLineRef.charAt(groupLineRef.length() - 1); + char computedChecksum = FrameUtil + .computeGroupLineChecksum(groupLineRef.substring(0, groupLineRef.length() - 2), ticMode); + if (computedChecksum != checksum) { + logger.trace("computedChecksum = {}", computedChecksum); + logger.trace("checksum = {}", checksum); + final String error = String.format( + "The groupLine '%s' is corrupted (integrity not checked). Actual checksum: '%s' / Expected checksum: '%s'", + groupLineRef, checksum, computedChecksum); + throw new InvalidFrameException(error); + } } Label label; try { - label = Label.valueOf(labelStr); + label = Label.getEnum(labelStr); } catch (IllegalArgumentException e) { if (autoRepairInvalidADPSgroupLine && labelStr.startsWith(Label.ADPS.name())) { // in this hardware issue, label variable is composed by label name and value. E.g: @@ -133,6 +166,9 @@ public void close() throws IOException { } frame.put(label, valueString); + if (timestampString != null) { + frame.putTimestamp(label, timestampString); + } } } @@ -152,7 +188,7 @@ public int read() throws IOException { throw new UnsupportedOperationException("The 'read()' is not supported"); } - private boolean isHeaderFrame(final @Nullable String line) { + public static boolean isHeaderFrame(final @Nullable String line) { // A new teleinfo trame begin with '3' and '2' bytes (END OF TEXT et START OF TEXT) return (line != null && line.length() > 1 && line.codePointAt(0) == 3 && line.codePointAt(1) == 2); } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java index ee8268a1f0e0b..fd8b623c969aa 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtil.java @@ -13,6 +13,7 @@ package org.openhab.binding.teleinfo.internal.reader.io.serialport; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; /** * The {@link FrameUtil} class defines a utility class for {@link FrameCbetmLong}. @@ -33,14 +34,31 @@ private FrameUtil() { * must not include in checksum computation. * @return the checksum of the given group line. */ - public static char computeGroupLineChecksum(final String label, final String value) { - final String groupLine = label + " " + value; + public static char computeGroupLineChecksum(final String groupLine, TeleinfoTicMode ticMode) { int sum = 0; for (int i = 0; i < groupLine.length(); i++) { - sum = sum + groupLine.codePointAt(i); + sum += groupLine.codePointAt(i); + } + if (ticMode == TeleinfoTicMode.STANDARD) { + sum += 0x09; } sum = (sum & 0x3F) + 0x20; - return (char) sum; } + + /** + * Parse relais states. + * + * @param relais integer string + * @return State of each relais + */ + public static boolean[] parseRelaisStates(String relais) { + boolean[] relaisState = new boolean[8]; + int value = Integer.parseInt(relais); + for (int i = 0; i <= 7; i++) { + relaisState[i] = (value & 1) == 1; + value >>= 1; + } + return relaisState; + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java index 433fb136c862a..e2b56d9f3d57b 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/Label.java @@ -27,13 +27,14 @@ @NonNullByDefault public enum Label { + // Historical labels ADCO(ValueType.STRING, NOT_A_CHANNEL, Units.ONE), OPTARIF(ValueType.STRING, NOT_A_CHANNEL, Units.ONE), BASE(ValueType.INTEGER, CHANNEL_BASE_FRAME_BASE, Units.WATT_HOUR), HCHC(ValueType.INTEGER, CHANNEL_HC_FRAME_HCHC, Units.WATT_HOUR), HCHP(ValueType.INTEGER, CHANNEL_HC_FRAME_HCHP, Units.WATT_HOUR), EJPHN(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHN, Units.WATT_HOUR), - EJPHPM(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHN, Units.WATT_HOUR), + EJPHPM(ValueType.INTEGER, CHANNEL_EJP_FRAME_EJPHPM, Units.WATT_HOUR), PTEC(ValueType.STRING, CHANNEL_PTEC, Units.ONE), MOTDETAT(ValueType.STRING, CHANNEL_MOTDETAT, Units.AMPERE), ISOUSC(ValueType.INTEGER, CHANNEL_ISOUSC, Units.AMPERE), @@ -60,16 +61,108 @@ public enum Label { BBRHCJR(ValueType.INTEGER, CHANNEL_TEMPO_FRAME_BBRHCJR, Units.WATT_HOUR), BBRHPJR(ValueType.INTEGER, CHANNEL_TEMPO_FRAME_BBRHPJR, Units.WATT_HOUR), PEJP(ValueType.INTEGER, CHANNEL_EJP_FRAME_PEJP, Units.MINUTE), - DEMAIN(ValueType.STRING, CHANNEL_TEMPO_FRAME_DEMAIN, Units.ONE); + DEMAIN(ValueType.STRING, CHANNEL_TEMPO_FRAME_DEMAIN, Units.ONE), - private ValueType type; - private String channelName; - private Unit unit; + // Standard TIC mode labels + ADSC(ValueType.STRING, NOT_A_CHANNEL, Units.ONE), + VTIC(ValueType.INTEGER, NOT_A_CHANNEL, Units.ONE), + DATE(ValueType.STRING, NOT_A_CHANNEL, CHANNEL_LSM_DATE, Units.ONE), + NGTF(ValueType.STRING, CHANNEL_LSM_NGTF, Units.ONE), + LTARF(ValueType.STRING, CHANNEL_LSM_LTARF, Units.ONE), + EAST(ValueType.INTEGER, CHANNEL_LSM_EAST, Units.WATT_HOUR), + EASF01(ValueType.INTEGER, CHANNEL_LSM_EASF01, Units.WATT_HOUR), + EASF02(ValueType.INTEGER, CHANNEL_LSM_EASF02, Units.WATT_HOUR), + EASF03(ValueType.INTEGER, CHANNEL_LSM_EASF03, Units.WATT_HOUR), + EASF04(ValueType.INTEGER, CHANNEL_LSM_EASF04, Units.WATT_HOUR), + EASF05(ValueType.INTEGER, CHANNEL_LSM_EASF05, Units.WATT_HOUR), + EASF06(ValueType.INTEGER, CHANNEL_LSM_EASF06, Units.WATT_HOUR), + EASF07(ValueType.INTEGER, CHANNEL_LSM_EASF07, Units.WATT_HOUR), + EASF08(ValueType.INTEGER, CHANNEL_LSM_EASF08, Units.WATT_HOUR), + EASF09(ValueType.INTEGER, CHANNEL_LSM_EASF09, Units.WATT_HOUR), + EASF10(ValueType.INTEGER, CHANNEL_LSM_EASF10, Units.WATT_HOUR), + EASD01(ValueType.INTEGER, CHANNEL_LSM_EASD01, Units.WATT_HOUR), + EASD02(ValueType.INTEGER, CHANNEL_LSM_EASD02, Units.WATT_HOUR), + EASD03(ValueType.INTEGER, CHANNEL_LSM_EASD03, Units.WATT_HOUR), + EASD04(ValueType.INTEGER, CHANNEL_LSM_EASD04, Units.WATT_HOUR), + EAIT(ValueType.INTEGER, CHANNEL_LSM_EAIT, Units.WATT_HOUR), + ERQ1(ValueType.INTEGER, CHANNEL_LSM_ERQ1, Units.VOLT_AMPERE_HOUR), + ERQ2(ValueType.INTEGER, CHANNEL_LSM_ERQ2, Units.VOLT_AMPERE_HOUR), + ERQ3(ValueType.INTEGER, CHANNEL_LSM_ERQ3, Units.VOLT_AMPERE_HOUR), + ERQ4(ValueType.INTEGER, CHANNEL_LSM_ERQ4, Units.VOLT_AMPERE_HOUR), + IRMS1(ValueType.INTEGER, CHANNEL_LSM_IRMS1, Units.AMPERE), + IRMS2(ValueType.INTEGER, CHANNEL_LSM_IRMS2, Units.AMPERE), + IRMS3(ValueType.INTEGER, CHANNEL_LSM_IRMS3, Units.AMPERE), + URMS1(ValueType.INTEGER, CHANNEL_LSM_URMS1, Units.VOLT), + URMS2(ValueType.INTEGER, CHANNEL_LSM_URMS2, Units.VOLT), + URMS3(ValueType.INTEGER, CHANNEL_LSM_URMS3, Units.VOLT), + PREF(ValueType.INTEGER, CHANNEL_LSM_PREF, Units.VOLT_AMPERE, 1000), + PCOUP(ValueType.INTEGER, CHANNEL_LSM_PCOUP, Units.VOLT_AMPERE, 1000), + SINSTS(ValueType.INTEGER, CHANNEL_LSM_SINSTS, Units.VOLT_AMPERE), + SINSTS1(ValueType.INTEGER, CHANNEL_LSM_SINSTS1, Units.VOLT_AMPERE), + SINSTS2(ValueType.INTEGER, CHANNEL_LSM_SINSTS2, Units.VOLT_AMPERE), + SINSTS3(ValueType.INTEGER, CHANNEL_LSM_SINSTS3, Units.VOLT_AMPERE), + SMAXSN(ValueType.INTEGER, CHANNEL_LSM_SMAXSN, CHANNEL_LSM_SMAXSN_DATE, Units.VOLT_AMPERE), + SMAXSN1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN1, CHANNEL_LSM_SMAXSN1_DATE, Units.VOLT_AMPERE), + SMAXSN2(ValueType.INTEGER, CHANNEL_LSM_SMAXSN2, CHANNEL_LSM_SMAXSN2_DATE, Units.VOLT_AMPERE), + SMAXSN3(ValueType.INTEGER, CHANNEL_LSM_SMAXSN3, CHANNEL_LSM_SMAXSN3_DATE, Units.VOLT_AMPERE), + SMAXSN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN_MINUS_1, CHANNEL_LSM_SMAXSN_MINUS_1_DATE, Units.VOLT_AMPERE), + SMAXSN1_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN1_MINUS_1, CHANNEL_LSM_SMAXSN1_MINUS_1_DATE, + Units.VOLT_AMPERE), + SMAXSN2_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN2_MINUS_1, CHANNEL_LSM_SMAXSN2_MINUS_1_DATE, + Units.VOLT_AMPERE), + SMAXSN3_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXSN3_MINUS_1, CHANNEL_LSM_SMAXSN3_MINUS_1_DATE, + Units.VOLT_AMPERE), + SINSTI(ValueType.INTEGER, CHANNEL_LSM_SINSTI, Units.VOLT_AMPERE), + SMAXIN(ValueType.INTEGER, CHANNEL_LSM_SMAXIN, CHANNEL_LSM_SMAXIN_DATE, Units.VOLT_AMPERE), + SMAXIN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_SMAXIN_MINUS_1, CHANNEL_LSM_SMAXIN_MINUS_1_DATE, Units.VOLT_AMPERE), + CCASN(ValueType.INTEGER, CHANNEL_LSM_CCASN, CHANNEL_LSM_CCASN_DATE, Units.WATT), + CCASN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_CCASN_MINUS_1, CHANNEL_LSM_CCASN_MINUS_1_DATE, Units.WATT), + CCAIN(ValueType.INTEGER, CHANNEL_LSM_CCAIN, CHANNEL_LSM_CCAIN_DATE, Units.WATT), + CCAIN_MINUS_1(ValueType.INTEGER, CHANNEL_LSM_CCAIN_MINUS_1, CHANNEL_LSM_CCAIN_MINUS_1_DATE, Units.WATT), + UMOY1(ValueType.INTEGER, CHANNEL_LSM_UMOY1, CHANNEL_LSM_UMOY1_DATE, Units.VOLT), + UMOY2(ValueType.INTEGER, CHANNEL_LSM_UMOY2, CHANNEL_LSM_UMOY2_DATE, Units.VOLT), + UMOY3(ValueType.INTEGER, CHANNEL_LSM_UMOY3, CHANNEL_LSM_UMOY3_DATE, Units.VOLT), + STGE(ValueType.STRING, CHANNEL_LSM_STGE, Units.ONE), + DPM1(ValueType.STRING, CHANNEL_LSM_DPM1, CHANNEL_LSM_DPM1_DATE, Units.ONE), + FPM1(ValueType.STRING, CHANNEL_LSM_FPM1, CHANNEL_LSM_FPM1_DATE, Units.ONE), + DPM2(ValueType.STRING, CHANNEL_LSM_DPM2, CHANNEL_LSM_DPM2_DATE, Units.ONE), + FPM2(ValueType.STRING, CHANNEL_LSM_FPM2, CHANNEL_LSM_FPM2_DATE, Units.ONE), + DPM3(ValueType.STRING, CHANNEL_LSM_DPM3, CHANNEL_LSM_DPM3_DATE, Units.ONE), + FPM3(ValueType.STRING, CHANNEL_LSM_FPM3, CHANNEL_LSM_FPM3_DATE, Units.ONE), + MSG1(ValueType.STRING, CHANNEL_LSM_MSG1, Units.ONE), + MSG2(ValueType.STRING, CHANNEL_LSM_MSG2, Units.ONE), + PRM(ValueType.STRING, CHANNEL_LSM_PRM, Units.ONE), + RELAIS(ValueType.STRING, NOT_A_CHANNEL, Units.ONE), + NTARF(ValueType.STRING, CHANNEL_LSM_NTARF, Units.ONE), + NJOURF(ValueType.STRING, CHANNEL_LSM_NJOURF, Units.ONE), + NJOURF_PLUS_1(ValueType.STRING, CHANNEL_LSM_NJOURF_PLUS_1, Units.ONE), + PJOURF_PLUS_1(ValueType.STRING, CHANNEL_LSM_PJOURF_PLUS_1, Units.ONE), + PPOINTE(ValueType.STRING, CHANNEL_LSM_PPOINTE, Units.ONE); + + private final ValueType type; + private final String channelName; + private final String timestampChannelName; + private final Unit unit; + private final int factor; Label(ValueType type, String channelName, Unit unit) { + this(type, channelName, NOT_A_CHANNEL, unit, 1); + } + + Label(ValueType type, String channelName, String timestampChannelName, Unit unit) { + this(type, channelName, timestampChannelName, unit, 1); + } + + Label(ValueType type, String channelName, Unit unit, int factor) { + this(type, channelName, NOT_A_CHANNEL, unit, factor); + } + + Label(ValueType type, String channelName, String timestampChannelName, Unit unit, int factor) { this.type = type; this.channelName = channelName; + this.timestampChannelName = timestampChannelName; this.unit = unit; + this.factor = factor; } public ValueType getType() { @@ -80,7 +173,21 @@ public String getChannelName() { return channelName; } + public String getTimestampChannelName() { + return timestampChannelName; + } + public Unit getUnit() { return unit; } + + public int getFactor() { + return factor; + } + + public static Label getEnum(String label) { + String modifiedLabel = label.replace("-", "_MINUS_"); + modifiedLabel = modifiedLabel.replace("+", "_PLUS_"); + return valueOf(modifiedLabel); + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java index 62d743565fe00..76519d3b6790a 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/ValueType.java @@ -12,12 +12,15 @@ */ package org.openhab.binding.teleinfo.internal.reader.io.serialport; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * Defines all the type of values * * @author Olivier MARCEAU - Initial contribution * */ +@NonNullByDefault public enum ValueType { INTEGER, STRING diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java index a3eee6052cf19..7228190bf5d91 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoReceiveThread.java @@ -36,20 +36,24 @@ public class TeleinfoReceiveThread extends Thread { private SerialPort serialPort; private @Nullable TeleinfoReceiveThreadListener listener; private boolean autoRepairInvalidADPSgroupLine; + private final TeleinfoTicMode ticMode; + private final boolean verifyChecksum; public TeleinfoReceiveThread(SerialPort serialPort, final TeleinfoSerialControllerHandler listener, - boolean autoRepairInvalidADPSgroupLine) { + boolean autoRepairInvalidADPSgroupLine, TeleinfoTicMode ticMode, boolean verifyChecksum) { super("OH-binding-TeleinfoReceiveThread-" + listener.getThing().getUID().getId()); setDaemon(true); this.serialPort = serialPort; this.listener = listener; this.autoRepairInvalidADPSgroupLine = autoRepairInvalidADPSgroupLine; + this.ticMode = ticMode; + this.verifyChecksum = verifyChecksum; } @Override public void run() { try (TeleinfoInputStream teleinfoStream = new TeleinfoInputStream(serialPort.getInputStream(), - autoRepairInvalidADPSgroupLine)) { + autoRepairInvalidADPSgroupLine, ticMode, verifyChecksum)) { while (!interrupted()) { TeleinfoReceiveThreadListener listener = this.listener; if (listener != null) { diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java index 654a6250d843f..71711c4dbdee4 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerConfiguration.java @@ -23,5 +23,7 @@ public class TeleinfoSerialControllerConfiguration { public String serialport = ""; + public String ticMode = ""; + public boolean verifyChecksum = true; public boolean autoRepairInvalidADPSgroupLine = true; } diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java index b5e08d32fbdb5..44fe2c15a27b5 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoSerialControllerHandler.java @@ -148,7 +148,9 @@ private void openSerialPortAndStartReceiving() { SerialPort commPort = portIdentifier.open("org.openhab.binding.teleinfo", 5000); serialPort = commPort; - commPort.setSerialPortParams(1200, SerialPort.DATABITS_7, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN); + TeleinfoTicMode ticMode = TeleinfoTicMode.valueOf(config.ticMode); + commPort.setSerialPortParams(ticMode.getBitrate(), SerialPort.DATABITS_7, SerialPort.STOPBITS_1, + SerialPort.PARITY_EVEN); try { commPort.enableReceiveThreshold(1); } catch (UnsupportedCommOperationException e) { @@ -161,7 +163,7 @@ private void openSerialPortAndStartReceiving() { } logger.debug("Starting receive thread"); TeleinfoReceiveThread receiveThread = new TeleinfoReceiveThread(commPort, this, - config.autoRepairInvalidADPSgroupLine); + config.autoRepairInvalidADPSgroupLine, ticMode, config.verifyChecksum); this.receiveThread = receiveThread; receiveThread.start(); diff --git a/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java new file mode 100644 index 0000000000000..77cd6ef0bd8b0 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/java/org/openhab/binding/teleinfo/internal/serial/TeleinfoTicMode.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.teleinfo.internal.serial; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Define an enum for TIC mode of Linky telemeters + * + * @author Olivier MARCEAU - Initial contribution + */ +@NonNullByDefault +public enum TeleinfoTicMode { + HISTORICAL(1200, "\\s"), + STANDARD(9600, "\\t"); + + private final int bitrate; + private final String separator; + + TeleinfoTicMode(int bitrate, String separator) { + this.bitrate = bitrate; + this.separator = separator; + } + + public int getBitrate() { + return bitrate; + } + + public String getSeparator() { + return separator; + } +} diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml index 6701d48d220c3..34d2a259b0429 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/config/config-description.xml @@ -7,7 +7,7 @@ - + Electricity meter identifier (format: 12 characters / e.g: '031528042289') false diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml new file mode 100644 index 0000000000000..8a17dd7845d06 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-channel-group.xml @@ -0,0 +1,362 @@ + + + + + + Common channels for Linky telemeter in standard teleinformation mode + Energy + + + + + Provider schedule name + + + + + Current pricing label + + + + + Total active energy withdrawn + + + + + Active energy withdrawn from provider on index 01 + + + + + Active energy withdrawn from provider on index 02 + + + + + Active energy withdrawn from provider on index 03 + + + + + Active energy withdrawn from provider on index 04 + + + + + Active energy withdrawn from provider on index 05 + + + + + Active energy withdrawn from provider on index 06 + + + + + Active energy withdrawn from provider on index 07 + + + + + Active energy withdrawn from provider on index 08 + + + + + Active energy withdrawn from provider on index 09 + + + + + Active energy withdrawn from provider on index 10 + + + + + Active energy withdrawn from distributor on index 01 + + + + + Active energy withdrawn from distributor on index 02 + + + + + Active energy withdrawn from distributor on index 03 + + + + + Active energy withdrawn from distributor on index 04 + + + + + RMS Current on phase 1 + + + + + RMS Voltage on phase 1 + + + + + Reference apparent power + + + + + Apparent power rupture capacity + + + + + Instantaneous withdrawn apparent power + + + + + Maximum withdrawn apparent power of the day + + + + + Maximum withdrawn apparent power of the previous day + + + + + Active charge point N + + + + + Active charge point N-1 + + + + + Mean Voltage on phase 1 + + + + + Status registry + + + + + Start of mobile peak period 1 + + + + + End of mobile peak period 1 + + + + + Start of mobile peak period 2 + + + + + End of mobile peak period 2 + + + + + Start of mobile peak period 3 + + + + + End of mobile peak period 3 + + + + + Short message + + + + + Very short message + + + + + PRM + + + + + + Index of current pricing + + + + + Number of current provider schedule + + + + + Number of next day provider schedule + + + + + Profile of next day provider schedule + + + + + Profile of next rush day + + + + + Date and Time + + + + + Timestamp of SMAXSN value + + + + + Timestamp of SMAXSN-1 value + + + + + Timestamp of CCASN value + + + + + Timestamp of CCASN-1 value + + + + + Timestamp of UMOY1 value + + + + + Date of DPM1 + + + + + Date of FPM1 + + + + + Date of DPM2 + + + + + Date of FPM2 + + + + + Date of DPM3 + + + + + Date of FPM3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml new file mode 100644 index 0000000000000..63399587edef0 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-prod-channel-group.xml @@ -0,0 +1,133 @@ + + + + + + Producer channels for Linky telemeter in standard teleinformation mode + Energy + + + + Total active energy injected + + + + + Total reactive energy Q1 + + + + + Total reactive energy Q2 + + + + + Total reactive energy Q3 + + + + + Total reactive energy Q4 + + + + + Instantaneous injected apparent power + + + + + Maximum injected apparent power of the day + + + + + Maximum injected apparent power of the previous day + + + + + Injected active charge point N + + + + + Injected active charge point N-1 + + + + + Timestamp of SMAXIN value + + + + + Timestamp of SMAXIN-1 value + + + + + Timestamp of CCAIN value + + + + + Timestamp of CCAIN-1 value + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml new file mode 100644 index 0000000000000..40860229781b2 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/common-lsm-three-phase-channel-group.xml @@ -0,0 +1,179 @@ + + + + + + Three-phased channels for Linky telemeter in standard teleinformation mode + Energy + + + + + RMS Current on phase 2 + + + + + RMS Current on phase 3 + + + + + RMS Voltage on phase 2 + + + + + RMS Voltage on phase 3 + + + + + Instantaneous withdrawn apparent power on phase 1 + + + + + Instantaneous withdrawn apparent power on phase 2 + + + + + Instantaneous withdrawn apparent power on phase 3 + + + + + Maximum withdrawn apparent power of the day on phase 1 + + + + + Maximum withdrawn apparent power of the day on phase 2 + + + + + Maximum withdrawn apparent power of the day on phase 3 + + + + + Maximum withdrawn apparent power of the previous day on phase 1 + + + + + Maximum withdrawn apparent power of the previous day on phase 2 + + + + + Maximum withdrawn apparent power of the previous day on phase 3 + + + + + Mean Voltage on phase 2 + + + + + Mean Voltage on phase 3 + + + + + Timestamp of SMAXSN1 value + + + + + Timestamp of SMAXSN2 value + + + + + Timestamp of SMAXSN3 value + + + + + Timestamp of SMAXSN1-1 value + + + + + Timestamp of SMAXSN2-1 value + + + + + Timestamp of SMAXSN3-1 value + + + + + Timestamp of UMOY2 value + + + + + Timestamp of UMOY3 value + + + + + + String + + Energy + + + + + Number:Energy + + Energy + + + + + Number:ElectricCurrent + + Energy + + + + + Number:ElectricPotential + + Energy + + + + + Number:Power + + Energy + + + + + Switch + + Energy + + + + + DateTime + + Energy + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml new file mode 100644 index 0000000000000..674173ffc8f17 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmElectricityMeter.xml @@ -0,0 +1,23 @@ + + + + + + + + + + Single-phase Linky Electricity meter in standard mode + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml new file mode 100644 index 0000000000000..d23487fdeeb6b --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmmProdElectricityMeter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + Single-phase producer Linky Electricity meter in standard mode + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml new file mode 100644 index 0000000000000..de906e24f9e72 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtElectricityMeter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + Three-phase Linky Electricity meter in standard mode + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml new file mode 100644 index 0000000000000..b744df2fdc627 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/lsmtProdElectricityMeter.xml @@ -0,0 +1,25 @@ + + + + + + + + + + Three-phase producer Linky Electricity meter in standard mode + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml index 486c94676f538..22984bc17e981 100644 --- a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/thing/serialController.xml @@ -19,6 +19,22 @@ Serial port of Teleinfo device (e.g.: /dev/ttyUSB0 on Linux, COM1 on Windows) false + + + TIC Mode of the telemeter (Standard TIC mode is only available on Linky telemeters) + HISTORICAL + + + + + true + + + + Activate checksum verification + true + true + Try to auto repair malformed ADPS data from hardware issues (e.g: "ADPS032" instead of "ADPS 032" diff --git a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java index d17f77c9d25a1..d420013900488 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java +++ b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/TeleinfoInputStreamTest.java @@ -15,13 +15,17 @@ import static org.junit.jupiter.api.Assertions.*; import java.io.FileInputStream; +import java.time.Month; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; +import org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants; import org.openhab.binding.teleinfo.internal.data.Frame; import org.openhab.binding.teleinfo.internal.data.FrameType; import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; import org.openhab.binding.teleinfo.util.TestUtils; +import org.openhab.core.library.types.DateTimeType; /** * @@ -33,7 +37,8 @@ public class TeleinfoInputStreamTest { @Test public void testReadNextFrameCbetmBase1() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("cbetm-base-option-1.raw")), false)) { + new FileInputStream(TestUtils.getTestFile("cbetm-base-option-1.raw")), false, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); @@ -57,7 +62,8 @@ public void testReadNextFrameCbetmBase1() throws Exception { @Test public void testReadNextFrameCbemmEvoIccHc1() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-hc-option-1.raw")), false)) { + new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-hc-option-1.raw")), false, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); @@ -78,7 +84,8 @@ public void testReadNextFrameCbemmEvoIccHc1() throws Exception { @Test public void testReadNextFrameCbetmEjp1() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("cbetm-ejp-option-1.raw")), false)) { + new FileInputStream(TestUtils.getTestFile("cbetm-ejp-option-1.raw")), false, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); @@ -104,7 +111,8 @@ public void testReadNextFrameCbetmEjp1() throws Exception { @Test public void testReadNextFrameCbemmEvoIccTempo1() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-tempo-option-1.raw")), false)) { + new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-tempo-option-1.raw")), false, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); @@ -133,7 +141,8 @@ public void testReadNextFrameCbemmEvoIccTempo1() throws Exception { @Test public void testReadNextFrameCbemmEvoIccBase1() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-base-option-1.raw")), false)) { + new FileInputStream(TestUtils.getTestFile("cbemm-evo-icc-base-option-1.raw")), false, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); assertEquals(FrameType.CBEMM_ICC_BASE, frame.getType()); @@ -151,7 +160,8 @@ public void testReadNextFrameCbemmEvoIccBase1() throws Exception { @Test public void testInvalidADPSgrouplineWithAutoRepairActivated() throws Exception { try (TeleinfoInputStream in = new TeleinfoInputStream( - new FileInputStream(TestUtils.getTestFile("invalid-adps-groupline.raw")), true)) { + new FileInputStream(TestUtils.getTestFile("invalid-adps-groupline.raw")), true, + TeleinfoTicMode.HISTORICAL)) { Frame frame = in.readNextFrame(); assertNotNull(frame); @@ -159,4 +169,60 @@ public void testInvalidADPSgrouplineWithAutoRepairActivated() throws Exception { assertEquals(37, frame.getAsInt(Label.ADPS)); } } + + @Test + public void testReadNextFrameLinkyTICModeStandardThreePhaseProd() throws Exception { + try (TeleinfoInputStream in = new TeleinfoInputStream( + new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-three-phase-prod.raw")), false, + TeleinfoTicMode.STANDARD, true)) { + Frame frame = in.readNextFrame(); + assertNotNull(frame); + assertEquals(FrameType.LSMT_PROD, frame.getType()); + assertEquals("123456789012", frame.get(Label.ADSC)); + assertEquals("02", frame.get(Label.VTIC)); + assertEquals("", frame.get(Label.DATE)); + assertEquals(" TEMPO ", frame.get(Label.NGTF)); + assertEquals(" HP BLEU ", frame.get(Label.LTARF)); + assertEquals(11604109, frame.getAsInt(Label.EAST)); + assertEquals(2741488, frame.getAsInt(Label.EASF01)); + assertEquals(18, frame.getAsInt(Label.PCOUP)); + assertEquals("2021-04-14T08:26:25", frame.getAsDateTime(Label.DATE)); + DateTimeType dateTime = DateTimeType.valueOf(frame.getAsDateTime(Label.DATE)); + assertEquals(2021, dateTime.getZonedDateTime().getYear()); + assertEquals(Month.APRIL, dateTime.getZonedDateTime().getMonth()); + assertEquals(14, dateTime.getZonedDateTime().getDayOfMonth()); + assertEquals(8, dateTime.getZonedDateTime().getHour()); + assertEquals(26, dateTime.getZonedDateTime().getMinute()); + assertEquals(25, dateTime.getZonedDateTime().getSecond()); + + assertNotEquals(TeleinfoBindingConstants.NOT_A_CHANNEL, Label.CCASN.getTimestampChannelName()); + assertEquals("2021-04-14T08:00:00", frame.getAsDateTime(Label.CCASN)); + dateTime = DateTimeType.valueOf(frame.getAsDateTime(Label.CCASN)); + assertEquals(2021, dateTime.getZonedDateTime().getYear()); + assertEquals(Month.APRIL, dateTime.getZonedDateTime().getMonth()); + assertEquals(14, dateTime.getZonedDateTime().getDayOfMonth()); + assertEquals(8, dateTime.getZonedDateTime().getHour()); + assertEquals(0, dateTime.getZonedDateTime().getMinute()); + assertEquals(0, dateTime.getZonedDateTime().getSecond()); + } + } + + @Test + public void testReadNextFrameLinkyTICModeStandardSinglePhaseProd() throws Exception { + try (TeleinfoInputStream in = new TeleinfoInputStream( + new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-single-phase-prod.raw")), + TeleinfoTicMode.STANDARD, true)) { + Frame frame = in.readNextFrame(); + assertNotNull(frame); + assertEquals(FrameType.LSMM_PROD, frame.getType()); + assertEquals("123456789012", frame.get(Label.ADSC)); + assertEquals("02", frame.get(Label.VTIC)); + assertEquals("", frame.get(Label.DATE)); + assertEquals("PRODUCTEUR", frame.get(Label.NGTF)); + assertEquals("INDEX NON CONSO ", frame.get(Label.LTARF)); + assertEquals(0, frame.getAsInt(Label.EAST)); + assertEquals(0, frame.getAsInt(Label.EASF01)); + assertEquals(32781, frame.getAsInt(Label.EAIT)); + } + } } diff --git a/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java new file mode 100644 index 0000000000000..057bc062b7f02 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/java/org/openhab/binding/teleinfo/internal/reader/io/serialport/FrameUtilTest.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.teleinfo.internal.reader.io.serialport; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.teleinfo.internal.reader.io.TeleinfoInputStream; +import org.openhab.binding.teleinfo.internal.serial.TeleinfoTicMode; +import org.openhab.binding.teleinfo.util.TestUtils; + +/** + * + * @author Olivier MARCEAU - Initial contribution + */ +@NonNullByDefault +public class FrameUtilTest { + + @Test + public void testComputeGroupLineChecksumThreePhaseProd() throws Exception { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( + new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-three-phase-prod.raw")))); + String groupLine; + int i = 0; + while ((groupLine = bufferedReader.readLine()) != null) { + if (i >= 1 && !TeleinfoInputStream.isHeaderFrame(groupLine)) { + char expected = groupLine.charAt(groupLine.length() - 1); + char actual = FrameUtil.computeGroupLineChecksum(groupLine.substring(0, groupLine.length() - 2), + TeleinfoTicMode.STANDARD); + assertEquals(expected, actual, i + " " + groupLine + " " + (int) expected + " " + (int) actual); + } + i++; + } + } + + @Test + public void testComputeGroupLineChecksumSinglePhaseProd() throws Exception { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( + new FileInputStream(TestUtils.getTestFile("linky-tic-mode-standard-single-phase-prod.raw")))); + String groupLine; + int i = 0; + while ((groupLine = bufferedReader.readLine()) != null) { + if (i >= 1 && !TeleinfoInputStream.isHeaderFrame(groupLine)) { + char expected = groupLine.charAt(groupLine.length() - 1); + char actual = FrameUtil.computeGroupLineChecksum(groupLine.substring(0, groupLine.length() - 2), + TeleinfoTicMode.STANDARD); + assertEquals(expected, actual, i + " " + groupLine + " " + (int) expected + " " + (int) actual); + } + i++; + } + } + + @Test + public void testComputeRelaisStates() { + assertArrayEquals(new boolean[] { true, false, false, false, false, false, false, false }, + FrameUtil.parseRelaisStates("001")); + assertArrayEquals(new boolean[] { false, false, true, true, false, false, false, true }, + FrameUtil.parseRelaisStates("140")); + } +} diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbemm-evo-icc-tempo-option-1.raw index e258d50e97c37afa110d8db309f91c740f855079..33fe7015dca6fad50cdf409bde301bef55a10439 100644 GIT binary patch delta 109 zcmX@hbehSH0SveT90LLr3=GUH3>5UaJUjwCoE01ubhv!|LtI=#97BLoAfVvH#mvOz b=;G|J5P<{~%qM!zWl~U>_{>iNhXO7DCBGTz delta 74 zcmX@jbe7480SveT90LLr3=GUH3>5TvxjZ}qJe(CA6?AyHeEmaQTtgf~fRZ4f;KV!8 VK#Y-hqTAewPyK+jffy4n7XUP}59t5^ diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw index 888d21217de8e..687acf0481001 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-base-option-1.raw @@ -14,6 +14,6 @@ IMAX3 027 ; PMAX 07990 ? PAPP 00540 * MOTDETAT 400000 F -PPOT 00 # +PPOT 00 #  ADCO XXXXXXXXXXXX 7 \ No newline at end of file diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw index 6ce7b6c901739..c080ed2ccb7b1 100644 --- a/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/cbetm-ejp-option-1.raw @@ -15,6 +15,6 @@ IMAX3 044 : PMAX 17480 : PAPP 05800 . MOTDETAT 000000 B -PPOT 00 # +PPOT 00 #  ADCO XXXXXXXXXX G \ No newline at end of file diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw new file mode 100644 index 0000000000000..f1057181c7905 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-single-phase-prod.raw @@ -0,0 +1,70 @@ +EP*PREF 03 B +PCOUP 03 \ +SINSTS 00000 F +SMAXSN E180716063417 00021 9 +SMAXSN-1 E180715064903 00023 Y +SINSTI 01258 L +SMAXIN E180716103316 01423 / +SMAXIN-1 E180715144229 01971 \ +CCASN E180716100000 00000 0 +CCASN-1 E180716090000 00000 V +UMOY1 E180716103000 230 + +STGE 002A0301 < +MSG1 PAS DE MESSAGE < +PRM 12345678901234 8 +RELAIS 000 B +NTARF 01 N +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE 9 + +ADSC 123456789012 = +VTIC 02 J +DATE E180716103423 B +NGTF PRODUCTEUR . +LTARF INDEX NON CONSO 0 +EAST 000000000 O +EASF01 000000000 " +EASF02 000000000 # +EASF03 000000000 $ +EASF04 000000000 % +EASF05 000000000 & +EASF06 000000000 ' +EASF07 000000000 ( +EASF08 000000000 ) +EASF09 000000000 * +EASF10 000000000 " +EASD01 000000000 +EASD02 000000000 ! +EASD03 000000000 " +EASD04 000000000 # +EAIT 000032781 Z +ERQ1 000000000 ; +ERQ2 000000890 M +ERQ3 000002546 N +ERQ4 000000000 > +IRMS1 005 3 +URMS1 228 F +PREF 03 B +PCOUP 03 \ +SINSTS 00000 F +SMAXSN E180716063417 00021 9 +SMAXSN-1 E180715064903 00023 Y +SINSTI 01253 G +SMAXIN E180716103316 01423 / +SMAXIN-1 E180715144229 01971 \ +CCASN E180716100000 00000 0 +CCASN-1 E180716090000 00000 V +UMOY1 E180716103000 230 + +STGE 002A0301 < +MSG1 PAS DE MESSAGE < +PRM 12345678901234 8 +RELAIS 000 B +NTARF 01 N +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00008001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE 9 + +ADSC 123456789012 = +VTIC 02 J +DATE E180716103424 C diff --git a/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw new file mode 100644 index 0000000000000..dc0225ac94057 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/test/resources/linky-tic-mode-standard-three-phase-prod.raw @@ -0,0 +1,171 @@ +774332 X +IRMS1 001 / +IRMS2 002 1 +IRMS3 001 1 +URMS1 234 C +URMS2 240 A +URMS3 242 D +PREF 18 H +PCOUP 18 " +SINSTS 00046 P +SINSTS1 00000 7 +SINSTS2 00531 A +SINSTS3 00000 9 +SMAXSN E210414070239 02636 < +SMAXSN1 E210414060632 00405 ! +SMAXSN2 E210414070239 02194 - +SMAXSN3 E210414054725 00565 0 +SMAXSN-1 E210413195606 06560 _ +SMAXSN1-1 E210413111148 01084 A +SMAXSN2-1 E210413195606 03275 Q +SMAXSN3-1 E210413195814 02904 Q +SINSTI 00000 < +SMAXIN E210414000000 00000 L +SMAXIN-1 E210413141848 03861 U +CCASN E210414080000 00806 : +CCASN-1 E210414073000 01152 U +CCAIN E210414080000 00000 " +CCAIN-1 E210414073000 00000 B +UMOY1 E210414082000 230 & +UMOY2 E210414082000 239 0 +UMOY3 E210414082000 243 , +STGE 013A0501 @ +MSG1 PAS DE MESSAGE < +PRM 12345678901234 8 +RELAIS 000 B +NTARF 02 O +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE . + +ADSC 123456789012 = +VTIC 02 J +DATE E210414082625 A +NGTF TEMPO F +LTARF HP BLEU + +EAST 011604109 % +EASF01 002741488 D +EASF02 005905500 ; +EASF03 000624053 8 +EASF04 001070566 > +EASF05 000524151 8 +EASF06 000738351 B +EASF07 000000000 ( +EASF08 000000000 ) +EASF09 000000000 * +EASF10 000000000 " +EASD01 011604109 6 +EASD02 000000000 ! +EASD03 000000000 " +EASD04 000000000 # +EAIT 000671631 ] +ERQ1 002970842 [ +ERQ2 000204084 N +ERQ3 000084948 ^ +ERQ4 000774332 X +IRMS1 001 / +IRMS2 002 1 +IRMS3 001 1 +URMS1 234 C +URMS2 240 A +URMS3 242 D +PREF 18 H +PCOUP 18 " +SINSTS 00013 J +SINSTS1 00000 7 +SINSTS2 00568 K +SINSTS3 00000 9 +SMAXSN E210414070239 02636 < +SMAXSN1 E210414060632 00405 ! +SMAXSN2 E210414070239 02194 - +SMAXSN3 E210414054725 00565 0 +SMAXSN-1 E210413195606 06560 _ +SMAXSN1-1 E210413111148 01084 A +SMAXSN2-1 E210413195606 03275 Q +SMAXSN3-1 E210413195814 02904 Q +SINSTI 00000 < +SMAXIN E210414000000 00000 L +SMAXIN-1 E210413141848 03861 U +CCASN E210414080000 00806 : +CCASN-1 E210414073000 01152 U +CCAIN E210414080000 00000 " +CCAIN-1 E210414073000 00000 B +UMOY1 E210414082000 230 & +UMOY2 E210414082000 239 0 +UMOY3 E210414082000 243 , +STGE 013A0501 @ +MSG1 PAS DE MESSAGE < +PRM 12345678901234 8 +RELAIS 000 B +NTARF 02 O +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE . + +ADSC 123456789012 = +VTIC 02 J +DATE E210414082627 C +NGTF TEMPO F +LTARF HP BLEU + +EAST 011604109 % +EASF01 002741488 D +EASF02 005905500 ; +EASF03 000624053 8 +EASF04 001070566 > +EASF05 000524151 8 +EASF06 000738351 B +EASF07 000000000 ( +EASF08 000000000 ) +EASF09 000000000 * +EASF10 000000000 " +EASD01 011604109 6 +EASD02 000000000 ! +EASD03 000000000 " +EASD04 000000000 # +EAIT 000671631 ] +ERQ1 002970842 [ +ERQ2 000204084 N +ERQ3 000084948 ^ +ERQ4 000774332 X +IRMS1 001 / +IRMS2 002 1 +IRMS3 001 1 +URMS1 234 C +URMS2 240 A +URMS3 242 D +PREF 18 H +PCOUP 18 " +SINSTS 00018 O +SINSTS1 00000 7 +SINSTS2 00565 H +SINSTS3 00000 9 +SMAXSN E210414070239 02636 < +SMAXSN1 E210414060632 00405 ! +SMAXSN2 E210414070239 02194 - +SMAXSN3 E210414054725 00565 0 +SMAXSN-1 E210413195606 06560 _ +SMAXSN1-1 E210413111148 01084 A +SMAXSN2-1 E210413195606 03275 Q +SMAXSN3-1 E210413195814 02904 Q +SINSTI 00000 < +SMAXIN E210414000000 00000 L +SMAXIN-1 E210413141848 03861 U +CCASN E210414080000 00806 : +CCASN-1 E210414073000 01152 U +CCAIN E210414080000 00000 " +CCAIN-1 E210414073000 00000 B +UMOY1 E210414082000 230 & +UMOY2 E210414082000 239 0 +UMOY3 E210414082000 243 , +STGE 013A0501 @ +MSG1 PAS DE MESSAGE < +PRM 12345678901234 8 +RELAIS 000 B +NTARF 02 O +NJOURF 00 & +NJOURF+1 00 B +PJOURF+1 00004001 06004002 22004001 NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE NONUTILE . + +ADSC 123456789012 = +VTIC 02 J +DATE E210414082629 E \ No newline at end of file From 5ac44dd7ef16198b6fd05efd002e2bee22eb98ae Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Sun, 12 Dec 2021 22:06:37 +0000 Subject: [PATCH 229/361] GraalJS now uses automation/js (#11719) * GraalJS now uses automation/js Signed-off-by: Jonathan Gilbert Signed-off-by: Michael Schmidt --- .../internal/GraalJSScriptEngineFactory.java | 19 ++++-- .../internal/OpenhabGraalJSScriptEngine.java | 11 ++-- .../fs/watch/JSDependencyTracker.java | 60 +++++++++++++++++ .../fs/watch/JSScriptFileWatcher.java | 65 +++++++++++++++++++ 4 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java index 14e9f783e8348..d6b98efeb7382 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java @@ -22,8 +22,6 @@ import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.osgi.service.component.annotations.Component; -import com.oracle.truffle.js.scriptengine.GraalJSEngineFactory; - /** * An implementation of {@link ScriptEngineFactory} with customizations for GraalJS ScriptEngines. * @@ -32,13 +30,24 @@ @Component(service = ScriptEngineFactory.class) public final class GraalJSScriptEngineFactory implements ScriptEngineFactory { + public static final String MIME_TYPE = "application/javascript;version=ECMAScript-2021"; + @Override public List getScriptTypes() { List scriptTypes = new ArrayList<>(); - GraalJSEngineFactory graalJSEngineFactory = new GraalJSEngineFactory(); - scriptTypes.addAll(graalJSEngineFactory.getMimeTypes()); - scriptTypes.addAll(graalJSEngineFactory.getExtensions()); + /* + * Whilst we run in parallel with Nashorn, we use a custom mime-type to avoid + * disrupting Nashorn scripts. When Nashorn is removed, we take over the standard + * JS runtime. + */ + + // GraalJSEngineFactory graalJSEngineFactory = new GraalJSEngineFactory(); + // + // scriptTypes.addAll(graalJSEngineFactory.getMimeTypes()); + // scriptTypes.addAll(graalJSEngineFactory.getExtensions()); + + scriptTypes.add(MIME_TYPE); return Collections.unmodifiableList(scriptTypes); } diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index 9f29b0d99d2c7..6621d5d1a1578 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -10,12 +10,10 @@ * * SPDX-License-Identifier: EPL-2.0 */ - package org.openhab.automation.jsscripting.internal; import static org.openhab.core.automation.module.script.ScriptEngineFactory.*; -import java.io.File; import java.io.IOException; import java.nio.channels.SeekableByteChannel; import java.nio.file.FileSystems; @@ -33,8 +31,8 @@ import org.graalvm.polyglot.Engine; import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; +import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable; -import org.openhab.core.OpenHAB; import org.openhab.core.automation.module.script.ScriptExtensionAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +49,6 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class); private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__"; - private static final String MODULE_DIR = String.join(File.separator, OpenHAB.getConfigFolder(), "automation", "lib", - "javascript", "personal"); // these fields start as null because they are populated on first use private @NonNullByDefault({}) String engineIdentifier; @@ -70,8 +66,9 @@ public OpenhabGraalJSScriptEngine() { Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false") .build(), Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true) - .option("js.commonjs-require-cwd", MODULE_DIR).option("js.nashorn-compat", "true") // to ease - // migration + .option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH) + .option("js.nashorn-compat", "true") // to ease + // migration .option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we // want ecma2021 .option("js.commonjs-require", "true") // enable CommonJS module support diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java new file mode 100644 index 0000000000000..aed75a0930696 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSDependencyTracker.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.fs.watch; + +import java.io.File; + +import org.openhab.core.OpenHAB; +import org.openhab.core.automation.module.script.rulesupport.loader.DependencyTracker; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tracks JS module dependencies + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true, service = JSDependencyTracker.class) +public class JSDependencyTracker extends DependencyTracker { + + private final Logger logger = LoggerFactory.getLogger(JSDependencyTracker.class); + + public static final String LIB_PATH = String.join(File.separator, OpenHAB.getConfigFolder(), "automation", "js", + "node_modules"); + + public JSDependencyTracker() { + super(LIB_PATH); + } + + @Activate + public void activate() { + File directory = new File(LIB_PATH); + if (!directory.exists()) { + if (!directory.mkdirs()) { + logger.warn("Failed to create watched directory: {}", LIB_PATH); + } + } else if (directory.isFile()) { + logger.warn("Trying to watch directory {}, however it is a file", LIB_PATH); + } + + super.activate(); + } + + @Deactivate + public void deactivate() { + super.deactivate(); + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java new file mode 100644 index 0000000000000..39dca7f3da661 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/watch/JSScriptFileWatcher.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.fs.watch; + +import java.io.File; +import java.util.Optional; + +import org.openhab.automation.jsscripting.internal.GraalJSScriptEngineFactory; +import org.openhab.core.automation.module.script.ScriptEngineManager; +import org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileReference; +import org.openhab.core.automation.module.script.rulesupport.loader.ScriptFileWatcher; +import org.openhab.core.service.ReadyService; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; + +/** + * Monitors /automation/js for Javascript files + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true) +public class JSScriptFileWatcher extends ScriptFileWatcher { + private static final String FILE_DIRECTORY = "automation" + File.separator + "js"; + + @Activate + public JSScriptFileWatcher(final @Reference ScriptEngineManager manager, final @Reference ReadyService readyService, + final @Reference JSDependencyTracker jsDependencyTracker) { + super(manager, jsDependencyTracker, readyService, FILE_DIRECTORY); + } + + @Activate + @Override + public void activate() { + super.activate(); + } + + @Deactivate + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + protected boolean createAndLoad(ScriptFileReference ref) { + return super.createAndLoad(new ScriptFileReference(ref.getScriptFileURL()) { + @Override + public Optional getScriptType() { + assert super.getScriptType().get().equalsIgnoreCase("js"); + return Optional.of(GraalJSScriptEngineFactory.MIME_TYPE); + } + }); + } +} From dac3358a2dd16a40fecac993019fab76e2b531a8 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Sun, 12 Dec 2021 23:13:13 -0800 Subject: [PATCH 230/361] [jsscripting] openhab-js integration (#11656) Fixes #11222 Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- .../pom.xml | 57 +++++ .../internal/GraalJSScriptEngineFactory.java | 28 ++- .../internal/OpenhabGraalJSScriptEngine.java | 71 +++++- .../fs/ReadOnlySeekableByteArrayChannel.java | 93 ++++++++ .../AbstractScriptExtensionProvider.java | 89 ++++++++ .../internal/scope/ClassExtender.java | 25 +++ .../jsscripting/internal/scope/Lifecycle.java | 64 ++++++ .../scope/OSGiScriptExtensionProvider.java | 40 ++++ .../internal/scope/ScriptDisposalAware.java | 32 +++ ...tDisposalAwareScriptExtensionProvider.java | 98 +++++++++ .../main/resources/OH-INF/config/config.xml | 20 ++ .../node_modules/@jsscripting-globals.js | 204 ++++++++++++++++++ 12 files changed, 811 insertions(+), 10 deletions(-) create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/ReadOnlySeekableByteArrayChannel.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/AbstractScriptExtensionProvider.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ClassExtender.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/Lifecycle.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/OSGiScriptExtensionProvider.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAware.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAwareScriptExtensionProvider.java create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/config/config.xml create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/resources/node_modules/@jsscripting-globals.js diff --git a/bundles/org.openhab.automation.jsscripting/pom.xml b/bundles/org.openhab.automation.jsscripting/pom.xml index 5a5ff68b054cc..dde3319bf46d7 100644 --- a/bundles/org.openhab.automation.jsscripting/pom.xml +++ b/bundles/org.openhab.automation.jsscripting/pom.xml @@ -25,6 +25,7 @@ 21.3.0 6.2.1 ${project.version} + openhab@0.0.1-beta.3
@@ -44,6 +45,62 @@ + + com.github.eirslett + frontend-maven-plugin + 1.12.0 + + v12.16.1 + target/js + + + + Install node and npm + + install-node-and-npm + + generate-sources + + + npm install + + npm + + + install ${ohjs.version} webpack webpack-cli + + + + npx webpack + + npx + + + webpack -c ./node_modules/openhab/webpack.config.js --entry ./node_modules/openhab/ -o ./dist + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + + add-resource + + generate-sources + + + + target/js/dist + node_modules + + + + + + diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java index d6b98efeb7382..4fa8ac8d98003 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java @@ -20,15 +20,26 @@ import javax.script.ScriptEngine; import org.openhab.core.automation.module.script.ScriptEngineFactory; +import org.openhab.core.config.core.ConfigurableService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Modified; /** * An implementation of {@link ScriptEngineFactory} with customizations for GraalJS ScriptEngines. * * @author Jonathan Gilbert - Initial contribution + * @author Dan Cunningham - Script injections */ -@Component(service = ScriptEngineFactory.class) +@Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.jsscripting", property = Constants.SERVICE_PID + + "=org.openhab.automation.jsscripting") +@ConfigurableService(category = "automation", label = "JS Scripting", description_uri = "automation:jsscripting") public final class GraalJSScriptEngineFactory implements ScriptEngineFactory { + private static final String CFG_INJECTION_ENABLED = "injectionEnabled"; + private static final String INJECTION_CODE = "Object.assign(this, require('openhab'));"; + private boolean injectionEnabled; public static final String MIME_TYPE = "application/javascript;version=ECMAScript-2021"; @@ -59,7 +70,18 @@ public void scopeValues(ScriptEngine scriptEngine, Map scopeValu @Override public ScriptEngine createScriptEngine(String scriptType) { - OpenhabGraalJSScriptEngine engine = new OpenhabGraalJSScriptEngine(); - return new DebuggingGraalScriptEngine<>(engine); + return new DebuggingGraalScriptEngine<>( + new OpenhabGraalJSScriptEngine(injectionEnabled ? INJECTION_CODE : null)); + } + + @Activate + protected void activate(BundleContext context, Map config) { + modified(config); + } + + @Modified + protected void modified(Map config) { + Object injectionEnabled = config.get(CFG_INJECTION_ENABLED); + this.injectionEnabled = injectionEnabled == null || (Boolean) injectionEnabled; } } diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index 6621d5d1a1578..f4939baa0f08b 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -15,22 +15,32 @@ import static org.openhab.core.automation.module.script.ScriptEngineFactory.*; import java.io.IOException; +import java.io.InputStream; import java.nio.channels.SeekableByteChannel; +import java.nio.file.AccessMode; import java.nio.file.FileSystems; +import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; import java.nio.file.OpenOption; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.FileAttribute; +import java.util.Collections; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import javax.script.ScriptContext; +import javax.script.ScriptException; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; +import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel; import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker; import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocable; import org.openhab.core.automation.module.script.ScriptExtensionAccessor; @@ -43,32 +53,36 @@ * GraalJS Script Engine implementation * * @author Jonathan Gilbert - Initial contribution + * @author Dan Cunningham - Script injections */ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngineWithInvocable { private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class); - + private static final String GLOBAL_REQUIRE = "require(\"@jsscripting-globals\");"; private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__"; + // final CommonJS search path for our library + private static final Path LOCAL_NODE_PATH = Paths.get("/node_modules"); // these fields start as null because they are populated on first use private @NonNullByDefault({}) String engineIdentifier; private @NonNullByDefault({}) Consumer scriptDependencyListener; private boolean initialized = false; + private String globalScript; /** * Creates an implementation of ScriptEngine (& Invocable), wrapping the contained engine, that tracks the script * lifecycle and provides hooks for scripts to do so too. */ - public OpenhabGraalJSScriptEngine() { + public OpenhabGraalJSScriptEngine(@Nullable String injectionCode) { super(null); // delegate depends on fields not yet initialised, so we cannot set it immediately + this.globalScript = GLOBAL_REQUIRE + (injectionCode != null ? injectionCode : ""); delegate = GraalJSScriptEngine.create( Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false") .build(), Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true) .option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH) - .option("js.nashorn-compat", "true") // to ease - // migration + .option("js.nashorn-compat", "true") // to ease migration .option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we // want ecma2021 .option("js.commonjs-require", "true") // enable CommonJS module support @@ -80,15 +94,52 @@ public SeekableByteChannel newByteChannel(Path path, Set o if (scriptDependencyListener != null) { scriptDependencyListener.accept(path.toString()); } - if (path.toString().endsWith(".js")) { + SeekableByteChannel sbc = null; + if (path.startsWith(LOCAL_NODE_PATH)) { + InputStream is = getClass().getResourceAsStream(path.toString()); + if (is == null) { + throw new IOException("Could not read " + path.toString()); + } + sbc = new ReadOnlySeekableByteArrayChannel(is.readAllBytes()); + } else { + sbc = super.newByteChannel(path, options, attrs); + } return new PrefixedSeekableByteChannel( - ("require=" + REQUIRE_WRAPPER_NAME + "(require);").getBytes(), - super.newByteChannel(path, options, attrs)); + ("require=" + REQUIRE_WRAPPER_NAME + "(require);").getBytes(), sbc); } else { return super.newByteChannel(path, options, attrs); } } + + @Override + public void checkAccess(Path path, Set modes, + LinkOption... linkOptions) throws IOException { + if (path.startsWith(LOCAL_NODE_PATH)) { + if (getClass().getResource(path.toString()) == null) { + throw new NoSuchFileException(path.toString()); + } + } else { + super.checkAccess(path, modes, linkOptions); + } + } + + @Override + public Map readAttributes(Path path, String attributes, + LinkOption... options) throws IOException { + if (path.startsWith(LOCAL_NODE_PATH)) { + return Collections.singletonMap("isRegularFile", true); + } + return super.readAttributes(path, attributes, options); + } + + @Override + public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException { + if (path.startsWith(LOCAL_NODE_PATH)) { + return path; + } + return super.toRealPath(path, linkOptions); + } })); } @@ -130,5 +181,11 @@ protected void beforeInvocation() { delegate.put("require", wrapRequireFn.apply((Function) delegate.get("require"))); initialized = true; + + try { + eval(globalScript); + } catch (ScriptException e) { + LOGGER.error("Could not inject global script", e); + } } } diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/ReadOnlySeekableByteArrayChannel.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/ReadOnlySeekableByteArrayChannel.java new file mode 100644 index 0000000000000..f150632f6a66c --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/fs/ReadOnlySeekableByteArrayChannel.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.automation.jsscripting.internal.fs; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SeekableByteChannel; + +/** + * Simple wrapper around a byte array to provide a SeekableByteChannel for consumption + * + * @author Dan Cunningham - Initial contribution + */ +public class ReadOnlySeekableByteArrayChannel implements SeekableByteChannel { + private byte[] data; + private int position; + private boolean closed; + + public ReadOnlySeekableByteArrayChannel(byte[] data) { + this.data = data; + } + + @Override + public long position() { + return position; + } + + @Override + public SeekableByteChannel position(long newPosition) throws IOException { + ensureOpen(); + position = (int) Math.max(0, Math.min(newPosition, size())); + return this; + } + + @Override + public long size() { + return data.length; + } + + @Override + public int read(ByteBuffer buf) throws IOException { + ensureOpen(); + int remaining = (int) size() - position; + if (remaining <= 0) { + return -1; + } + int readBytes = buf.remaining(); + if (readBytes > remaining) { + readBytes = remaining; + } + buf.put(data, position, readBytes); + position += readBytes; + return readBytes; + } + + @Override + public void close() { + closed = true; + } + + @Override + public boolean isOpen() { + return !closed; + } + + @Override + public int write(ByteBuffer b) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public SeekableByteChannel truncate(long newSize) { + throw new UnsupportedOperationException(); + } + + private void ensureOpen() throws ClosedChannelException { + if (!isOpen()) { + throw new ClosedChannelException(); + } + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/AbstractScriptExtensionProvider.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/AbstractScriptExtensionProvider.java new file mode 100644 index 0000000000000..0592076ff8f65 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/AbstractScriptExtensionProvider.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.automation.jsscripting.internal.scope; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.openhab.core.automation.module.script.ScriptExtensionProvider; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.annotations.Activate; + +/** + * Base class to offer support for script extension providers + * + * @author Jonathan Gilbert - Initial contribution + */ +public abstract class AbstractScriptExtensionProvider implements ScriptExtensionProvider { + private Map> types; + private Map> idToTypes = new ConcurrentHashMap<>(); + + protected abstract String getPresetName(); + + protected abstract void initializeTypes(final BundleContext context); + + protected void addType(String name, Function value) { + types.put(name, value); + } + + @Activate + public void activate(final BundleContext context) { + types = new HashMap<>(); + initializeTypes(context); + } + + @Override + public Collection getDefaultPresets() { + return Collections.emptyList(); + } + + @Override + public Collection getPresets() { + return Collections.singleton(getPresetName()); + } + + @Override + public Collection getTypes() { + return types.keySet(); + } + + @Override + public Object get(String scriptIdentifier, String type) throws IllegalArgumentException { + + Map forScript = idToTypes.computeIfAbsent(scriptIdentifier, k -> new HashMap<>()); + return forScript.computeIfAbsent(type, k -> types.get(k).apply(scriptIdentifier)); + } + + @Override + public Map importPreset(String scriptIdentifier, String preset) { + if (getPresetName().equals(preset)) { + Map results = new HashMap<>(types.size()); + for (String type : types.keySet()) { + results.put(type, get(scriptIdentifier, type)); + } + return results; + } + + return Collections.emptyMap(); + } + + @Override + public void unload(String scriptIdentifier) { + // ignore by default + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ClassExtender.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ClassExtender.java new file mode 100644 index 0000000000000..ee67607c894d1 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ClassExtender.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.scope; + +//import com.oracle.truffle.js.runtime.java.adapter.JavaAdapterFactory; + +/** + * Class utility to allow creation of 'extendable' classes with a classloader of the current bundle, rather than the + * classloader of the file being extended. + * + * @author Jonathan Gilbert - Initial contribution + */ +public class ClassExtender { + private ClassLoader classLoader = getClass().getClassLoader(); +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/Lifecycle.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/Lifecycle.java new file mode 100644 index 0000000000000..859029543832a --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/Lifecycle.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.scope; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Allows scripts to register for lifecycle events + * + * @author Jonathan Gilbert - Initial contribution + */ +public class Lifecycle implements ScriptDisposalAware { + private static final Logger logger = LoggerFactory.getLogger(Lifecycle.class); + public static final int DEFAULT_PRIORITY = 50; + private List listeners = new ArrayList<>(); + + public void addDisposeHook(Consumer listener, int priority) { + addListener(listener, priority); + } + + public void addDisposeHook(Consumer listener) { + addDisposeHook(listener, DEFAULT_PRIORITY); + } + + private void addListener(Consumer listener, int priority) { + listeners.add(new Hook(priority, listener)); + } + + @Override + public void unload(String scriptIdentifier) { + try { + listeners.stream().sorted(Comparator.comparingInt(h -> h.priority)) + .forEach(h -> h.fn.accept(scriptIdentifier)); + } catch (RuntimeException ex) { + logger.warn("Script unloading halted due to exception in disposal: {}: {}", ex.getClass(), ex.getMessage()); + } + } + + private static class Hook { + public Hook(int priority, Consumer fn) { + this.priority = priority; + this.fn = fn; + } + + int priority; + Consumer fn; + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/OSGiScriptExtensionProvider.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/OSGiScriptExtensionProvider.java new file mode 100644 index 0000000000000..5ec867ba70fd6 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/OSGiScriptExtensionProvider.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.automation.jsscripting.internal.scope; + +import org.openhab.core.automation.module.script.ScriptExtensionProvider; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.annotations.Component; + +/** + * ScriptExtensionProvider which provides various functions to help scripts to work with OSGi + * + * @author Jonathan Gilbert - Initial contribution + */ +@Component(immediate = true, service = ScriptExtensionProvider.class) +public class OSGiScriptExtensionProvider extends ScriptDisposalAwareScriptExtensionProvider { + + @Override + protected String getPresetName() { + return "osgi"; + } + + @Override + protected void initializeTypes(final BundleContext context) { + ClassExtender classExtender = new ClassExtender(); + + addType("bundleContext", k -> context); + addType("lifecycle", k -> new Lifecycle()); + addType("classutil", k -> classExtender); + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAware.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAware.java new file mode 100644 index 0000000000000..6c18c598cc0ba --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAware.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.automation.jsscripting.internal.scope; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Specifies that an object is aware of script disposal events + * + * @author Jonathan Gilbert - Initial contribution + */ +@NonNullByDefault +public interface ScriptDisposalAware { + + /** + * Indicates that the script has been disposed + * + * @param scriptIdentifier the identifier for the script + */ + void unload(String scriptIdentifier); +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAwareScriptExtensionProvider.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAwareScriptExtensionProvider.java new file mode 100644 index 0000000000000..29ac13a93f977 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/scope/ScriptDisposalAwareScriptExtensionProvider.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.automation.jsscripting.internal.scope; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.openhab.core.automation.module.script.ScriptExtensionProvider; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.annotations.Activate; + +/** + * Base class to offer support for script extension providers + * + * @author Jonathan Gilbert - Initial contribution + */ +public abstract class ScriptDisposalAwareScriptExtensionProvider + implements ScriptExtensionProvider, ScriptDisposalAware { + private Map> types; + private Map> idToTypes = new ConcurrentHashMap<>(); + + protected abstract String getPresetName(); + + protected abstract void initializeTypes(final BundleContext context); + + protected void addType(String name, Function value) { + types.put(name, value); + } + + @Activate + public void activate(final BundleContext context) { + types = new HashMap<>(); + initializeTypes(context); + } + + @Override + public Collection getDefaultPresets() { + return Collections.emptyList(); + } + + @Override + public Collection getPresets() { + return Collections.singleton(getPresetName()); + } + + @Override + public Collection getTypes() { + return types.keySet(); + } + + @Override + public Object get(String scriptIdentifier, String type) throws IllegalArgumentException { + + Map forScript = idToTypes.computeIfAbsent(scriptIdentifier, k -> new HashMap<>()); + return forScript.computeIfAbsent(type, k -> types.get(k).apply(scriptIdentifier)); + } + + @Override + public Map importPreset(String scriptIdentifier, String preset) { + if (getPresetName().equals(preset)) { + Map results = new HashMap<>(types.size()); + for (String type : types.keySet()) { + results.put(type, get(scriptIdentifier, type)); + } + return results; + } + + return Collections.emptyMap(); + } + + @Override + public void unload(String scriptIdentifier) { + Map forScript = idToTypes.remove(scriptIdentifier); + + if (forScript != null) { + for (Object o : forScript.values()) { + if (o instanceof ScriptDisposalAware) { + ((ScriptDisposalAware) o).unload(scriptIdentifier); + } + } + } + } +} diff --git a/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/config/config.xml new file mode 100644 index 0000000000000..3348680be3321 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/config/config.xml @@ -0,0 +1,20 @@ + + + + + + + If disabled, the OH scripting library can be imported manually using "require('openhab')" + ]]> + + + + + true + + + diff --git a/bundles/org.openhab.automation.jsscripting/src/main/resources/node_modules/@jsscripting-globals.js b/bundles/org.openhab.automation.jsscripting/src/main/resources/node_modules/@jsscripting-globals.js new file mode 100644 index 0000000000000..d60a905174028 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/resources/node_modules/@jsscripting-globals.js @@ -0,0 +1,204 @@ + +(function (global) { + 'use strict'; + + const System = Java.type('java.lang.System'); + const log = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.automation.script"); + const ScriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution'); + const ZonedDateTime = Java.type('java.time.ZonedDateTime'); + + const formatRegExp = /%[sdj%]/g; + + function stringify(value) { + try { + if (Java.isJavaObject(value)) { + return value.toString(); + } else { + // special cases + if (value === undefined) { + return "undefined" + } + if (typeof value === 'function') { + return "[Function]" + } + if (value instanceof RegExp) { + return value.toString(); + } + // fallback to JSON + return JSON.stringify(value, null, 2); + } + } catch (e) { + return '[Circular: ' + e + ']'; + } + } + + function format(f) { + if (typeof f !== 'string') { + var objects = []; + for (var index = 0; index < arguments.length; index++) { + objects.push(stringify(arguments[index])); + } + return objects.join(' '); + } + + if (arguments.length === 1) return f; + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function (x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + // falls through + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (x === null || (typeof x !== 'object' && typeof x !== 'symbol')) { + str += ' ' + x; + } else { + str += ' ' + stringify(x); + } + } + return str; + } + + const counters = {}; + const timers = {}; + + const console = { + 'assert': function (expression, message) { + if (!expression) { + log.error(message); + } + }, + + count: function (label) { + let counter; + + if (label) { + if (counters.hasOwnProperty(label)) { + counter = counters[label]; + } else { + counter = 0; + } + + // update + counters[label] = ++counter; + log.debug(format.apply(null, [label + ':', counter])); + } + }, + + debug: function () { + log.debug(format.apply(null, arguments)); + }, + + info: function () { + log.info(format.apply(null, arguments)); + }, + + log: function () { + log.info(format.apply(null, arguments)); + }, + + warn: function () { + log.warn(format.apply(null, arguments)); + }, + + error: function () { + log.error(format.apply(null, arguments)); + }, + + trace: function (e) { + if (Java.isJavaObject(e)) { + log.trace(e.getLocalizedMessage(), e); + } else { + if (e.stack) { + log.trace(e.stack); + } else { + if (e.message) { + log.trace(format.apply(null, [(e.name || 'Error') + ':', e.message])); + } else { + log.trace((e.name || 'Error')); + } + } + } + }, + + time: function (label) { + if (label) { + timers[label] = System.currentTimeMillis(); + } + }, + timeEnd: function (label) { + if (label) { + const now = System.currentTimeMillis(); + if (timers.hasOwnProperty(label)) { + log.info(format.apply(null, [label + ':', (now - timers[label]) + 'ms'])); + delete timers[label]; + } else { + log.info(format.apply(null, [label + ':', ''])); + } + } + } + }; + + function setTimeout(cb, delay) { + const args = Array.prototype.slice.call(arguments, 2); + return ScriptExecution.createTimerWithArgument( + ZonedDateTime.now().plusNanos(delay * 1000000), + args, + function (args) { + cb.apply(global, args); + } + ); + } + + function clearTimeout(timer) { + if (timer !== undefined && timer.isActive()) { + timer.cancel(); + } + } + + function setInterval(cb, delay) { + const args = Array.prototype.slice.call(arguments, 2); + const delayNanos = delay * 1000000 + let timer = ScriptExecution.createTimerWithArgument( + ZonedDateTime.now().plusNanos(delayNanos), + args, + function (args) { + cb.apply(global, args); + if (!timer.isCancelled()) { + timer.reschedule(ZonedDateTime.now().plusNanos(delayNanos)); + } + } + ); + return timer; + } + + function clearInterval(timer) { + clearTimeout(timer); + } + + //Polyfil common functions onto the global object + globalThis.console = console; + globalThis.setTimeout = setTimeout; + globalThis.clearTimeout = clearTimeout; + globalThis.setInterval = setInterval; + globalThis.clearInterval = clearInterval; + + //Support legacy NodeJS libraries + globalThis.global = globalThis; + globalThis.process = { env: { NODE_ENV: '' } }; + +})(this); From ea541127a7e08d0a8694c352f56b09bdebd142c3 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Mon, 13 Dec 2021 23:30:32 -0800 Subject: [PATCH 231/361] [jsscripting] Update library and change config PID (#11777) * Use OH standrard component pid naming, default injection to true. * Bump openhab-js Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- bundles/org.openhab.automation.jsscripting/pom.xml | 2 +- .../jsscripting/internal/GraalJSScriptEngineFactory.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.automation.jsscripting/pom.xml b/bundles/org.openhab.automation.jsscripting/pom.xml index dde3319bf46d7..aad7fb28b6fd9 100644 --- a/bundles/org.openhab.automation.jsscripting/pom.xml +++ b/bundles/org.openhab.automation.jsscripting/pom.xml @@ -25,7 +25,7 @@ 21.3.0 6.2.1 ${project.version} - openhab@0.0.1-beta.3 + openhab@1.2.0 diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java index 4fa8ac8d98003..e435da216dd8d 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/GraalJSScriptEngineFactory.java @@ -33,13 +33,13 @@ * @author Jonathan Gilbert - Initial contribution * @author Dan Cunningham - Script injections */ -@Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.automation.jsscripting", property = Constants.SERVICE_PID - + "=org.openhab.automation.jsscripting") +@Component(service = ScriptEngineFactory.class, configurationPid = "org.openhab.jsscripting", property = Constants.SERVICE_PID + + "=org.openhab.jsscripting") @ConfigurableService(category = "automation", label = "JS Scripting", description_uri = "automation:jsscripting") public final class GraalJSScriptEngineFactory implements ScriptEngineFactory { private static final String CFG_INJECTION_ENABLED = "injectionEnabled"; private static final String INJECTION_CODE = "Object.assign(this, require('openhab'));"; - private boolean injectionEnabled; + private boolean injectionEnabled = true; public static final String MIME_TYPE = "application/javascript;version=ECMAScript-2021"; From 440da8f3c99e4a0f75f0c30acb0167e993d2f21d Mon Sep 17 00:00:00 2001 From: jlaur Date: Tue, 14 Dec 2021 17:32:29 +0100 Subject: [PATCH 232/361] Reduce log level to TRACE for full request/response logging. (#11782) Fixes #11781 Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- .../binding/miele/internal/handler/MieleBridgeHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java index 47849b1f4c590..fd159a5756830 100644 --- a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java +++ b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java @@ -586,7 +586,7 @@ protected JsonElement invokeRPC(String methodName, Object[] args) { } if (responseData != null) { - logger.debug("The request '{}' yields '{}'", requestData, responseData); + logger.trace("The request '{}' yields '{}'", requestData, responseData); JsonObject resp = (JsonObject) JsonParser.parseReader(new StringReader(responseData)); result = resp.get("result"); From 8ad078c321d6ef941ae4c4720f30e7d61f8b1a35 Mon Sep 17 00:00:00 2001 From: Hans van den Bogert Date: Wed, 15 Dec 2021 09:20:21 +0100 Subject: [PATCH 233/361] [omnikinverter] feature: Add channels for voltage and current (#11645) Signed-off-by: Hans van den Bogert Signed-off-by: Michael Schmidt --- .../README.md | 47 ++++-- .../OmnikInverterBindingConstants.java | 11 ++ .../internal/OmnikInverterMessage.java | 158 ++++++++++++++++-- .../handler/OmnikInverterHandler.java | 36 +++- .../resources/OH-INF/thing/thing-types.xml | 65 ++++++- .../test/OmnikInverterMessageTest.java | 45 +++++ 6 files changed, 336 insertions(+), 26 deletions(-) diff --git a/bundles/org.openhab.binding.omnikinverter/README.md b/bundles/org.openhab.binding.omnikinverter/README.md index 1107246c0b8da..4b80806241059 100644 --- a/bundles/org.openhab.binding.omnikinverter/README.md +++ b/bundles/org.openhab.binding.omnikinverter/README.md @@ -21,11 +21,20 @@ No autodiscovery available ## Channels -| Channel Type Id | Item Type | Description | -| :---------------- | :---------- | :------------ | -| power | Number:Power | The instantaneous power generation | -| energyToday | Number:Energy | The amount of energy generated today | -| energyTotal | Number:Energy | The total amount of energy generated | +| Channel Type Id | Item Type | Description | +|:---------------|:--------------|:------------------------------------------------------------------------------------------------------------------| +| power | Number:Power | The instantaneous power generation for feed 1 to the grid, in Watt by default (**deprecated**; same as powerAC1) | +| powerAC1 | Number:Power | The instantaneous power generation for feed 1 to the grid, in Watt by default | +| powerAC2 | Number:Power | The instantaneous power generation for feed 2 to the grid, in Watt by default | +| powerAC3 | Number:Power | The instantaneous power generation for feed 3 to the grid, in Watt by default | +| currentPV1 | Number:Current | The current generation for input string 1, in ampere by default | +| currentPV2 | Number:Current | The current generation for input string 2, in ampere by default | +| currentPV3 | Number:Current | The current generation for input string 3, in ampere by default | +| voltagePV1 | Number:Voltage | The voltage on input string 1, in volt by default | +| voltagePV2 | Number:Voltage | The voltage on input string 2, in volt by default | +| voltagePV3 | Number:Voltage | The voltage on input string 3, in volt by default | +| energyToday | Number:Energy | The amount of energy generated today, in kWh by default | +| energyTotal | Number:Energy | The total amount of energy generated, in kWh by default | ## Full Example @@ -38,17 +47,35 @@ Thing omnikinverter:omnik:70ecb4f0 "Solar Inverter" [ hostname="igen-wifi.lan",s ### demo.items ``` -Number OmnikInverterBindingThing_InstantaneousPower "Solar Power" {channel="omnikinverter:omnik:70ecb4f0:power"} -Number OmnikInverterBindingThing_TotalGeneratedEnergyToday "Solar Energy Today" {channel="omnikinverter:omnik:70ecb4f0:energyToday"} -Number OmnikInverterBindingThing_TotalGeneratedEnergy "Solar Energy Total" {channel="omnikinverter:omnik:70ecb4f0:energyTotal"} +Number:Power OmnikInverterBindingThing_InstantaneousPower "Solar Power" {channel="omnikinverter:omnik:70ecb4f0:power"} +Number:Power OmnikInverterBindingThing_InstantaneousPower1 "Solar Power 1" {channel="omnikinverter:omnik:70ecb4f0:powerAC1"} +Number:Power OmnikInverterBindingThing_InstantaneousPower2 "Solar Power 2" {channel="omnikinverter:omnik:70ecb4f0:powerAC2"} +Number:Power OmnikInverterBindingThing_InstantaneousPower3 "Solar Power 3" {channel="omnikinverter:omnik:70ecb4f0:powerAC3"} +Number:Voltage OmnikInverterBindingThing_VoltagePV1 "PV Voltage 1" {channel="omnikinverter:omnik:70ecb4f0:voltagePV1"} +Number:Voltage OmnikInverterBindingThing_VoltagePV2 "PV Voltage 2" {channel="omnikinverter:omnik:70ecb4f0:voltagePV2"} +Number:Voltage OmnikInverterBindingThing_VoltagePV3 "PV Voltage 3" {channel="omnikinverter:omnik:70ecb4f0:voltagePV3"} +Number:Current OmnikInverterBindingThing_CurrentPV1 "PV current 1" {channel="omnikinverter:omnik:70ecb4f0:currentPV1"} +Number:Current OmnikInverterBindingThing_CurrentPV2 "PV current 2" {channel="omnikinverter:omnik:70ecb4f0:currentPV2"} +Number:Current OmnikInverterBindingThing_CurrentPV3 "PV current 3" {channel="omnikinverter:omnik:70ecb4f0:currentPV3"} +Number:Energy OmnikInverterBindingThing_TotalGeneratedEnergyToday "Solar Energy Today" {channel="omnikinverter:omnik:70ecb4f0:energyToday"} +Number:Energy OmnikInverterBindingThing_TotalGeneratedEnergy "Solar Energy Total" {channel="omnikinverter:omnik:70ecb4f0:energyTotal"} ``` ### Sitemap ``` Text item=OmnikInverterBindingThing_InstantaneousPower -Text item=OmnikInverterBindingThing_TotalGeneratedEnergyToday label="Today" -Text item=OmnikInverterBindingThing_TotalGeneratedEnergy label="Total" +Text item=OmnikInverterBindingThing_InstantaneousPower1 +Text item=OmnikInverterBindingThing_InstantaneousPower2 +Text item=OmnikInverterBindingThing_InstantaneousPower3 +Text item=OmnikInverterBindingThing_VoltagePV1 +Text item=OmnikInverterBindingThing_VoltagePV2 +Text item=OmnikInverterBindingThing_VoltagePV3 +Text item=OmnikInverterBindingThing_CurrentPV1 +Text item=OmnikInverterBindingThing_CurrentPV2 +Text item=OmnikInverterBindingThing_CurrentPV3 +Text item=OmnikInverterBindingThing_TotalGeneratedEnergyToday +Text item=OmnikInverterBindingThing_TotalGeneratedEnergy ``` ## References diff --git a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterBindingConstants.java b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterBindingConstants.java index 6716b0520a52c..b7d45d0636d6f 100644 --- a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterBindingConstants.java +++ b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterBindingConstants.java @@ -30,7 +30,18 @@ public class OmnikInverterBindingConstants { public static final ThingTypeUID THING_TYPE_OMNIK = new ThingTypeUID(BINDING_ID, "omnik"); // List of all Channel ids + public static final String CHANNEL_CURRENT_PV1 = "currentPV1"; + public static final String CHANNEL_CURRENT_PV2 = "currentPV2"; + public static final String CHANNEL_CURRENT_PV3 = "currentPV3"; + + public static final String CHANNEL_VOLTAGE_PV1 = "voltagePV1"; + public static final String CHANNEL_VOLTAGE_PV2 = "voltagePV2"; + public static final String CHANNEL_VOLTAGE_PV3 = "voltagePV3"; + public static final String CHANNEL_POWER = "power"; + public static final String CHANNEL_POWER_AC1 = "powerAC1"; + public static final String CHANNEL_POWER_AC2 = "powerAC2"; + public static final String CHANNEL_POWER_AC3 = "powerAC3"; public static final String CHANNEL_ENERGY_TODAY = "energyToday"; diff --git a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterMessage.java b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterMessage.java index 9d778314f7542..dd8cb41226e3e 100644 --- a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterMessage.java +++ b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/OmnikInverterMessage.java @@ -30,11 +30,153 @@ public OmnikInverterMessage(byte[] b) { this.bytes = b; } - public double getPower() { + private double getShort(int offset, int compensationFactor) { ByteBuffer buf = ByteBuffer.allocate(2); - buf.put(bytes, 59, 2); + buf.put(bytes, offset, 2); + buf.rewind(); + return (double) buf.getShort() / compensationFactor; + } + + private double getInt(int offset, int compensationFactor) { + ByteBuffer buf = ByteBuffer.allocate(4); + buf.put(bytes, offset, 4); buf.rewind(); - return buf.getShort(); + return (double) buf.getInt() / compensationFactor; + } + + /** + * @return the voltage for PV1 + */ + public double getVoltagePV1() { + return getShort(33, 10); + } + + /** + * @return the voltage for PV2 + */ + public double getVoltagePV2() { + return getShort(35, 10); + } + + /** + * @return the voltage for PV3 + */ + public double getVoltagePV3() { + return getShort(37, 10); + } + + /** + * @return the amperage for PV1 + */ + public double getCurrentPV1() { + return getShort(39, 10); + } + + /** + * @return the amperage for PV2 + */ + public double getCurrentPV2() { + return getShort(41, 10); + } + + /** + * @return the amperage for PV3 + */ + public double getCurrentPV3() { + return getShort(43, 10); + } + + /** + * @return the amperage for AC1 + */ + public double getAmperageAC1() { + return getShort(45, 10); + } + + /** + * @return the amperage for AC2 + */ + public double getAmperageAC2() { + return getShort(47, 10); + } + + /** + * @return the amperage for AC3 + */ + public double getAmperageAC3() { + return getShort(49, 10); + } + + /** + * @return the voltage for AC1 + */ + public double getVoltageAC1() { + return getShort(51, 10); + } + + /** + * @return the voltage for AC2 + */ + public double getVoltageAC2() { + return getShort(53, 10); + } + + /** + * @return the voltage for AC3 + */ + public double getVoltageAC3() { + return getShort(55, 10); + } + + /** + * @return the Frequency for AC1 + */ + public double getFrequencyAC1() { + return getShort(57, 100); + } + + /** + * @return the power for AC1 + * + * @deprecated + */ + public double getPower() { + return getShort(59, 1); + } + + /** + * @return the power for AC1 + */ + public double getPowerAC1() { + return getShort(59, 1); + } + + /** + * @return the Frequency for AC2 + */ + public double getFrequencyAC2() { + return getShort(61, 100); + } + + /** + * @return the power for AC2 + */ + public double getPowerAC2() { + return getShort(63, 1); + } + + /** + * @return the Frequency for AC3 + */ + public double getFrequencyAC3() { + return getShort(65, 100); + } + + /** + * @return the power for AC3 + */ + public double getPowerAC3() { + return getShort(67, 1); } /** @@ -42,10 +184,7 @@ public double getPower() { * @return the total energy outputted this day in kWh */ public double getEnergyToday() { - ByteBuffer buf = ByteBuffer.allocate(2); - buf.put(bytes, 69, 2); - buf.rewind(); - return (buf.getShort() / 100.0); + return getShort(69, 100); } /** @@ -53,9 +192,6 @@ public double getEnergyToday() { * @return the total energy outputted in kWh */ public double getTotalEnergy() { - ByteBuffer buf = ByteBuffer.allocate(4); - buf.put(bytes, 71, 4); - buf.rewind(); - return buf.getInt() / 10.0; + return getInt(71, 10); } } diff --git a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/handler/OmnikInverterHandler.java b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/handler/OmnikInverterHandler.java index d8d2a3110ba83..9fb37e0191b76 100644 --- a/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/handler/OmnikInverterHandler.java +++ b/bundles/org.openhab.binding.omnikinverter/src/main/java/org/openhab/binding/omnikinverter/internal/handler/OmnikInverterHandler.java @@ -19,6 +19,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import javax.measure.quantity.ElectricCurrent; +import javax.measure.quantity.ElectricPotential; import javax.measure.quantity.Power; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -58,10 +60,9 @@ public OmnikInverterHandler(Thing thing) { @Override public void handleCommand(ChannelUID channelUID, Command command) { - if (OmnikInverterBindingConstants.CHANNEL_POWER.equals(channelUID.getId())) { - if (command instanceof RefreshType) { - updateData(); - } + // All channels depend on data gotten from `updateData()` + if (command instanceof RefreshType) { + updateData(); } } @@ -94,6 +95,33 @@ private void updateData() { QuantityType powerQuantity = new QuantityType<>(message.getPower(), Units.WATT); updateState(OmnikInverterBindingConstants.CHANNEL_POWER, powerQuantity); + QuantityType powerQuantity1 = new QuantityType<>(message.getPowerAC1(), Units.WATT); + updateState(OmnikInverterBindingConstants.CHANNEL_POWER_AC1, powerQuantity1); + + QuantityType powerQuantity2 = new QuantityType<>(message.getPowerAC2(), Units.WATT); + updateState(OmnikInverterBindingConstants.CHANNEL_POWER_AC2, powerQuantity2); + + QuantityType powerQuantity3 = new QuantityType<>(message.getPowerAC3(), Units.WATT); + updateState(OmnikInverterBindingConstants.CHANNEL_POWER_AC3, powerQuantity3); + + QuantityType pvAmp1 = new QuantityType<>(message.getCurrentPV1(), Units.AMPERE); + updateState(OmnikInverterBindingConstants.CHANNEL_CURRENT_PV1, pvAmp1); + + QuantityType pvAmp2 = new QuantityType<>(message.getCurrentPV2(), Units.AMPERE); + updateState(OmnikInverterBindingConstants.CHANNEL_CURRENT_PV2, pvAmp2); + + QuantityType pvAmp3 = new QuantityType<>(message.getCurrentPV3(), Units.AMPERE); + updateState(OmnikInverterBindingConstants.CHANNEL_CURRENT_PV3, pvAmp3); + + QuantityType pvVoltage1 = new QuantityType<>(message.getVoltagePV1(), Units.VOLT); + updateState(OmnikInverterBindingConstants.CHANNEL_VOLTAGE_PV1, pvVoltage1); + + QuantityType pvVoltage2 = new QuantityType<>(message.getVoltagePV2(), Units.VOLT); + updateState(OmnikInverterBindingConstants.CHANNEL_VOLTAGE_PV2, pvVoltage2); + + QuantityType pvVoltage3 = new QuantityType<>(message.getVoltagePV3(), Units.VOLT); + updateState(OmnikInverterBindingConstants.CHANNEL_VOLTAGE_PV3, pvVoltage3); + updateState(OmnikInverterBindingConstants.CHANNEL_ENERGY_TODAY, new QuantityType<>(message.getEnergyToday(), Units.KILOWATT_HOUR)); diff --git a/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/thing/thing-types.xml index 12ec7a4de08bf..21de16074807c 100644 --- a/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/thing/thing-types.xml @@ -10,6 +10,15 @@ + + + + + + + + + @@ -36,7 +45,61 @@ Number:Power - The instantaneous power generation + The instantaneous power generation for output 1 + + + + Number:Power + + The instantaneous power generation for output 1 + + + + Number:Power + + The instantaneous power generation for output 2 + + + + Number:Power + + The instantaneous power generation for output 3 + + + + Number:Current + + The current on input string 1 + + + + Number:Current + + The current on input string 2 + + + + Number:Current + + The current on input string 3 + + + + Number:Voltage + + The voltage on input string 1 + + + + Number:Voltage + + The voltage on input string 2 + + + + Number:Voltage + + The voltage PV3 diff --git a/bundles/org.openhab.binding.omnikinverter/src/test/java/org/openhab/binding/omnikinverter/internal/test/OmnikInverterMessageTest.java b/bundles/org.openhab.binding.omnikinverter/src/test/java/org/openhab/binding/omnikinverter/internal/test/OmnikInverterMessageTest.java index 8ae385449b498..54d4a16541565 100644 --- a/bundles/org.openhab.binding.omnikinverter/src/test/java/org/openhab/binding/omnikinverter/internal/test/OmnikInverterMessageTest.java +++ b/bundles/org.openhab.binding.omnikinverter/src/test/java/org/openhab/binding/omnikinverter/internal/test/OmnikInverterMessageTest.java @@ -40,6 +40,51 @@ public void testGetPower() { assertEquals(137.0, message.getPower(), 0.01); } + @Test + public void testGetPowerAC1() { + assertEquals(137.0, message.getPowerAC1(), 0.01); + } + + @Test + public void testGetPowerAC2() { + assertEquals(-1.0, message.getPowerAC2(), 0.01); + } + + @Test + public void testGetPowerAC3() { + assertEquals(-1.0, message.getPowerAC3(), 0.01); + } + + @Test + public void testGetCurrentPV1() { + assertEquals(0.5, message.getCurrentPV1(), 0.01); + } + + @Test + public void testGetCurrentPV2() { + assertEquals(0.6, message.getCurrentPV2(), 0.01); + } + + @Test + public void testGetCurrentPV3() { + assertEquals(-0.1, message.getCurrentPV3(), 0.01); + } + + @Test + public void testGetVoltagePV1() { + assertEquals(160.0, message.getVoltagePV1(), 0.01); + } + + @Test + public void testGetVoltagePV2() { + assertEquals(131.9, message.getVoltagePV2(), 0.01); + } + + @Test + public void testGetVoltagePV3() { + assertEquals(-0.1, message.getVoltagePV3(), 0.01); + } + @Test public void testGetTotalEnergy() { assertEquals(12412.7, message.getTotalEnergy(), 0.01); From e37a1391012a8c51715ee23060f76a403073563e Mon Sep 17 00:00:00 2001 From: Matthew Skinner Date: Wed, 15 Dec 2021 21:30:21 +1100 Subject: [PATCH 234/361] Fix two events being logged when off. (#11786) Signed-off-by: Matthew Skinner Signed-off-by: Michael Schmidt --- .../java/org/openhab/binding/wled/internal/api/WledApiV084.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java index bd6d00ddef79c..2053928e67823 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java @@ -264,7 +264,6 @@ protected void processState() throws ApiException { } HSBType tempHSB = WLedHelper .parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[0].toString()); - handler.update(CHANNEL_MASTER_CONTROLS, tempHSB); handler.update(CHANNEL_PRIMARY_COLOR, tempHSB); handler.update(CHANNEL_SECONDARY_COLOR, WLedHelper.parseToHSBType(state.stateResponse.seg[handler.config.segmentIndex].col[1].toString())); @@ -283,6 +282,7 @@ protected void processState() throws ApiException { handler.update(CHANNEL_MASTER_CONTROLS, OnOffType.OFF); handler.update(CHANNEL_SEGMENT_BRIGHTNESS, OnOffType.OFF); } else { + handler.update(CHANNEL_MASTER_CONTROLS, tempHSB); handler.update(CHANNEL_SEGMENT_BRIGHTNESS, new PercentType(new BigDecimal(state.stateResponse.seg[handler.config.segmentIndex].bri) .divide(BIG_DECIMAL_2_55, RoundingMode.HALF_UP))); From 0ca49afabe1069866b99eae4a5db336efb0f4a2b Mon Sep 17 00:00:00 2001 From: lordjaxom Date: Wed, 15 Dec 2021 11:36:17 +0100 Subject: [PATCH 235/361] [wled] add configuration to sort state options of channels effects and palettes (#11785) Signed-off-by: Sascha Volkenandt Signed-off-by: Michael Schmidt --- .../binding/wled/internal/WLedConfiguration.java | 2 ++ .../openhab/binding/wled/internal/WLedHandler.java | 1 + .../binding/wled/internal/api/WledApiV084.java | 7 +++++++ .../src/main/resources/OH-INF/thing/thing-types.xml | 12 ++++++++++++ 4 files changed, 22 insertions(+) diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java index 04d8d7b855121..2721dc5dfc4d0 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedConfiguration.java @@ -25,4 +25,6 @@ public class WLedConfiguration { public int pollTime; public int segmentIndex; public int saturationThreshold; + public boolean sortEffects = false; + public boolean sortPalettes = false; } diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java index 7088441bcbc1d..9a77d7fddff01 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java @@ -305,6 +305,7 @@ public void dispose() { future.cancel(true); pollingFuture = null; } + api = null; // re-initialize api after configuration change } @Override diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java index 2053928e67823..4d3245af4cc36 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/api/WledApiV084.java @@ -17,6 +17,7 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -230,6 +231,9 @@ protected void getUpdatedFxList() { for (String value : state.jsonResponse.effects) { fxOptions.add(new StateOption(Integer.toString(counter++), value)); } + if (handler.config.sortEffects) { + fxOptions.sort(Comparator.comparing(o -> o.getValue().equals("0") ? "" : o.getLabel())); + } handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_FX), fxOptions); } @@ -240,6 +244,9 @@ protected void getUpdatedPaletteList() { for (String value : state.jsonResponse.palettes) { palleteOptions.add(new StateOption(Integer.toString(counter++), value)); } + if (handler.config.sortPalettes) { + palleteOptions.sort(Comparator.comparing(o -> o.getValue().equals("0") ? "" : o.getLabel())); + } handler.stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThing().getUID(), CHANNEL_PALETTES), palleteOptions); } diff --git a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml index 1d565066ff4d4..e97550b41db0f 100644 --- a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/thing/thing-types.xml @@ -57,6 +57,18 @@ 0 + + + If set, will sort the state options of the effects channel alphabetically while keeping the first + option (Solid) at the top. + false + + + + If set, will sort the state options of the palettes channel alphabetically while keeping the first + option (Default) at the top. + false + From 3b7bb2587f5fdc4157ceb32ea7139e80ffb184df Mon Sep 17 00:00:00 2001 From: jlaur Date: Wed, 15 Dec 2021 11:41:50 +0100 Subject: [PATCH 236/361] Fix deprecated channels on reinitialization. (#11779) Fixes #11778 Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- .../hdpowerview/internal/handler/HDPowerViewHubHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index 3b3579a363e7f..9a75c03f318d3 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -169,6 +169,7 @@ private void initializeChannels() { sceneCache.clear(); sceneCollectionCache.clear(); scheduledEventCache.clear(); + deprecatedChannelsCreated = false; } public @Nullable HDPowerViewWebTargets getWebTargets() { From bb215cc7fd690c85550ef7ae80d71871be97c90a Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Wed, 15 Dec 2021 13:53:29 +0100 Subject: [PATCH 237/361] [avmfritz] Fixed update of data for blinds (#11773) Signed-off-by: Christoph Weitkamp Signed-off-by: Michael Schmidt --- .../handler/AVMFritzBaseThingHandler.java | 21 ++--- .../dto/AVMFritzDeviceListModelTest.java | 93 ++++++++++++++++++- 2 files changed, 100 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java index c587b45ce4fa9..698f2a89de3ff 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java @@ -91,7 +91,7 @@ public abstract class AVMFritzBaseThingHandler extends BaseThingHandler implemen /** * keeps track of the current state for handling of increase/decrease */ - private @Nullable AVMFritzBaseModel state; + private AVMFritzBaseModel currentDevice = new DeviceModel(); private @Nullable String identifier; /** @@ -130,7 +130,7 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { } else { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Device not present"); } - state = device; + currentDevice = device; updateProperties(device, editProperties()); @@ -156,13 +156,12 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { } if (deviceModel.isHANFUNBlinds()) { updateLevelControl(deviceModel.getLevelControlModel()); - } - if (deviceModel.isColorLight()) { + } else if (deviceModel.isColorLight()) { updateColorLight(deviceModel.getColorControlModel(), deviceModel.getLevelControlModel()); } else if (deviceModel.isDimmableLight()) { updateDimmableLight(deviceModel.getLevelControlModel()); - } else if (device.isHANFUNUnit() && device.isHANFUNOnOff()) { - updateSimpleOnOffUnit(device.getSimpleOnOffUnit()); + } else if (deviceModel.isHANFUNUnit() && deviceModel.isHANFUNOnOff()) { + updateSimpleOnOffUnit(deviceModel.getSimpleOnOffUnit()); } } } @@ -438,7 +437,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { ((QuantityType) command).getUnit(), SIUnits.CELSIUS); } } else if (command instanceof IncreaseDecreaseType) { - temperature = state.getHkr().getTsoll(); + temperature = currentDevice.getHkr().getTsoll(); if (IncreaseDecreaseType.INCREASE.equals(command)) { temperature.add(BigDecimal.ONE); } else { @@ -449,7 +448,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } if (temperature != null) { fritzBox.setSetTemp(ain, fromCelsius(temperature)); - HeatingModel heatingModel = state.getHkr(); + HeatingModel heatingModel = currentDevice.getHkr(); heatingModel.setTsoll(temperature); updateState(CHANNEL_RADIATOR_MODE, new StringType(heatingModel.getRadiatorMode())); } @@ -465,10 +464,10 @@ public void handleCommand(ChannelUID channelUID, Command command) { targetTemperature = TEMP_FRITZ_OFF; break; case MODE_COMFORT: - targetTemperature = state.getHkr().getKomfort(); + targetTemperature = currentDevice.getHkr().getKomfort(); break; case MODE_ECO: - targetTemperature = state.getHkr().getAbsenk(); + targetTemperature = currentDevice.getHkr().getAbsenk(); break; case MODE_BOOST: targetTemperature = TEMP_FRITZ_MAX; @@ -480,7 +479,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } if (targetTemperature != null) { fritzBox.setSetTemp(ain, targetTemperature); - state.getHkr().setTsoll(targetTemperature); + currentDevice.getHkr().setTsoll(targetTemperature); updateState(CHANNEL_SETTEMP, new QuantityType<>(toCelsius(targetTemperature), SIUnits.CELSIUS)); } } diff --git a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java index aeb65d7b3ef21..87604e956d961 100644 --- a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java +++ b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java @@ -85,6 +85,30 @@ public void setUp() throws JAXBException, XMLStreamException { + " 262\n" + " 512\n" + " \n" + + "" + + "\n" + + " 0\n" + + " 0\n" + + " SmartHome LED-Lampe #1\n" + + " \n" + + " 0\n" + + " \n" + + " \n" + + " 26\n" + + " 10\n" + + " \n" + + " \n" + + " 254\n" + + " 100\n" + + " \n" + + " \n" + + " 2700\n" + + " \n" + + " \n" + + " 407\n" + + " 278\n" + + " 512,514,513\n" + + " \n" + "" + ""; //@formatter:on @@ -96,7 +120,7 @@ public void setUp() throws JAXBException, XMLStreamException { @Test public void validateDeviceListModel() { assertNotNull(devices); - assertEquals(16, devices.getDevicelist().size()); + assertEquals(17, devices.getDevicelist().size()); assertEquals("1", devices.getXmlApiVersion()); } @@ -611,15 +635,21 @@ public void validateHANFUNBlindModel() { assertEquals(1, device.getPresent()); assertEquals("Rollotron 1213 #1", device.getName()); - assertFalse(device.isButton()); + assertFalse(device.isHANFUNDevice()); assertFalse(device.isHANFUNButton()); assertTrue(device.isHANFUNAlarmSensor()); - assertFalse(device.isDectRepeater()); + assertFalse(device.isButton()); assertFalse(device.isSwitchableOutlet()); assertFalse(device.isTemperatureSensor()); assertFalse(device.isHumiditySensor()); assertFalse(device.isPowermeter()); + assertFalse(device.isDectRepeater()); assertFalse(device.isHeatingThermostat()); + assertFalse(device.hasMicrophone()); + assertTrue(device.isHANFUNUnit()); + assertTrue(device.isHANFUNOnOff()); + assertTrue(device.isDimmableLight()); + assertFalse(device.isColorLight()); assertTrue(device.isHANFUNBlinds()); assertTrue(device.getButtons().isEmpty()); @@ -641,6 +671,63 @@ public void validateHANFUNBlindModel() { assertEquals(BigDecimal.valueOf(10L), levelcontrol.getLevelPercentage()); } + @Test + public void validateHANFUNColorLightModel() { + Optional optionalDevice = findModelByIdentifier("127010027533-1"); + assertTrue(optionalDevice.isPresent()); + assertTrue(optionalDevice.get() instanceof DeviceModel); + + DeviceModel device = (DeviceModel) optionalDevice.get(); + assertEquals("HAN-FUN", device.getProductName()); + assertEquals("127010027533-1", device.getIdentifier()); + assertEquals("2002", device.getDeviceId()); + assertEquals("0.0", device.getFirmwareVersion()); + assertEquals("0x319d", device.getManufacturer()); + + assertEquals(0, device.getPresent()); + assertEquals("SmartHome LED-Lampe #1", device.getName()); + + assertFalse(device.isHANFUNDevice()); + assertFalse(device.isHANFUNButton()); + assertFalse(device.isHANFUNAlarmSensor()); + assertFalse(device.isButton()); + assertFalse(device.isSwitchableOutlet()); + assertFalse(device.isTemperatureSensor()); + assertFalse(device.isHumiditySensor()); + assertFalse(device.isPowermeter()); + assertFalse(device.isDectRepeater()); + assertFalse(device.isHeatingThermostat()); + assertFalse(device.hasMicrophone()); + assertTrue(device.isHANFUNUnit()); + assertTrue(device.isHANFUNOnOff()); + assertTrue(device.isDimmableLight()); + assertTrue(device.isColorLight()); + assertFalse(device.isHANFUNBlinds()); + + assertTrue(device.getButtons().isEmpty()); + + assertNull(device.getAlert()); + + assertNull(device.getSwitch()); + + assertNull(device.getTemperature()); + + assertNull(device.getPowermeter()); + + assertNull(device.getHkr()); + + LevelControlModel levelcontrol = device.getLevelControlModel(); + assertNotNull(levelcontrol); + assertEquals(BigDecimal.valueOf(26L), levelcontrol.getLevel()); + assertEquals(BigDecimal.valueOf(10L), levelcontrol.getLevelPercentage()); + + ColorControlModel colorModel = device.getColorControlModel(); + assertNotNull(colorModel); + assertEquals(254, colorModel.hue); + assertEquals(100, colorModel.saturation); + assertEquals(2700, colorModel.temperature); + } + @Test public void validateHANFUNOnOffModel() { Optional optionalDevice = findModelByIdentifier("113240824499-1"); From 04cb2e6d26db1095c43599730f19f40b2606a65c Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Wed, 15 Dec 2021 18:40:21 +0100 Subject: [PATCH 238/361] Add default translations for binding add-ons (#11760) * Add default translations for binding add-ons This makes the texts used by these add-ons translatable with Crowdin. To keep the PR simple, it only adds default translations for add-ons which do not yet have any default translations properties file. We can do follow up PRs for adding missing key/values to add-ons that already have these files or to remove duplications. There are several add-ons in this PR that do have non-English translation files, so I'll upload those to Crowdin when the PR is merged. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/adorne.properties | 21 + .../OH-INF/i18n/ahawastecollection.properties | 37 + .../resources/OH-INF/i18n/airq.properties | 111 + .../OH-INF/i18n/airvisualnode.properties | 43 + .../OH-INF/i18n/alarmdecoder.properties | 105 + .../resources/OH-INF/i18n/allplay.properties | 78 + .../OH-INF/i18n/amazonechocontrol.properties | 181 + .../resources/OH-INF/i18n/amplipi.properties | 45 + .../OH-INF/i18n/androiddebugbridge.properties | 349 + .../resources/OH-INF/i18n/anel.properties | 62 + .../resources/OH-INF/i18n/atlona.properties | 236 + .../resources/OH-INF/i18n/autelis.properties | 369 + .../OH-INF/i18n/benqprojector.properties | 83 + .../OH-INF/i18n/bigassfan.properties | 82 + .../OH-INF/i18n/bluetooth.properties | 27 + .../OH-INF/i18n/bmwconnecteddrive.properties | 253 + .../OH-INF/i18n/boschindego.properties | 58 + .../OH-INF/i18n/bosesoundtouch.properties | 183 + .../i18n/broadlinkthermostat.properties | 48 + .../resources/OH-INF/i18n/bsblan.properties | 53 + .../OH-INF/i18n/bticinosmarther.properties | 116 + .../OH-INF/i18n/buienradar.properties | 73 + .../resources/OH-INF/i18n/caddx.properties | 372 + .../resources/OH-INF/i18n/cbus.properties | 51 + .../resources/OH-INF/i18n/cm11a.properties | 31 + .../resources/OH-INF/i18n/comfoair.properties | 312 + .../OH-INF/i18n/coolmasternet.properties | 52 + .../OH-INF/i18n/coronastats.properties | 30 + .../resources/OH-INF/i18n/daikin.properties | 149 + .../resources/OH-INF/i18n/dali.properties | 32 + .../resources/OH-INF/i18n/dbquery.properties | 56 + .../OH-INF/i18n/denonmarantz.properties | 110 + .../OH-INF/i18n/deutschebahn.properties | 102 + .../resources/OH-INF/i18n/digiplex.properties | 139 + .../OH-INF/i18n/dlinksmarthome.properties | 18 + .../main/resources/OH-INF/i18n/dmx.properties | 116 + .../OH-INF/i18n/dominoswiss.properties | 41 + .../resources/OH-INF/i18n/doorbird.properties | 81 + .../OH-INF/i18n/draytonwiser.properties | 115 + .../resources/OH-INF/i18n/dscalarm.properties | 203 + .../OH-INF/i18n/dwdpollenflug.properties | 79 + .../OH-INF/i18n/dwdunwetter.properties | 55 + .../resources/OH-INF/i18n/ecobee.properties | 327 + .../resources/OH-INF/i18n/ecotouch.properties | 188 + .../i18n/elerotransmitterstick.properties | 27 + .../OH-INF/i18n/energenie.properties | 43 + .../OH-INF/i18n/epsonprojector.properties | 143 + .../OH-INF/i18n/etherrain.properties | 59 + .../resources/OH-INF/i18n/evohome.properties | 52 + .../resources/OH-INF/i18n/exec.properties | 35 + .../resources/OH-INF/i18n/feican.properties | 54 + .../OH-INF/i18n/fmiweather.properties | 267 + .../OH-INF/i18n/folderwatcher.properties | 52 + .../resources/OH-INF/i18n/folding.properties | 34 + .../resources/OH-INF/i18n/foobot.properties | 41 + .../resources/OH-INF/i18n/freebox.properties | 151 + .../resources/OH-INF/i18n/fronius.properties | 89 + .../OH-INF/i18n/fsinternetradio.properties | 39 + .../OH-INF/i18n/ftpupload.properties | 38 + .../resources/OH-INF/i18n/gardena.properties | 264 + .../OH-INF/i18n/generacmobilelink.properties | 39 + .../OH-INF/i18n/globalcache.properties | 159 + .../OH-INF/i18n/goecharger.properties | 73 + .../resources/OH-INF/i18n/gpio.properties | 39 + .../OH-INF/i18n/gpstracker.properties | 37 + .../OH-INF/i18n/groheondus.properties | 58 + .../i18n/haassohnpelletstove.properties | 41 + .../OH-INF/i18n/harmonyhub.properties | 39 + .../OH-INF/i18n/haywardomnilogic.properties | 150 + .../i18n/hccrubbishcollection.properties | 39 + .../OH-INF/i18n/hdanywhere.properties | 31 + .../resources/OH-INF/i18n/helios.properties | 93 + .../OH-INF/i18n/heliosventilation.properties | 62 + .../resources/OH-INF/i18n/heos.properties | 60 + .../OH-INF/i18n/homeconnect.properties | 287 + .../OH-INF/i18n/homematic.properties | 56 + .../OH-INF/i18n/homewizard.properties | 39 + .../OH-INF/i18n/hpprinter.properties | 60 + .../resources/OH-INF/i18n/http.properties | 240 + .../OH-INF/i18n/hydrawise.properties | 270 + .../resources/OH-INF/i18n/hyperion.properties | 63 + .../resources/OH-INF/i18n/iammeter.properties | 60 + .../OH-INF/i18n/iaqualink.properties | 165 + .../main/resources/OH-INF/i18n/ihc.properties | 138 + .../OH-INF/i18n/innogysmarthome.properties | 157 + .../resources/OH-INF/i18n/insteon.properties | 177 + .../resources/OH-INF/i18n/ipcamera.properties | 694 ++ .../OH-INF/i18n/ipobserver.properties | 57 + .../main/resources/OH-INF/i18n/ipp.properties | 27 + .../resources/OH-INF/i18n/irobot.properties | 154 + .../resources/OH-INF/i18n/irtrans.properties | 54 + .../resources/OH-INF/i18n/ism8.properties | 60 + .../OH-INF/i18n/jablotron.properties | 106 + .../OH-INF/i18n/kaleidescape.properties | 206 + .../resources/OH-INF/i18n/keba.properties | 90 + .../resources/OH-INF/i18n/km200.properties | 46 + .../main/resources/OH-INF/i18n/knx.properties | 134 + .../OH-INF/i18n/konnected.properties | 100 + .../OH-INF/i18n/kostalinverter.properties | 338 + .../main/resources/OH-INF/i18n/kvv.properties | 36 + .../main/resources/OH-INF/i18n/lcn.properties | 224 + .../OH-INF/i18n/leapmotion.properties | 14 + .../OH-INF/i18n/lgtvserial.properties | 563 ++ .../OH-INF/i18n/linuxinput.properties | 26 + .../resources/OH-INF/i18n/lirc.properties | 27 + .../resources/OH-INF/i18n/loxone.properties | 116 + .../OH-INF/i18n/luftdateninfo.properties | 47 + .../resources/OH-INF/i18n/lutron.properties | 500 ++ .../OH-INF/i18n/magentatv.properties | 118 + .../resources/OH-INF/i18n/mcp23017.properties | 48 + .../resources/OH-INF/i18n/mecmeter.properties | 152 + .../resources/OH-INF/i18n/melcloud.properties | 118 + .../OH-INF/i18n/meteostick.properties | 65 + .../resources/OH-INF/i18n/mihome.properties | 156 + .../resources/OH-INF/i18n/mikrotik.properties | 111 + .../resources/OH-INF/i18n/milight.properties | 102 + .../resources/OH-INF/i18n/millheat.properties | 66 + .../OH-INF/i18n/minecraft.properties | 57 + .../OH-INF/i18n/modbus-sbc.properties | 2 + .../OH-INF/i18n/stiebeleltron.properties | 4 + .../resources/OH-INF/i18n/sunspec.properties | 8 + .../resources/OH-INF/i18n/modbus.properties | 184 + .../OH-INF/i18n/monopriceaudio.properties | 106 + .../main/resources/OH-INF/i18n/mpd.properties | 33 + .../resources/OH-INF/i18n/mqtt.properties | 32 + .../resources/OH-INF/i18n/mqtt.properties | 8 + .../resources/OH-INF/i18n/mqtt.properties | 18 + .../main/resources/OH-INF/i18n/myq.properties | 42 + .../resources/OH-INF/i18n/mystrom.properties | 36 + .../resources/OH-INF/i18n/neato.properties | 89 + .../resources/OH-INF/i18n/neeo.properties | 68 + .../resources/OH-INF/i18n/neohub.properties | 84 + .../resources/OH-INF/i18n/nest.properties | 310 + .../resources/OH-INF/i18n/network.properties | 84 + .../OH-INF/i18n/networkupstools.properties | 107 + .../OH-INF/i18n/nibeheatpump.properties | 7426 +++++++++++++++++ .../OH-INF/i18n/nibeuplink.properties | 469 ++ .../resources/OH-INF/i18n/nikobus.properties | 90 + .../OH-INF/i18n/novafinedust.properties | 29 + .../resources/OH-INF/i18n/nuki.properties | 92 + .../resources/OH-INF/i18n/nuvo.properties | 142 + .../OH-INF/i18n/nzwateralerts.properties | 45 + .../resources/OH-INF/i18n/oceanic.properties | 60 + .../OH-INF/i18n/ojelectronics.properties | 55 + .../OH-INF/i18n/omnikinverter.properties | 27 + .../resources/OH-INF/i18n/omnilink.properties | 308 + .../OH-INF/i18n/onebusaway.properties | 45 + .../resources/OH-INF/i18n/onewire.properties | 185 + .../OH-INF/i18n/onewiregpio.properties | 23 + .../resources/OH-INF/i18n/onkyo.properties | 230 + .../OH-INF/i18n/opengarage.properties | 51 + .../OH-INF/i18n/opensprinkler.properties | 63 + .../OH-INF/i18n/openthermgateway.properties | 119 + .../resources/OH-INF/i18n/oppo.properties | 165 + .../OH-INF/i18n/orbitbhyve.properties | 43 + .../resources/OH-INF/i18n/orvibo.properties | 19 + .../OH-INF/i18n/paradoxalarm.properties | 117 + .../resources/OH-INF/i18n/pentair.properties | 81 + .../main/resources/OH-INF/i18n/phc.properties | 68 + .../resources/OH-INF/i18n/pilight.properties | 42 + .../OH-INF/i18n/pioneeravr.properties | 678 ++ .../OH-INF/i18n/pjLinkDevice.properties | 55 + .../resources/OH-INF/i18n/plclogo.properties | 77 + .../OH-INF/i18n/plugwiseha.properties | 94 + .../OH-INF/i18n/pulseaudio.properties | 73 + .../resources/OH-INF/i18n/qbus.properties | 72 + .../OH-INF/i18n/radiothermostat.properties | 78 + .../OH-INF/i18n/regoheatpump.properties | 191 + .../resources/OH-INF/i18n/renault.properties | 57 + .../resources/OH-INF/i18n/resol.properties | 90 + .../resources/OH-INF/i18n/revogi.properties | 40 + .../main/resources/OH-INF/i18n/rme.properties | 38 + .../resources/OH-INF/i18n/robonect.properties | 95 + .../resources/OH-INF/i18n/roku.properties | 93 + .../resources/OH-INF/i18n/russound.properties | 170 + .../OH-INF/i18n/samsungtv.properties | 309 + .../OH-INF/i18n/semsportal.properties | 37 + .../OH-INF/i18n/senechome.properties | 99 + .../resources/OH-INF/i18n/seneye.properties | 51 + .../resources/OH-INF/i18n/sensebox.properties | 50 + .../resources/OH-INF/i18n/sensibo.properties | 27 + .../resources/OH-INF/i18n/serial.properties | 112 + .../OH-INF/i18n/serialbutton.properties | 14 + .../OH-INF/i18n/siemensrds.properties | 69 + .../i18n/silvercrestwifisocket.properties | 27 + .../OH-INF/i18n/smaenergymeter.properties | 36 + .../OH-INF/i18n/smartmeter.properties | 24 + .../resources/OH-INF/i18n/smhi.properties | 217 + .../resources/OH-INF/i18n/snmp.properties | 101 + .../OH-INF/i18n/solaredge.properties | 131 + .../resources/OH-INF/i18n/solarlog.properties | 53 + .../OH-INF/i18n/solarwatt.properties | 34 + .../OH-INF/i18n/somfymylink.properties | 33 + .../OH-INF/i18n/somfytahoma.properties | 226 + .../OH-INF/i18n/sonyaudio.properties | 194 + .../resources/OH-INF/i18n/souliss.properties | 327 + .../OH-INF/i18n/squeezebox.properties | 113 + .../OH-INF/i18n/systeminfo.properties | 151 + .../resources/OH-INF/i18n/tacmi.properties | 93 + .../resources/OH-INF/i18n/tado.properties | 80 + .../OH-INF/i18n/tankerkoenig.properties | 35 + .../OH-INF/i18n/tapocontrol.properties | 75 + .../resources/OH-INF/i18n/telegram.properties | 56 + .../resources/OH-INF/i18n/teleinfo.properties | 151 + .../OH-INF/i18n/tellstick.properties | 107 + .../resources/OH-INF/i18n/tesla.properties | 273 + .../resources/OH-INF/i18n/tibber.properties | 41 + .../resources/OH-INF/i18n/tivo.properties | 102 + .../OH-INF/i18n/touchwand.properties | 68 + .../OH-INF/i18n/tplinksmarthome.properties | 144 + .../resources/OH-INF/i18n/unifi.properties | 57 + .../OH-INF/i18n/unifiedremote.properties | 56 + .../main/resources/OH-INF/i18n/upb.properties | 48 + .../OH-INF/i18n/upnpcontrol.properties | 102 + .../resources/OH-INF/i18n/valloxmv.properties | 103 + .../main/resources/OH-INF/i18n/vdr.properties | 109 + .../resources/OH-INF/i18n/vektiva.properties | 25 + .../resources/OH-INF/i18n/velbus.properties | 545 ++ .../OH-INF/i18n/venstarthermostat.properties | 96 + .../resources/OH-INF/i18n/ventaair.properties | 84 + .../resources/OH-INF/i18n/verisure.properties | 167 + .../OH-INF/i18n/vitotronic.properties | 161 + .../resources/OH-INF/i18n/warmup.properties | 46 + .../resources/OH-INF/i18n/webthing.properties | 29 + .../resources/OH-INF/i18n/wemo.properties | 126 + .../resources/OH-INF/i18n/wifiled.properties | 62 + .../OH-INF/i18n/wlanthermo.properties | 212 + .../resources/OH-INF/i18n/wled.properties | 92 + .../OH-INF/i18n/wolfsmartset.properties | 37 + .../OH-INF/i18n/xmppclient.properties | 34 + .../OH-INF/i18n/yamahareceiver.properties | 181 + .../resources/OH-INF/i18n/yeelight.properties | 45 + .../OH-INF/i18n/yioremote.properties | 30 + .../OH-INF/i18n/zoneminder.properties | 113 + 234 files changed, 33234 insertions(+) create mode 100644 bundles/org.openhab.binding.adorne/src/main/resources/OH-INF/i18n/adorne.properties create mode 100644 bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/i18n/ahawastecollection.properties create mode 100644 bundles/org.openhab.binding.airq/src/main/resources/OH-INF/i18n/airq.properties create mode 100644 bundles/org.openhab.binding.airvisualnode/src/main/resources/OH-INF/i18n/airvisualnode.properties create mode 100644 bundles/org.openhab.binding.alarmdecoder/src/main/resources/OH-INF/i18n/alarmdecoder.properties create mode 100644 bundles/org.openhab.binding.allplay/src/main/resources/OH-INF/i18n/allplay.properties create mode 100644 bundles/org.openhab.binding.amazonechocontrol/src/main/resources/OH-INF/i18n/amazonechocontrol.properties create mode 100644 bundles/org.openhab.binding.amplipi/src/main/resources/OH-INF/i18n/amplipi.properties create mode 100644 bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties create mode 100644 bundles/org.openhab.binding.anel/src/main/resources/OH-INF/i18n/anel.properties create mode 100644 bundles/org.openhab.binding.atlona/src/main/resources/OH-INF/i18n/atlona.properties create mode 100644 bundles/org.openhab.binding.autelis/src/main/resources/OH-INF/i18n/autelis.properties create mode 100644 bundles/org.openhab.binding.benqprojector/src/main/resources/OH-INF/i18n/benqprojector.properties create mode 100644 bundles/org.openhab.binding.bigassfan/src/main/resources/OH-INF/i18n/bigassfan.properties create mode 100644 bundles/org.openhab.binding.bluetooth/src/main/resources/OH-INF/i18n/bluetooth.properties create mode 100644 bundles/org.openhab.binding.bmwconnecteddrive/src/main/resources/OH-INF/i18n/bmwconnecteddrive.properties create mode 100644 bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/i18n/boschindego.properties create mode 100644 bundles/org.openhab.binding.bosesoundtouch/src/main/resources/OH-INF/i18n/bosesoundtouch.properties create mode 100644 bundles/org.openhab.binding.broadlinkthermostat/src/main/resources/OH-INF/i18n/broadlinkthermostat.properties create mode 100644 bundles/org.openhab.binding.bsblan/src/main/resources/OH-INF/i18n/bsblan.properties create mode 100644 bundles/org.openhab.binding.bticinosmarther/src/main/resources/OH-INF/i18n/bticinosmarther.properties create mode 100644 bundles/org.openhab.binding.buienradar/src/main/resources/OH-INF/i18n/buienradar.properties create mode 100644 bundles/org.openhab.binding.caddx/src/main/resources/OH-INF/i18n/caddx.properties create mode 100644 bundles/org.openhab.binding.cbus/src/main/resources/OH-INF/i18n/cbus.properties create mode 100644 bundles/org.openhab.binding.cm11a/src/main/resources/OH-INF/i18n/cm11a.properties create mode 100644 bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/i18n/comfoair.properties create mode 100644 bundles/org.openhab.binding.coolmasternet/src/main/resources/OH-INF/i18n/coolmasternet.properties create mode 100644 bundles/org.openhab.binding.coronastats/src/main/resources/OH-INF/i18n/coronastats.properties create mode 100644 bundles/org.openhab.binding.daikin/src/main/resources/OH-INF/i18n/daikin.properties create mode 100644 bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties create mode 100644 bundles/org.openhab.binding.dbquery/src/main/resources/OH-INF/i18n/dbquery.properties create mode 100644 bundles/org.openhab.binding.denonmarantz/src/main/resources/OH-INF/i18n/denonmarantz.properties create mode 100644 bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn.properties create mode 100644 bundles/org.openhab.binding.digiplex/src/main/resources/OH-INF/i18n/digiplex.properties create mode 100644 bundles/org.openhab.binding.dlinksmarthome/src/main/resources/OH-INF/i18n/dlinksmarthome.properties create mode 100644 bundles/org.openhab.binding.dmx/src/main/resources/OH-INF/i18n/dmx.properties create mode 100644 bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss.properties create mode 100644 bundles/org.openhab.binding.doorbird/src/main/resources/OH-INF/i18n/doorbird.properties create mode 100644 bundles/org.openhab.binding.draytonwiser/src/main/resources/OH-INF/i18n/draytonwiser.properties create mode 100644 bundles/org.openhab.binding.dscalarm/src/main/resources/OH-INF/i18n/dscalarm.properties create mode 100644 bundles/org.openhab.binding.dwdpollenflug/src/main/resources/OH-INF/i18n/dwdpollenflug.properties create mode 100644 bundles/org.openhab.binding.dwdunwetter/src/main/resources/OH-INF/i18n/dwdunwetter.properties create mode 100644 bundles/org.openhab.binding.ecobee/src/main/resources/OH-INF/i18n/ecobee.properties create mode 100644 bundles/org.openhab.binding.ecotouch/src/main/resources/OH-INF/i18n/ecotouch.properties create mode 100644 bundles/org.openhab.binding.elerotransmitterstick/src/main/resources/OH-INF/i18n/elerotransmitterstick.properties create mode 100644 bundles/org.openhab.binding.energenie/src/main/resources/OH-INF/i18n/energenie.properties create mode 100644 bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/i18n/epsonprojector.properties create mode 100644 bundles/org.openhab.binding.etherrain/src/main/resources/OH-INF/i18n/etherrain.properties create mode 100644 bundles/org.openhab.binding.evohome/src/main/resources/OH-INF/i18n/evohome.properties create mode 100644 bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec.properties create mode 100644 bundles/org.openhab.binding.feican/src/main/resources/OH-INF/i18n/feican.properties create mode 100644 bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties create mode 100644 bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/i18n/folderwatcher.properties create mode 100644 bundles/org.openhab.binding.folding/src/main/resources/OH-INF/i18n/folding.properties create mode 100644 bundles/org.openhab.binding.foobot/src/main/resources/OH-INF/i18n/foobot.properties create mode 100644 bundles/org.openhab.binding.freebox/src/main/resources/OH-INF/i18n/freebox.properties create mode 100644 bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/i18n/fronius.properties create mode 100644 bundles/org.openhab.binding.fsinternetradio/src/main/resources/OH-INF/i18n/fsinternetradio.properties create mode 100644 bundles/org.openhab.binding.ftpupload/src/main/resources/OH-INF/i18n/ftpupload.properties create mode 100644 bundles/org.openhab.binding.gardena/src/main/resources/OH-INF/i18n/gardena.properties create mode 100644 bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/i18n/generacmobilelink.properties create mode 100644 bundles/org.openhab.binding.globalcache/src/main/resources/OH-INF/i18n/globalcache.properties create mode 100644 bundles/org.openhab.binding.goecharger/src/main/resources/OH-INF/i18n/goecharger.properties create mode 100644 bundles/org.openhab.binding.gpio/src/main/resources/OH-INF/i18n/gpio.properties create mode 100644 bundles/org.openhab.binding.gpstracker/src/main/resources/OH-INF/i18n/gpstracker.properties create mode 100644 bundles/org.openhab.binding.groheondus/src/main/resources/OH-INF/i18n/groheondus.properties create mode 100644 bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/i18n/haassohnpelletstove.properties create mode 100644 bundles/org.openhab.binding.harmonyhub/src/main/resources/OH-INF/i18n/harmonyhub.properties create mode 100644 bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/i18n/haywardomnilogic.properties create mode 100644 bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/i18n/hccrubbishcollection.properties create mode 100644 bundles/org.openhab.binding.hdanywhere/src/main/resources/OH-INF/i18n/hdanywhere.properties create mode 100644 bundles/org.openhab.binding.helios/src/main/resources/OH-INF/i18n/helios.properties create mode 100644 bundles/org.openhab.binding.heliosventilation/src/main/resources/OH-INF/i18n/heliosventilation.properties create mode 100644 bundles/org.openhab.binding.heos/src/main/resources/OH-INF/i18n/heos.properties create mode 100644 bundles/org.openhab.binding.homeconnect/src/main/resources/OH-INF/i18n/homeconnect.properties create mode 100644 bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/i18n/homematic.properties create mode 100644 bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties create mode 100644 bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/i18n/hpprinter.properties create mode 100644 bundles/org.openhab.binding.http/src/main/resources/OH-INF/i18n/http.properties create mode 100644 bundles/org.openhab.binding.hydrawise/src/main/resources/OH-INF/i18n/hydrawise.properties create mode 100644 bundles/org.openhab.binding.hyperion/src/main/resources/OH-INF/i18n/hyperion.properties create mode 100644 bundles/org.openhab.binding.iammeter/src/main/resources/OH-INF/i18n/iammeter.properties create mode 100644 bundles/org.openhab.binding.iaqualink/src/main/resources/OH-INF/i18n/iaqualink.properties create mode 100644 bundles/org.openhab.binding.ihc/src/main/resources/OH-INF/i18n/ihc.properties create mode 100644 bundles/org.openhab.binding.innogysmarthome/src/main/resources/OH-INF/i18n/innogysmarthome.properties create mode 100644 bundles/org.openhab.binding.insteon/src/main/resources/OH-INF/i18n/insteon.properties create mode 100644 bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties create mode 100644 bundles/org.openhab.binding.ipobserver/src/main/resources/OH-INF/i18n/ipobserver.properties create mode 100644 bundles/org.openhab.binding.ipp/src/main/resources/OH-INF/i18n/ipp.properties create mode 100644 bundles/org.openhab.binding.irobot/src/main/resources/OH-INF/i18n/irobot.properties create mode 100644 bundles/org.openhab.binding.irtrans/src/main/resources/OH-INF/i18n/irtrans.properties create mode 100644 bundles/org.openhab.binding.ism8/src/main/resources/OH-INF/i18n/ism8.properties create mode 100644 bundles/org.openhab.binding.jablotron/src/main/resources/OH-INF/i18n/jablotron.properties create mode 100644 bundles/org.openhab.binding.kaleidescape/src/main/resources/OH-INF/i18n/kaleidescape.properties create mode 100644 bundles/org.openhab.binding.keba/src/main/resources/OH-INF/i18n/keba.properties create mode 100644 bundles/org.openhab.binding.km200/src/main/resources/OH-INF/i18n/km200.properties create mode 100644 bundles/org.openhab.binding.knx/src/main/resources/OH-INF/i18n/knx.properties create mode 100644 bundles/org.openhab.binding.konnected/src/main/resources/OH-INF/i18n/konnected.properties create mode 100644 bundles/org.openhab.binding.kostalinverter/src/main/resources/OH-INF/i18n/kostalinverter.properties create mode 100644 bundles/org.openhab.binding.kvv/src/main/resources/OH-INF/i18n/kvv.properties create mode 100644 bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties create mode 100644 bundles/org.openhab.binding.leapmotion/src/main/resources/OH-INF/i18n/leapmotion.properties create mode 100644 bundles/org.openhab.binding.lgtvserial/src/main/resources/OH-INF/i18n/lgtvserial.properties create mode 100644 bundles/org.openhab.binding.linuxinput/src/main/resources/OH-INF/i18n/linuxinput.properties create mode 100644 bundles/org.openhab.binding.lirc/src/main/resources/OH-INF/i18n/lirc.properties create mode 100644 bundles/org.openhab.binding.loxone/src/main/resources/OH-INF/i18n/loxone.properties create mode 100644 bundles/org.openhab.binding.luftdateninfo/src/main/resources/OH-INF/i18n/luftdateninfo.properties create mode 100644 bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/i18n/lutron.properties create mode 100644 bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/i18n/magentatv.properties create mode 100644 bundles/org.openhab.binding.mcp23017/src/main/resources/OH-INF/i18n/mcp23017.properties create mode 100644 bundles/org.openhab.binding.mecmeter/src/main/resources/OH-INF/i18n/mecmeter.properties create mode 100644 bundles/org.openhab.binding.melcloud/src/main/resources/OH-INF/i18n/melcloud.properties create mode 100644 bundles/org.openhab.binding.meteostick/src/main/resources/OH-INF/i18n/meteostick.properties create mode 100644 bundles/org.openhab.binding.mihome/src/main/resources/OH-INF/i18n/mihome.properties create mode 100644 bundles/org.openhab.binding.mikrotik/src/main/resources/OH-INF/i18n/mikrotik.properties create mode 100644 bundles/org.openhab.binding.milight/src/main/resources/OH-INF/i18n/milight.properties create mode 100644 bundles/org.openhab.binding.millheat/src/main/resources/OH-INF/i18n/millheat.properties create mode 100644 bundles/org.openhab.binding.minecraft/src/main/resources/OH-INF/i18n/minecraft.properties create mode 100644 bundles/org.openhab.binding.modbus.sbc/src/main/resources/OH-INF/i18n/modbus-sbc.properties create mode 100644 bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/OH-INF/i18n/stiebeleltron.properties create mode 100644 bundles/org.openhab.binding.modbus.sunspec/src/main/resources/OH-INF/i18n/sunspec.properties create mode 100644 bundles/org.openhab.binding.modbus/src/main/resources/OH-INF/i18n/modbus.properties create mode 100644 bundles/org.openhab.binding.monopriceaudio/src/main/resources/OH-INF/i18n/monopriceaudio.properties create mode 100644 bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd.properties create mode 100644 bundles/org.openhab.binding.mqtt.espmilighthub/src/main/resources/OH-INF/i18n/mqtt.properties create mode 100644 bundles/org.openhab.binding.mqtt.homeassistant/src/main/resources/OH-INF/i18n/mqtt.properties create mode 100644 bundles/org.openhab.binding.mqtt.homie/src/main/resources/OH-INF/i18n/mqtt.properties create mode 100644 bundles/org.openhab.binding.myq/src/main/resources/OH-INF/i18n/myq.properties create mode 100644 bundles/org.openhab.binding.mystrom/src/main/resources/OH-INF/i18n/mystrom.properties create mode 100644 bundles/org.openhab.binding.neato/src/main/resources/OH-INF/i18n/neato.properties create mode 100644 bundles/org.openhab.binding.neeo/src/main/resources/OH-INF/i18n/neeo.properties create mode 100644 bundles/org.openhab.binding.neohub/src/main/resources/OH-INF/i18n/neohub.properties create mode 100644 bundles/org.openhab.binding.nest/src/main/resources/OH-INF/i18n/nest.properties create mode 100644 bundles/org.openhab.binding.network/src/main/resources/OH-INF/i18n/network.properties create mode 100644 bundles/org.openhab.binding.networkupstools/src/main/resources/OH-INF/i18n/networkupstools.properties create mode 100644 bundles/org.openhab.binding.nibeheatpump/src/main/resources/OH-INF/i18n/nibeheatpump.properties create mode 100644 bundles/org.openhab.binding.nibeuplink/src/main/resources/OH-INF/i18n/nibeuplink.properties create mode 100644 bundles/org.openhab.binding.nikobus/src/main/resources/OH-INF/i18n/nikobus.properties create mode 100644 bundles/org.openhab.binding.novafinedust/src/main/resources/OH-INF/i18n/novafinedust.properties create mode 100644 bundles/org.openhab.binding.nuki/src/main/resources/OH-INF/i18n/nuki.properties create mode 100644 bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties create mode 100644 bundles/org.openhab.binding.nzwateralerts/src/main/resources/OH-INF/i18n/nzwateralerts.properties create mode 100644 bundles/org.openhab.binding.oceanic/src/main/resources/OH-INF/i18n/oceanic.properties create mode 100644 bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties create mode 100644 bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/i18n/omnikinverter.properties create mode 100644 bundles/org.openhab.binding.omnilink/src/main/resources/OH-INF/i18n/omnilink.properties create mode 100644 bundles/org.openhab.binding.onebusaway/src/main/resources/OH-INF/i18n/onebusaway.properties create mode 100644 bundles/org.openhab.binding.onewire/src/main/resources/OH-INF/i18n/onewire.properties create mode 100644 bundles/org.openhab.binding.onewiregpio/src/main/resources/OH-INF/i18n/onewiregpio.properties create mode 100644 bundles/org.openhab.binding.onkyo/src/main/resources/OH-INF/i18n/onkyo.properties create mode 100644 bundles/org.openhab.binding.opengarage/src/main/resources/OH-INF/i18n/opengarage.properties create mode 100644 bundles/org.openhab.binding.opensprinkler/src/main/resources/OH-INF/i18n/opensprinkler.properties create mode 100644 bundles/org.openhab.binding.openthermgateway/src/main/resources/OH-INF/i18n/openthermgateway.properties create mode 100644 bundles/org.openhab.binding.oppo/src/main/resources/OH-INF/i18n/oppo.properties create mode 100644 bundles/org.openhab.binding.orbitbhyve/src/main/resources/OH-INF/i18n/orbitbhyve.properties create mode 100644 bundles/org.openhab.binding.orvibo/src/main/resources/OH-INF/i18n/orvibo.properties create mode 100644 bundles/org.openhab.binding.paradoxalarm/src/main/resources/OH-INF/i18n/paradoxalarm.properties create mode 100644 bundles/org.openhab.binding.pentair/src/main/resources/OH-INF/i18n/pentair.properties create mode 100644 bundles/org.openhab.binding.phc/src/main/resources/OH-INF/i18n/phc.properties create mode 100644 bundles/org.openhab.binding.pilight/src/main/resources/OH-INF/i18n/pilight.properties create mode 100644 bundles/org.openhab.binding.pioneeravr/src/main/resources/OH-INF/i18n/pioneeravr.properties create mode 100644 bundles/org.openhab.binding.pjlinkdevice/src/main/resources/OH-INF/i18n/pjLinkDevice.properties create mode 100644 bundles/org.openhab.binding.plclogo/src/main/resources/OH-INF/i18n/plclogo.properties create mode 100644 bundles/org.openhab.binding.plugwiseha/src/main/resources/OH-INF/i18n/plugwiseha.properties create mode 100644 bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/i18n/pulseaudio.properties create mode 100644 bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus.properties create mode 100644 bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/i18n/radiothermostat.properties create mode 100644 bundles/org.openhab.binding.regoheatpump/src/main/resources/OH-INF/i18n/regoheatpump.properties create mode 100644 bundles/org.openhab.binding.renault/src/main/resources/OH-INF/i18n/renault.properties create mode 100644 bundles/org.openhab.binding.resol/src/main/resources/OH-INF/i18n/resol.properties create mode 100644 bundles/org.openhab.binding.revogi/src/main/resources/OH-INF/i18n/revogi.properties create mode 100644 bundles/org.openhab.binding.rme/src/main/resources/OH-INF/i18n/rme.properties create mode 100644 bundles/org.openhab.binding.robonect/src/main/resources/OH-INF/i18n/robonect.properties create mode 100644 bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties create mode 100644 bundles/org.openhab.binding.russound/src/main/resources/OH-INF/i18n/russound.properties create mode 100644 bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv.properties create mode 100644 bundles/org.openhab.binding.semsportal/src/main/resources/OH-INF/i18n/semsportal.properties create mode 100644 bundles/org.openhab.binding.senechome/src/main/resources/OH-INF/i18n/senechome.properties create mode 100644 bundles/org.openhab.binding.seneye/src/main/resources/OH-INF/i18n/seneye.properties create mode 100644 bundles/org.openhab.binding.sensebox/src/main/resources/OH-INF/i18n/sensebox.properties create mode 100644 bundles/org.openhab.binding.sensibo/src/main/resources/OH-INF/i18n/sensibo.properties create mode 100644 bundles/org.openhab.binding.serial/src/main/resources/OH-INF/i18n/serial.properties create mode 100644 bundles/org.openhab.binding.serialbutton/src/main/resources/OH-INF/i18n/serialbutton.properties create mode 100644 bundles/org.openhab.binding.siemensrds/src/main/resources/OH-INF/i18n/siemensrds.properties create mode 100644 bundles/org.openhab.binding.silvercrestwifisocket/src/main/resources/OH-INF/i18n/silvercrestwifisocket.properties create mode 100644 bundles/org.openhab.binding.smaenergymeter/src/main/resources/OH-INF/i18n/smaenergymeter.properties create mode 100644 bundles/org.openhab.binding.smartmeter/src/main/resources/OH-INF/i18n/smartmeter.properties create mode 100644 bundles/org.openhab.binding.smhi/src/main/resources/OH-INF/i18n/smhi.properties create mode 100644 bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties create mode 100644 bundles/org.openhab.binding.solaredge/src/main/resources/OH-INF/i18n/solaredge.properties create mode 100644 bundles/org.openhab.binding.solarlog/src/main/resources/OH-INF/i18n/solarlog.properties create mode 100644 bundles/org.openhab.binding.solarwatt/src/main/resources/OH-INF/i18n/solarwatt.properties create mode 100644 bundles/org.openhab.binding.somfymylink/src/main/resources/OH-INF/i18n/somfymylink.properties create mode 100644 bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/i18n/somfytahoma.properties create mode 100644 bundles/org.openhab.binding.sonyaudio/src/main/resources/OH-INF/i18n/sonyaudio.properties create mode 100644 bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/i18n/souliss.properties create mode 100644 bundles/org.openhab.binding.squeezebox/src/main/resources/OH-INF/i18n/squeezebox.properties create mode 100644 bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties create mode 100644 bundles/org.openhab.binding.tacmi/src/main/resources/OH-INF/i18n/tacmi.properties create mode 100644 bundles/org.openhab.binding.tado/src/main/resources/OH-INF/i18n/tado.properties create mode 100644 bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig.properties create mode 100644 bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties create mode 100644 bundles/org.openhab.binding.telegram/src/main/resources/OH-INF/i18n/telegram.properties create mode 100644 bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/teleinfo.properties create mode 100644 bundles/org.openhab.binding.tellstick/src/main/resources/OH-INF/i18n/tellstick.properties create mode 100644 bundles/org.openhab.binding.tesla/src/main/resources/OH-INF/i18n/tesla.properties create mode 100644 bundles/org.openhab.binding.tibber/src/main/resources/OH-INF/i18n/tibber.properties create mode 100644 bundles/org.openhab.binding.tivo/src/main/resources/OH-INF/i18n/tivo.properties create mode 100644 bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/i18n/touchwand.properties create mode 100644 bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/i18n/tplinksmarthome.properties create mode 100644 bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties create mode 100644 bundles/org.openhab.binding.unifiedremote/src/main/resources/OH-INF/i18n/unifiedremote.properties create mode 100644 bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/upb.properties create mode 100644 bundles/org.openhab.binding.upnpcontrol/src/main/resources/OH-INF/i18n/upnpcontrol.properties create mode 100644 bundles/org.openhab.binding.valloxmv/src/main/resources/OH-INF/i18n/valloxmv.properties create mode 100644 bundles/org.openhab.binding.vdr/src/main/resources/OH-INF/i18n/vdr.properties create mode 100644 bundles/org.openhab.binding.vektiva/src/main/resources/OH-INF/i18n/vektiva.properties create mode 100644 bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties create mode 100644 bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/i18n/venstarthermostat.properties create mode 100644 bundles/org.openhab.binding.ventaair/src/main/resources/OH-INF/i18n/ventaair.properties create mode 100644 bundles/org.openhab.binding.verisure/src/main/resources/OH-INF/i18n/verisure.properties create mode 100644 bundles/org.openhab.binding.vitotronic/src/main/resources/OH-INF/i18n/vitotronic.properties create mode 100644 bundles/org.openhab.binding.warmup/src/main/resources/OH-INF/i18n/warmup.properties create mode 100644 bundles/org.openhab.binding.webthing/src/main/resources/OH-INF/i18n/webthing.properties create mode 100644 bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties create mode 100644 bundles/org.openhab.binding.wifiled/src/main/resources/OH-INF/i18n/wifiled.properties create mode 100644 bundles/org.openhab.binding.wlanthermo/src/main/resources/OH-INF/i18n/wlanthermo.properties create mode 100644 bundles/org.openhab.binding.wled/src/main/resources/OH-INF/i18n/wled.properties create mode 100644 bundles/org.openhab.binding.wolfsmartset/src/main/resources/OH-INF/i18n/wolfsmartset.properties create mode 100644 bundles/org.openhab.binding.xmppclient/src/main/resources/OH-INF/i18n/xmppclient.properties create mode 100644 bundles/org.openhab.binding.yamahareceiver/src/main/resources/OH-INF/i18n/yamahareceiver.properties create mode 100644 bundles/org.openhab.binding.yeelight/src/main/resources/OH-INF/i18n/yeelight.properties create mode 100644 bundles/org.openhab.binding.yioremote/src/main/resources/OH-INF/i18n/yioremote.properties create mode 100644 bundles/org.openhab.binding.zoneminder/src/main/resources/OH-INF/i18n/zoneminder.properties diff --git a/bundles/org.openhab.binding.adorne/src/main/resources/OH-INF/i18n/adorne.properties b/bundles/org.openhab.binding.adorne/src/main/resources/OH-INF/i18n/adorne.properties new file mode 100644 index 0000000000000..72becbe108fa4 --- /dev/null +++ b/bundles/org.openhab.binding.adorne/src/main/resources/OH-INF/i18n/adorne.properties @@ -0,0 +1,21 @@ +# binding + +binding.adorne.name = Adorne Binding +binding.adorne.description = The Adorne Binding controls Legrand's Adorne Wi-Fi ready switches and outlets. + +# thing types + +thing-type.adorne.dimmer.label = Adorne Dimmer Switch +thing-type.adorne.dimmer.description = Controls an Adorne dimmer switch. +thing-type.adorne.hub.label = Adorne Hub +thing-type.adorne.hub.description = The Adorne Hub serves as the bridge to control Adorne switches, dimmer switches and outlets. +thing-type.adorne.switch.label = Adorne Switch +thing-type.adorne.switch.description = Controls an Adorne switch or outlet. + +# thing types config + +thing-type.config.adorne.dimmer.zoneId.label = Zone ID +thing-type.config.adorne.hub.host.label = Host +thing-type.config.adorne.hub.host.description = Host name or IP address. +thing-type.config.adorne.hub.port.label = Port +thing-type.config.adorne.switch.zoneId.label = Zone ID diff --git a/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/i18n/ahawastecollection.properties b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/i18n/ahawastecollection.properties new file mode 100644 index 0000000000000..f737917fdf9e2 --- /dev/null +++ b/bundles/org.openhab.binding.ahawastecollection/src/main/resources/OH-INF/i18n/ahawastecollection.properties @@ -0,0 +1,37 @@ +# binding + +binding.ahawastecollection.name = aha WasteCollection Binding +binding.ahawastecollection.description = This binding provides information about the upcoming waste collection dates for places, that are served by aha, the waste collection company of the region Hannover. The values are retrieved from the online aha waste collection schedule available at: https://www.aha-region.de/abholtermine/abfuhrkalender. + +# thing types + +thing-type.ahawastecollection.collectionSchedule.label = aha Waste Collection Schedule +thing-type.ahawastecollection.collectionSchedule.description = aha Waste Collection Schedule from http://www.aha-region.de/abholtermine/abfuhrkalender + +# thing types config + +thing-type.config.ahawastecollection.collectionSchedule.collectionPlace.label = Collection Place +thing-type.config.ahawastecollection.collectionSchedule.collectionPlace.description = Form value for the collection place, taken from the form field `ladeort`. This value must look like 67269-0010+ +thing-type.config.ahawastecollection.collectionSchedule.commune.label = Commune +thing-type.config.ahawastecollection.collectionSchedule.commune.description = The selected commune, taken from the form field 'gemeinde'. +thing-type.config.ahawastecollection.collectionSchedule.houseNumber.label = House Number +thing-type.config.ahawastecollection.collectionSchedule.houseNumber.description = The selected house number, taken from the form field 'hausnr'. +thing-type.config.ahawastecollection.collectionSchedule.houseNumberAddon.label = House Number Addon +thing-type.config.ahawastecollection.collectionSchedule.houseNumberAddon.description = The selected house number addon, taken from the form field 'hausnraddon'. +thing-type.config.ahawastecollection.collectionSchedule.street.label = Street +thing-type.config.ahawastecollection.collectionSchedule.street.description = The selected street, taken from the form field 'strasse'. This value must look like 67269@Rosmarinweg+/+Kirchhorst@Kirchhorst + +# channel types + +channel-type.ahawastecollection.collectionDateBioWaste.label = Bio Waste +channel-type.ahawastecollection.collectionDateBioWaste.description = Next collection day for bio waste +channel-type.ahawastecollection.collectionDateBioWaste.state.pattern = %1$tF +channel-type.ahawastecollection.collectionDateGeneralWaste.label = General Waste +channel-type.ahawastecollection.collectionDateGeneralWaste.description = Next collection day for general waste +channel-type.ahawastecollection.collectionDateGeneralWaste.state.pattern = %1$tF +channel-type.ahawastecollection.collectionDateLeightweightPackaging.label = Leightweight Packaging +channel-type.ahawastecollection.collectionDateLeightweightPackaging.description = Next collection day for leightweight packaging +channel-type.ahawastecollection.collectionDateLeightweightPackaging.state.pattern = %1$tF +channel-type.ahawastecollection.collectionDatePaper.label = Paper +channel-type.ahawastecollection.collectionDatePaper.description = Next collection day for paper +channel-type.ahawastecollection.collectionDatePaper.state.pattern = %1$tF diff --git a/bundles/org.openhab.binding.airq/src/main/resources/OH-INF/i18n/airq.properties b/bundles/org.openhab.binding.airq/src/main/resources/OH-INF/i18n/airq.properties new file mode 100644 index 0000000000000..ab4577908d867 --- /dev/null +++ b/bundles/org.openhab.binding.airq/src/main/resources/OH-INF/i18n/airq.properties @@ -0,0 +1,111 @@ +# binding + +binding.airq.name = air-Q Binding +binding.airq.description = This is the binding for air-Q devices. The air-Q device contains several sensors measuring gases in the air and other ambiance parameters like noise or temperature. With this binding you can integrate those values into your openHAB system and change parametrs of the air-Q device. + +# thing types + +thing-type.airq.airq.label = air-Q +thing-type.airq.airq.description = Thing for air-Q Device + +# thing types config + +thing-type.config.airq.airq.ipAddress.label = Network Address +thing-type.config.airq.airq.ipAddress.description = IP Network Address where air-Q Can Be Reached. +thing-type.config.airq.airq.password.label = Password +thing-type.config.airq.airq.password.description = Password of air-Q Device. + +# channel types + +channel-type.airq.AdvancedDataProcessing.label = Advanced Data Processing +channel-type.airq.AlarmForwarding.label = Share Alarms With Other air-Q +channel-type.airq.AutoDriftCompensation.label = Compensate Automatic Drift +channel-type.airq.AutoUpdate.label = Automatic Firmware Update +channel-type.airq.Averaging.label = Do Average +channel-type.airq.DeleteKey.label = Settings to Be Deleted +channel-type.airq.ErrorBars.label = Calculate Maximum Errors +channel-type.airq.FireAlarm.label = Fire Alarm +channel-type.airq.GasAlarm.label = Gas Alarm +channel-type.airq.InitialCalFinished.label = Initial Calibration Done +channel-type.airq.Logging.label = Logging Level +channel-type.airq.Rejection.label = Power Frequency +channel-type.airq.RoomType.label = Room Type +channel-type.airq.SecondsMeasurementDelay.label = Rhythm Historic Average +channel-type.airq.SoundInfo.label = Sound Info +channel-type.airq.TimeServer.label = Time Server +channel-type.airq.WLAN_config_BSSID.label = Network BSSID +channel-type.airq.WLAN_config_Gateway.label = Network Gateway +channel-type.airq.WLAN_config_IPAddress.label = Assigned IP Address +channel-type.airq.WLAN_config_MAC.label = MAC Address +channel-type.airq.WLAN_config_NetMask.label = Network Mask +channel-type.airq.WLAN_config_SSID.label = WLAN SSID +channel-type.airq.WLANssid.label = WLAN SSID +channel-type.airq.WarmupPhase.label = Send data as in Warmup Phase +channel-type.airq.Wifi.label = Use WLAN +channel-type.airq.WifiInfo.label = Show WLAN Status with LED +channel-type.airq.cloudUpload.label = Upload to air-Q Cloud +channel-type.airq.cnt0_3.label = Fine Dust >0,3 μm +channel-type.airq.cnt0_3_maxerr.label = Max. Error Fine Dust >0,3μm +channel-type.airq.cnt0_5.label = Fine Dust >0,5 μm +channel-type.airq.cnt0_5_maxerr.label = Max. Error Fine Dust >0,5μm +channel-type.airq.cnt1.label = Fine Dust >1 μm +channel-type.airq.cnt10.label = Fine Dust >10 μm +channel-type.airq.cnt10_maxerr.label = Max. Error Fine Dust >10μm +channel-type.airq.cnt1_maxerr.label = Max. Error Fine Dust >1μm +channel-type.airq.cnt2_5.label = Fine Dust >2,5 μm +channel-type.airq.cnt2_5_maxerr.label = Max. Error Fine Dust >2,5μm +channel-type.airq.cnt5.label = Fine Dust >5 μm +channel-type.airq.cnt5_maxerr.label = Max. Error Fine Dust >5μm +channel-type.airq.co.label = CO Concentration +channel-type.airq.co2.label = CO₂ Concentration +channel-type.airq.co2_maxerr.label = Max. Error CO₂ Conc. +channel-type.airq.co_maxerr.label = Max. Error CO Conc. +channel-type.airq.dco2dt.label = Change of CO₂ Concentr. +channel-type.airq.deviceName.label = Device Name +channel-type.airq.dewpt.label = Dew Point +channel-type.airq.dewpt_maxerr.label = Max. Error Dew Point +channel-type.airq.dhdt.label = Change of Humidity +channel-type.airq.door.label = Door Event (exp) +channel-type.airq.geopos.label = Location of air-Q Device +channel-type.airq.health.label = Health Index +channel-type.airq.humidity.label = Humidity +channel-type.airq.humidity_abs.label = Absolute Humidity +channel-type.airq.humidity_abs_maxerr.label = Max. Error Abs. Humidity +channel-type.airq.humidity_maxerr.label = Max. Error Humidity +channel-type.airq.mtime.label = Time Needed for Measurement +channel-type.airq.nightmodeBrightnessDay.label = Day Brightness of LED +channel-type.airq.nightmodeBrightnessNight.label = Night Brightness of LED +channel-type.airq.nightmodeFanNightOff.label = Switch Off Fan at Night +channel-type.airq.nightmodeStartDay.label = Start of Day Operation +channel-type.airq.nightmodeStartNight.label = End of Day Operation +channel-type.airq.nightmodeWifiNightOff.label = Switch Off WLAN at Night +channel-type.airq.no2.label = NO₂ Concentration +channel-type.airq.no2_maxerr.label = Max. Error NO₂ Conc. +channel-type.airq.o3.label = O₃ Concentration +channel-type.airq.o3_maxerr.label = Max. Error O₃ Conc. +channel-type.airq.oxygen.label = Oxygen Concentration +channel-type.airq.oxygen_maxerr.label = Max. Error Oxygen Conc. +channel-type.airq.pass.label = Device Password +channel-type.airq.performance.label = Performance Index +channel-type.airq.pm1.label = Fine Dust Concentr. >1μ +channel-type.airq.pm10.label = Fine Dust Concentr. >10μ +channel-type.airq.pm10_maxerr.label = Max. Error Fine Dust Conc. >10μm +channel-type.airq.pm1_maxerr.label = Max. Error Fine Dust Conc. >1μm +channel-type.airq.pm2_5.label = Fine Dust Concentr. >2,5μ +channel-type.airq.pm2_5_maxerr.label = Max. Error Fine Dust Conc. >2,5μm +channel-type.airq.ppm_and_ppb.label = Values in Particles +channel-type.airq.pressure.label = Pressure +channel-type.airq.pressure_maxerr.label = Max. Error Pressure +channel-type.airq.so2.label = SO₂ Concentration +channel-type.airq.so2_maxerr.label = Max. Error SO₂ Conc. +channel-type.airq.sound.label = Noise +channel-type.airq.sound_maxerr.label = Max. Error Noise +channel-type.airq.status.label = Status of Sensors +channel-type.airq.temperature.label = Temperature +channel-type.airq.temperature_maxerr.label = Max. Error Temperature +channel-type.airq.timestamp.label = Time Stamp +channel-type.airq.tvoc.label = VOC Concentration +channel-type.airq.tvoc_maxerr.label = Max. Error VOC Conc. +channel-type.airq.typps.label = Average Size of Fine Dust +channel-type.airq.uptime.label = Uptime +channel-type.airq.usercalib.label = Last Sensor Calibration diff --git a/bundles/org.openhab.binding.airvisualnode/src/main/resources/OH-INF/i18n/airvisualnode.properties b/bundles/org.openhab.binding.airvisualnode/src/main/resources/OH-INF/i18n/airvisualnode.properties new file mode 100644 index 0000000000000..0852a23ae3966 --- /dev/null +++ b/bundles/org.openhab.binding.airvisualnode/src/main/resources/OH-INF/i18n/airvisualnode.properties @@ -0,0 +1,43 @@ +# binding + +binding.airvisualnode.name = AirVisual Node Binding +binding.airvisualnode.description = Binding for AirVisual Node air quality monitor + +# thing types + +thing-type.airvisualnode.avnode.label = AirVisual Node +thing-type.airvisualnode.avnode.description = AirVisual Node air quality monitor + +# thing types config + +thing-type.config.airvisualnode.avnode.address.label = Node Network Address +thing-type.config.airvisualnode.avnode.address.description = Node network address +thing-type.config.airvisualnode.avnode.password.label = Node Password +thing-type.config.airvisualnode.avnode.password.description = Node network password +thing-type.config.airvisualnode.avnode.refresh.label = Refresh Interval +thing-type.config.airvisualnode.avnode.refresh.description = Node data fetches interval (in seconds) +thing-type.config.airvisualnode.avnode.share.label = Share Name +thing-type.config.airvisualnode.avnode.share.description = Node network share name +thing-type.config.airvisualnode.avnode.username.label = Node Username +thing-type.config.airvisualnode.avnode.username.description = Node network username + +# channel types + +channel-type.airvisualnode.Aqi.label = AQI +channel-type.airvisualnode.Aqi.description = Air Quality Index (US) +channel-type.airvisualnode.Co2.label = CO₂ Level +channel-type.airvisualnode.Co2.description = CO₂ level, ppm +channel-type.airvisualnode.Humidity.label = Humidity +channel-type.airvisualnode.Humidity.description = Humidity, % +channel-type.airvisualnode.Pm_01.label = PM0.1 +channel-type.airvisualnode.Pm_01.description = PM0.1 level, µg/m³(Only in Pro version) +channel-type.airvisualnode.Pm_10.label = PM10 +channel-type.airvisualnode.Pm_10.description = PM10 level, µg/m³(Only in Pro version) +channel-type.airvisualnode.Pm_25.label = PM2.5 +channel-type.airvisualnode.Pm_25.description = PM2.5 level, µg/m³ +channel-type.airvisualnode.Temperature.label = Temperature +channel-type.airvisualnode.Temperature.description = Current temperature +channel-type.airvisualnode.Timestamp.label = Timestamp +channel-type.airvisualnode.Timestamp.description = Status timestamp +channel-type.airvisualnode.Used_memory.label = Used Memory +channel-type.airvisualnode.Used_memory.description = Used memory diff --git a/bundles/org.openhab.binding.alarmdecoder/src/main/resources/OH-INF/i18n/alarmdecoder.properties b/bundles/org.openhab.binding.alarmdecoder/src/main/resources/OH-INF/i18n/alarmdecoder.properties new file mode 100644 index 0000000000000..c7af2197f8dcf --- /dev/null +++ b/bundles/org.openhab.binding.alarmdecoder/src/main/resources/OH-INF/i18n/alarmdecoder.properties @@ -0,0 +1,105 @@ +# binding + +binding.alarmdecoder.name = Alarm Decoder Binding +binding.alarmdecoder.description = This binding is for the Nu Tech Alarm Decoder, used for interfacing with Ademco/Honeywell and DSC alarm systems. + +# thing types + +thing-type.alarmdecoder.ipbridge.label = Alarm Decoder IP Bridge +thing-type.alarmdecoder.ipbridge.description = Nu Tech Alarm Decoder IP Bridge +thing-type.alarmdecoder.keypad.label = Alarm Keypad +thing-type.alarmdecoder.keypad.description = Alarm Decoder keypad thing +thing-type.alarmdecoder.keypad.channel.acpower.label = AC Power +thing-type.alarmdecoder.keypad.channel.alarm.label = Alarm +thing-type.alarmdecoder.keypad.channel.alarm.description = Alarm is currently sounding +thing-type.alarmdecoder.keypad.channel.alarmoccurred.label = Alarm Occurred +thing-type.alarmdecoder.keypad.channel.alarmoccurred.description = Alarm has occurred in the past +thing-type.alarmdecoder.keypad.channel.armedaway.label = Armed Away +thing-type.alarmdecoder.keypad.channel.armedhome.label = Armed Stay +thing-type.alarmdecoder.keypad.channel.backlight.label = Keypad Backlight +thing-type.alarmdecoder.keypad.channel.beeps.label = Beeps +thing-type.alarmdecoder.keypad.channel.beeps.description = Number of beeps for message +thing-type.alarmdecoder.keypad.channel.bypassed.label = Zone Bypassed +thing-type.alarmdecoder.keypad.channel.chime.label = Chime Enabled +thing-type.alarmdecoder.keypad.channel.command.label = Keypad Command +thing-type.alarmdecoder.keypad.channel.delayoff.label = Entry Delay Off +thing-type.alarmdecoder.keypad.channel.fire.label = Fire Detected +thing-type.alarmdecoder.keypad.channel.intcommand.label = Integer Mapped Keypad Command +thing-type.alarmdecoder.keypad.channel.lowbat.label = Low Battery +thing-type.alarmdecoder.keypad.channel.perimeter.label = Perimeter Only +thing-type.alarmdecoder.keypad.channel.program.label = Programming Mode +thing-type.alarmdecoder.keypad.channel.ready.label = Ready +thing-type.alarmdecoder.keypad.channel.sysfault.label = System Fault +thing-type.alarmdecoder.keypad.channel.text.label = Keypad Message +thing-type.alarmdecoder.keypad.channel.zone.label = Zone +thing-type.alarmdecoder.lrr.label = Long Range Radio +thing-type.alarmdecoder.lrr.description = Long range radio message handler +thing-type.alarmdecoder.lrr.channel.cidmessage.label = CID Message +thing-type.alarmdecoder.lrr.channel.cidmessage.description = SIA Contact ID Protocol message +thing-type.alarmdecoder.lrr.channel.eventdata.label = Event Data +thing-type.alarmdecoder.lrr.channel.eventdata.description = CID event data (user or zone) +thing-type.alarmdecoder.lrr.channel.partition.label = Partition +thing-type.alarmdecoder.lrr.channel.partition.description = Partition number (0 = System) +thing-type.alarmdecoder.lrr.channel.reportcode.label = Report Code +thing-type.alarmdecoder.lrr.channel.reportcode.description = CID report code +thing-type.alarmdecoder.rfzone.label = Alarm RF Zone +thing-type.alarmdecoder.rfzone.description = Alarm Decoder RFX zone +thing-type.alarmdecoder.rfzone.channel.loop1.label = Loop 1 +thing-type.alarmdecoder.rfzone.channel.loop2.label = Loop 2 +thing-type.alarmdecoder.rfzone.channel.loop3.label = Loop 3 +thing-type.alarmdecoder.rfzone.channel.loop4.label = Loop 4 +thing-type.alarmdecoder.rfzone.channel.lowbat.label = Low Battery +thing-type.alarmdecoder.rfzone.channel.supervision.label = Supervision Indicator +thing-type.alarmdecoder.serialbridge.label = Alarm Decoder Serial Bridge +thing-type.alarmdecoder.serialbridge.description = Nu Tech Alarm Decoder Serial Bridge +thing-type.alarmdecoder.vzone.label = Virtual Zone +thing-type.alarmdecoder.vzone.description = Alarm Decoder virtual zone +thing-type.alarmdecoder.zone.label = Alarm Zone +thing-type.alarmdecoder.zone.description = Alarm Decoder REL or EXP zone + +# thing types config + +thing-type.config.alarmdecoder.ipbridge.discovery.label = Enable Discovery +thing-type.config.alarmdecoder.ipbridge.discovery.description = Enable automatic discovery of zones and RF zones +thing-type.config.alarmdecoder.ipbridge.hostname.label = Host Name +thing-type.config.alarmdecoder.ipbridge.hostname.description = The hostname or IP address of the Alarm Decoder device +thing-type.config.alarmdecoder.ipbridge.reconnect.label = Reconnect Interval +thing-type.config.alarmdecoder.ipbridge.reconnect.description = The period in minutes that the handler will wait between connection attempts and checks +thing-type.config.alarmdecoder.ipbridge.tcpPort.label = TCP Port +thing-type.config.alarmdecoder.ipbridge.tcpPort.description = TCP port number for the Alarm Decoder connection +thing-type.config.alarmdecoder.ipbridge.timeout.label = Message Receive Timeout +thing-type.config.alarmdecoder.ipbridge.timeout.description = The period in minutes after which the connection will be reset if no valid messages have been received. Set to 0 to disable. +thing-type.config.alarmdecoder.keypad.addressMask.label = Address Mask +thing-type.config.alarmdecoder.keypad.addressMask.description = String containing the address mask in hex that the keypad thing will receive messages for. (0=any) +thing-type.config.alarmdecoder.keypad.commandMapping.label = Command Mapping for intcommand Channel +thing-type.config.alarmdecoder.keypad.commandMapping.description = Comma separated list of key/value pairs mapping integers to command strings for intcommand channel. +thing-type.config.alarmdecoder.keypad.sendCommands.label = Send Commands +thing-type.config.alarmdecoder.keypad.sendCommands.description = Allow keypad commands to be sent to the alarm system from openHAB. Enabling this means the alarm system will be only as secure as your openHAB system. +thing-type.config.alarmdecoder.keypad.sendStar.label = Send * for Fault Info +thing-type.config.alarmdecoder.keypad.sendStar.description = When disarmed, automatically send * character to obtain zone fault information. +thing-type.config.alarmdecoder.lrr.partition.label = Partition +thing-type.config.alarmdecoder.lrr.partition.description = Partition for which to receive LRR events (0=All) +thing-type.config.alarmdecoder.rfzone.serial.label = Serial +thing-type.config.alarmdecoder.rfzone.serial.description = Serial number of the RF zone +thing-type.config.alarmdecoder.serialbridge.bitrate.label = Bitrate +thing-type.config.alarmdecoder.serialbridge.bitrate.description = Speed of the serial connection +thing-type.config.alarmdecoder.serialbridge.discovery.label = Enable Discovery +thing-type.config.alarmdecoder.serialbridge.discovery.description = Enable automatic discovery of zones and RF zones +thing-type.config.alarmdecoder.serialbridge.serialPort.label = Serial Or USB Port +thing-type.config.alarmdecoder.serialbridge.serialPort.description = The name of the serial port used to connect to the Alarm Decoder device +thing-type.config.alarmdecoder.vzone.address.label = Virtual Zone Number +thing-type.config.alarmdecoder.zone.address.label = Zone Address +thing-type.config.alarmdecoder.zone.channel.label = Zone Channel + +# channel types + +channel-type.alarmdecoder.command-channel.label = Command Channel +channel-type.alarmdecoder.contact-channel.label = Contact State +channel-type.alarmdecoder.contact-command-channel.label = Contact Command +channel-type.alarmdecoder.contact-command-channel.command.option.OPEN = Open +channel-type.alarmdecoder.contact-command-channel.command.option.CLOSED = Closed +channel-type.alarmdecoder.indicator-channel.label = Indicator State +channel-type.alarmdecoder.int-command-channel.label = Integer Command Channel +channel-type.alarmdecoder.number-channel.label = Number +channel-type.alarmdecoder.switch-channel.label = Switch State +channel-type.alarmdecoder.text-channel.label = Text Channel diff --git a/bundles/org.openhab.binding.allplay/src/main/resources/OH-INF/i18n/allplay.properties b/bundles/org.openhab.binding.allplay/src/main/resources/OH-INF/i18n/allplay.properties new file mode 100644 index 0000000000000..a2dc5bce097b9 --- /dev/null +++ b/bundles/org.openhab.binding.allplay/src/main/resources/OH-INF/i18n/allplay.properties @@ -0,0 +1,78 @@ +# binding + +binding.allplay.name = AllPlay Binding +binding.allplay.description = The AllPlay binding integrates devices compatible with Qualcomm AllPlay. + +# binding config + +binding.config.allplay.callbackUrl.label = Callback URL +binding.config.allplay.callbackUrl.description = URL to use for playing audio streams, e.g. http://192.168.0.2:8080 +binding.config.allplay.fastForwardSkipTimeInSec.label = Fast Forward Skip Time +binding.config.allplay.fastForwardSkipTimeInSec.description = Seconds to jump forward if the fastforward command is executed +binding.config.allplay.rewindSkipTimeInSec.label = Rewind Skip Time +binding.config.allplay.rewindSkipTimeInSec.description = Seconds to jump backwards if the rewind command is executed +binding.config.allplay.zoneMemberSeparator.label = Zone Member Separator +binding.config.allplay.zoneMemberSeparator.description = Separator which is used when sending multiple zone members to channel 'zonemembers' + +# thing types + +thing-type.allplay.speaker.label = AllPlay Speaker + +# thing types config + +thing-type.config.allplay.speaker.deviceId.label = Device ID +thing-type.config.allplay.speaker.deviceId.description = The device identifier identifies one certain speaker. +thing-type.config.allplay.speaker.deviceName.label = Device Name +thing-type.config.allplay.speaker.deviceName.description = The device name of the speaker. +thing-type.config.allplay.speaker.volumeStepSize.label = Volume Step Size +thing-type.config.allplay.speaker.volumeStepSize.description = Step size to use if the volume is changed using the increase/decrease command. + +# channel types + +channel-type.allplay.clearzone.label = Clear Zone +channel-type.allplay.clearzone.description = Remove the current speaker from the zone +channel-type.allplay.control.label = Control +channel-type.allplay.control.description = Control the AllPlay speaker, e.g. start/pause/next/previous/ffward/rewind +channel-type.allplay.coverart.label = Cover Art +channel-type.allplay.coverart.description = Cover art image of the track currently playing +channel-type.allplay.coverarturl.label = Cover Art URL +channel-type.allplay.coverarturl.description = Cover art URL of the track currently playing +channel-type.allplay.currentalbum.label = Current Album +channel-type.allplay.currentalbum.description = Album of the track currently playing +channel-type.allplay.currentartist.label = Current Artist +channel-type.allplay.currentartist.description = Artist of the track currently playing +channel-type.allplay.currentduration.label = Current Duration +channel-type.allplay.currentduration.description = Duration in seconds of the track currently playing +channel-type.allplay.currentgenre.label = Current Genre +channel-type.allplay.currentgenre.description = Genre of the track currently playing +channel-type.allplay.currenttitle.label = Current Title +channel-type.allplay.currenttitle.description = Title of the track currently playing +channel-type.allplay.currenturl.label = Current URL +channel-type.allplay.currenturl.description = URL of the track or radio station currently playing +channel-type.allplay.currentuserdata.label = Current User Data +channel-type.allplay.currentuserdata.description = Custom user data (e.g. name of radio station) of the track currently playing +channel-type.allplay.input.label = Input +channel-type.allplay.input.description = Current input of the speaker +channel-type.allplay.loopmode.label = Loop Mode +channel-type.allplay.loopmode.description = Loop mode of the speaker (ONE, ALL, NONE) +channel-type.allplay.loopmode.state.option.NONE = No Repeat +channel-type.allplay.loopmode.state.option.ONE = Repeat Track +channel-type.allplay.loopmode.state.option.ALL = Repeat Playlist +channel-type.allplay.mute.label = Mute +channel-type.allplay.mute.description = Set or get the mute state of the speaker +channel-type.allplay.playstate.label = State +channel-type.allplay.playstate.description = The State channel contains state of the Speaker, e.g. BUFFERING, PLAYING, STOPPED,... +channel-type.allplay.shufflemode.label = Shuffle Mode +channel-type.allplay.shufflemode.description = Toggle the shuffle mode of the speaker +channel-type.allplay.stop.label = Stop +channel-type.allplay.stop.description = Stop the current playback +channel-type.allplay.stream.label = Stream URL +channel-type.allplay.stream.description = Play the given HTTP or file stream (file:// or http://) +channel-type.allplay.volume.label = Volume +channel-type.allplay.volume.description = Set or get the master volume +channel-type.allplay.volumecontrol.label = Volume Control +channel-type.allplay.volumecontrol.description = Flag if the volume control is enabled (might be disabled if speaker is not master of the zone) +channel-type.allplay.zoneid.label = Zone ID +channel-type.allplay.zoneid.description = Id of the Zone the speaker belongs to +channel-type.allplay.zonemembers.label = Zone Members +channel-type.allplay.zonemembers.description = Comma-separated list of zone members of this (lead) speaker diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/OH-INF/i18n/amazonechocontrol.properties b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/OH-INF/i18n/amazonechocontrol.properties new file mode 100644 index 0000000000000..1875688d70123 --- /dev/null +++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/OH-INF/i18n/amazonechocontrol.properties @@ -0,0 +1,181 @@ +# binding + +binding.amazonechocontrol.name = Amazon Echo Control Binding +binding.amazonechocontrol.description = Binding 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. + +# thing types + +thing-type.amazonechocontrol.account.label = Amazon Account +thing-type.amazonechocontrol.account.description = Amazon Account where the amazon echo devices are registered. +thing-type.amazonechocontrol.echo.label = Amazon Echo +thing-type.amazonechocontrol.echo.description = Amazon Echo device (Amazon Echo, Amazon Echo Dot, Amazon Echo Plus...) +thing-type.amazonechocontrol.echoshow.label = Amazon Echo Show +thing-type.amazonechocontrol.echoshow.description = Amazon Echo Show device +thing-type.amazonechocontrol.echospot.label = Amazon Echo Spot +thing-type.amazonechocontrol.echospot.description = Amazon Echo Spot device +thing-type.amazonechocontrol.flashbriefingprofile.label = Flash Briefing Profile +thing-type.amazonechocontrol.flashbriefingprofile.description = Store and load a flash briefing configuration +thing-type.amazonechocontrol.smartHomeDevice.label = Smart Home Device +thing-type.amazonechocontrol.smartHomeDevice.description = Smart home device connected to Alexa +thing-type.amazonechocontrol.smartHomeDeviceGroup.label = Smart Home Device Group +thing-type.amazonechocontrol.smartHomeDeviceGroup.description = Group of smart home devices in your amazon account +thing-type.amazonechocontrol.wha.label = Amazon Echo Whole House Audio Control +thing-type.amazonechocontrol.wha.description = Amazon Multiroom Music + +# thing types config + +thing-type.config.amazonechocontrol.account.discoverSmartHome.label = Device Discovery Mode +thing-type.config.amazonechocontrol.account.discoverSmartHome.description = Defines which devices shall be discovered. +thing-type.config.amazonechocontrol.account.discoverSmartHome.option.0 = No Discovery +thing-type.config.amazonechocontrol.account.discoverSmartHome.option.1 = Direct connected +thing-type.config.amazonechocontrol.account.discoverSmartHome.option.2 = Direct and over Alexa skill +thing-type.config.amazonechocontrol.account.discoverSmartHome.option.3 = Direct, over Alexa and openHAB skill +thing-type.config.amazonechocontrol.account.pollingIntervalSmartHomeAlexa.label = Polling Interval Alexa +thing-type.config.amazonechocontrol.account.pollingIntervalSmartHomeAlexa.description = Defines the time in seconds for openHAB to pull the state of the directly connected devices. The minimum is 10 seconds. +thing-type.config.amazonechocontrol.account.pollingIntervalSmartSkills.label = Polling Interval Skill +thing-type.config.amazonechocontrol.account.pollingIntervalSmartSkills.description = Defines the time in seconds for openHAB to pull the state of the over a skill connected devices. The minimum is 60 seconds. +thing-type.config.amazonechocontrol.echo.serialNumber.label = Serial Number +thing-type.config.amazonechocontrol.echo.serialNumber.description = The serial number of the device from the Alexa app +thing-type.config.amazonechocontrol.echoshow.serialNumber.label = Serial Number +thing-type.config.amazonechocontrol.echoshow.serialNumber.description = The serial number of the device from the Alexa app +thing-type.config.amazonechocontrol.echospot.serialNumber.label = Serial Number +thing-type.config.amazonechocontrol.echospot.serialNumber.description = The serial number of the device from the Alexa app +thing-type.config.amazonechocontrol.smartHomeDevice.id.label = Device Id +thing-type.config.amazonechocontrol.smartHomeDevice.id.description = The id of the device (Please use the discover function to get a configured Thing) +thing-type.config.amazonechocontrol.smartHomeDeviceGroup.id.label = Group Id +thing-type.config.amazonechocontrol.smartHomeDeviceGroup.id.description = The id of the device group (Please use the discover function to get a configured Thing) +thing-type.config.amazonechocontrol.wha.serialNumber.label = Serial Number +thing-type.config.amazonechocontrol.wha.serialNumber.description = The serial number of the device from the Alexa app + +# channel types + +channel-type.amazonechocontrol.active.label = Active +channel-type.amazonechocontrol.active.description = Activate this flash briefing configuration +channel-type.amazonechocontrol.amazonMusic.label = Amazon Music +channel-type.amazonechocontrol.amazonMusic.description = Amazon Music turned on +channel-type.amazonechocontrol.amazonMusicPlayListId.label = Amazon Music Play List Id +channel-type.amazonechocontrol.amazonMusicPlayListId.description = Amazon Music play list id (Write only, no current state) +channel-type.amazonechocontrol.amazonMusicPlayListIdLastUsed.label = Amazon Music Last Selected Playlist Id +channel-type.amazonechocontrol.amazonMusicPlayListIdLastUsed.description = Id of the playlist which was started with openHAB +channel-type.amazonechocontrol.amazonMusicTrackId.label = Amazon Music Track Id +channel-type.amazonechocontrol.amazonMusicTrackId.description = Id of the amazon music track +channel-type.amazonechocontrol.announcement.label = Announcement +channel-type.amazonechocontrol.announcement.description = 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. +channel-type.amazonechocontrol.armState.label = ARM State +channel-type.amazonechocontrol.armState.description = ARM State +channel-type.amazonechocontrol.ascendingAlarm.label = Ascending Alarm +channel-type.amazonechocontrol.ascendingAlarm.description = Ascending alarm up to the configured volume +channel-type.amazonechocontrol.bluetooth.label = Bluetooth Connection +channel-type.amazonechocontrol.bluetooth.description = Connect to last used device +channel-type.amazonechocontrol.bluetoothDeviceName.label = Bluetooth Device +channel-type.amazonechocontrol.bluetoothDeviceName.description = Connected bluetooth device +channel-type.amazonechocontrol.bluetoothMAC.label = Bluetooth Connection +channel-type.amazonechocontrol.bluetoothMAC.description = MAC-Address of the bluetooth connected device +channel-type.amazonechocontrol.brightness.label = Brightness +channel-type.amazonechocontrol.brightness.description = Brightness +channel-type.amazonechocontrol.burglaryAlarm.label = Burglary Alarm +channel-type.amazonechocontrol.burglaryAlarm.description = Burglary Alarm +channel-type.amazonechocontrol.carbonMonoxideAlarm.label = Carbon Monoxide Alarm +channel-type.amazonechocontrol.carbonMonoxideAlarm.description = Carbon Monoxide Alarm +channel-type.amazonechocontrol.color.label = Color +channel-type.amazonechocontrol.color.description = Color +channel-type.amazonechocontrol.colorName.label = Color Name +channel-type.amazonechocontrol.colorName.description = Color Name +channel-type.amazonechocontrol.colorTemperatureInKelvin.label = Color Temperature In Kelvin +channel-type.amazonechocontrol.colorTemperatureInKelvin.description = Color Temperature In Kelvin +channel-type.amazonechocontrol.colorTemperatureName.label = Color Temperature Name +channel-type.amazonechocontrol.colorTemperatureName.description = Color Temperature Name +channel-type.amazonechocontrol.equalizerBass.label = Bass +channel-type.amazonechocontrol.equalizerBass.description = Equalizer Bass +channel-type.amazonechocontrol.equalizerMidrange.label = Midrange +channel-type.amazonechocontrol.equalizerMidrange.description = Equalizer Midrange +channel-type.amazonechocontrol.equalizerTreble.label = Treble +channel-type.amazonechocontrol.equalizerTreble.description = Equalizer Treble +channel-type.amazonechocontrol.fireAlarm.label = Fire Alarm +channel-type.amazonechocontrol.fireAlarm.description = Fire Alarm +channel-type.amazonechocontrol.glassBreakDetectionState.label = Glass Break Detection State +channel-type.amazonechocontrol.glassBreakDetectionState.description = Glass Break Detection State +channel-type.amazonechocontrol.imageUrl.label = Image Url +channel-type.amazonechocontrol.imageUrl.description = Url of the album image or radio station logo +channel-type.amazonechocontrol.lastVoiceCommand.label = Last Voice Command +channel-type.amazonechocontrol.lastVoiceCommand.description = Last voice command spoken to the device. Writing to the channel starts voice output. +channel-type.amazonechocontrol.loop.label = Loop +channel-type.amazonechocontrol.loop.description = Loop +channel-type.amazonechocontrol.mediaLength.label = Media Length +channel-type.amazonechocontrol.mediaLength.description = Media length +channel-type.amazonechocontrol.mediaProgress.label = Media Progress +channel-type.amazonechocontrol.mediaProgress.description = Media progress in percent +channel-type.amazonechocontrol.mediaProgressTime.label = Media Play Time +channel-type.amazonechocontrol.mediaProgressTime.description = Media play time +channel-type.amazonechocontrol.musicProviderId.label = Music Provider +channel-type.amazonechocontrol.musicProviderId.description = Music provider +channel-type.amazonechocontrol.nextAlarm.label = Next Alarm +channel-type.amazonechocontrol.nextAlarm.description = Next alarm +channel-type.amazonechocontrol.nextMusicAlarm.label = Next Music Alarm +channel-type.amazonechocontrol.nextMusicAlarm.description = Next music alarm +channel-type.amazonechocontrol.nextReminder.label = Next Reminder +channel-type.amazonechocontrol.nextReminder.description = Next Reminder +channel-type.amazonechocontrol.nextTimer.label = Next Timer +channel-type.amazonechocontrol.nextTimer.description = Next timer +channel-type.amazonechocontrol.notificationVolume.label = Notification Volume +channel-type.amazonechocontrol.notificationVolume.description = Notification Volume +channel-type.amazonechocontrol.percentage.label = Percentage +channel-type.amazonechocontrol.percentage.description = Percentage +channel-type.amazonechocontrol.playAlarmSound.label = Alarm Sound +channel-type.amazonechocontrol.playAlarmSound.description = Plays an alarm sound +channel-type.amazonechocontrol.playMusicVoiceCommand.label = Music Voice Command +channel-type.amazonechocontrol.playMusicVoiceCommand.description = Voice command as text. E.g. 'Yesterday from the Beatles' (Write only) +channel-type.amazonechocontrol.playOnDevice.label = Play On Device +channel-type.amazonechocontrol.playOnDevice.description = Plays the briefing on the device (serial number or name, write only) +channel-type.amazonechocontrol.player.label = Player +channel-type.amazonechocontrol.player.description = Music Player +channel-type.amazonechocontrol.powerLevel.label = Power Level +channel-type.amazonechocontrol.powerLevel.description = Power Level +channel-type.amazonechocontrol.powerState.label = Power State +channel-type.amazonechocontrol.powerState.description = Power State +channel-type.amazonechocontrol.providerDisplayName.label = Provider Name +channel-type.amazonechocontrol.providerDisplayName.description = Name of music provider +channel-type.amazonechocontrol.radio.label = TuneIn Radio +channel-type.amazonechocontrol.radio.description = Radio turned on +channel-type.amazonechocontrol.radioStationId.label = TuneIn Radio Station Id +channel-type.amazonechocontrol.radioStationId.description = Id of the radio station +channel-type.amazonechocontrol.remind.label = Remind +channel-type.amazonechocontrol.remind.description = Speak the reminder and send a notification to the Alexa app +channel-type.amazonechocontrol.save.label = Save +channel-type.amazonechocontrol.save.description = Save the current flash briefing configuration (Write only) +channel-type.amazonechocontrol.sendMessage.label = Send Message +channel-type.amazonechocontrol.sendMessage.description = Sends a message to the Echo devices (Write only). +channel-type.amazonechocontrol.shuffle.label = Shuffle +channel-type.amazonechocontrol.shuffle.description = Shuffle play +channel-type.amazonechocontrol.smokeAlarmDetectionState.label = Smoke Alarm Detection State +channel-type.amazonechocontrol.smokeAlarmDetectionState.description = Smoke Alarm Detection State +channel-type.amazonechocontrol.startCommand.label = Start +channel-type.amazonechocontrol.startCommand.description = Start information (Write only) +channel-type.amazonechocontrol.startCommand.state.option.Weather = Weather +channel-type.amazonechocontrol.startCommand.state.option.Traffic = Traffic +channel-type.amazonechocontrol.startCommand.state.option.GoodMorning = Good morning +channel-type.amazonechocontrol.startCommand.state.option.SingASong = Song +channel-type.amazonechocontrol.startCommand.state.option.TellStory = Story +channel-type.amazonechocontrol.startCommand.state.option.FlashBriefing = Flash briefing +channel-type.amazonechocontrol.startRoutine.label = Start a Routine +channel-type.amazonechocontrol.startRoutine.description = The command which must be spoken to active the routing without the preceding "Alexa," (Write Only) +channel-type.amazonechocontrol.subtitle1.label = Subtitle 1 +channel-type.amazonechocontrol.subtitle1.description = Subtitle 1 +channel-type.amazonechocontrol.subtitle2.label = Subtitle 2 +channel-type.amazonechocontrol.subtitle2.description = Subtitle 2 +channel-type.amazonechocontrol.targetSetpoint.label = Target Setpoint +channel-type.amazonechocontrol.targetSetpoint.description = Target Setpoint +channel-type.amazonechocontrol.temperature.label = Temperature +channel-type.amazonechocontrol.temperature.description = Temperature +channel-type.amazonechocontrol.textCommand.label = TextCommand +channel-type.amazonechocontrol.textCommand.description = Run a command (Write only). The command can run like a spoken command. +channel-type.amazonechocontrol.textToSpeech.label = Speak +channel-type.amazonechocontrol.textToSpeech.description = Speak the text (Write only). It is possible to use plain text or SSML: I want to tell you a secret.I am not a real human..Can you believe it? +channel-type.amazonechocontrol.textToSpeechVolume.label = Speak Volume +channel-type.amazonechocontrol.textToSpeechVolume.description = Volume of the Speak channel. If 0, the current volume will be used. +channel-type.amazonechocontrol.title.label = Title +channel-type.amazonechocontrol.title.description = Title +channel-type.amazonechocontrol.volume.label = Volume +channel-type.amazonechocontrol.volume.description = Volume of the sound +channel-type.amazonechocontrol.waterAlarm.label = Water Alarm +channel-type.amazonechocontrol.waterAlarm.description = Water Alarm diff --git a/bundles/org.openhab.binding.amplipi/src/main/resources/OH-INF/i18n/amplipi.properties b/bundles/org.openhab.binding.amplipi/src/main/resources/OH-INF/i18n/amplipi.properties new file mode 100644 index 0000000000000..b7fce2d0557b6 --- /dev/null +++ b/bundles/org.openhab.binding.amplipi/src/main/resources/OH-INF/i18n/amplipi.properties @@ -0,0 +1,45 @@ +# binding + +binding.amplipi.name = AmpliPi Binding +binding.amplipi.description = This is the binding for the AmpliPi Home Audio System from MicroNova. + +# thing types + +thing-type.amplipi.controller.label = AmpliPi Controller +thing-type.amplipi.controller.description = An AmpliPi controller +thing-type.amplipi.controller.channel.input1.label = Source 1 +thing-type.amplipi.controller.channel.input1.description = This channel selects the input for source 1. +thing-type.amplipi.controller.channel.input2.label = Source 2 +thing-type.amplipi.controller.channel.input2.description = This channel selects the input for source 2. +thing-type.amplipi.controller.channel.input3.label = Source 3 +thing-type.amplipi.controller.channel.input3.description = This channel selects the input for source 3. +thing-type.amplipi.controller.channel.input4.label = Source 4 +thing-type.amplipi.controller.channel.input4.description = This channel selects the input for source 4. +thing-type.amplipi.group.label = AmpliPi Group +thing-type.amplipi.group.description = A group of the AmpliPi system +thing-type.amplipi.zone.label = AmpliPi Zone +thing-type.amplipi.zone.description = A zone of the AmpliPi system + +# thing types config + +thing-type.config.amplipi.controller.hostname.label = Hostname +thing-type.config.amplipi.controller.hostname.description = Hostname or IP address of the AmpliPi +thing-type.config.amplipi.controller.refreshInterval.label = Refresh Interval +thing-type.config.amplipi.controller.refreshInterval.description = Interval the device is polled in sec. +thing-type.config.amplipi.group.id.label = Group ID +thing-type.config.amplipi.group.id.description = The ID of the group +thing-type.config.amplipi.zone.id.label = Zone ID +thing-type.config.amplipi.zone.id.description = The ID of the zone + +# channel types + +channel-type.amplipi.input.label = Input +channel-type.amplipi.input.description = The selected input for the source +channel-type.amplipi.preset.label = Preset +channel-type.amplipi.preset.description = Choose an existing preset +channel-type.amplipi.source.label = Source +channel-type.amplipi.source.description = The audio source that is played +channel-type.amplipi.source.state.option.0 = Source 1 +channel-type.amplipi.source.state.option.1 = Source 2 +channel-type.amplipi.source.state.option.2 = Source 3 +channel-type.amplipi.source.state.option.3 = Source 4 diff --git a/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties new file mode 100644 index 0000000000000..7e336f9ff10d7 --- /dev/null +++ b/bundles/org.openhab.binding.androiddebugbridge/src/main/resources/OH-INF/i18n/androiddebugbridge.properties @@ -0,0 +1,349 @@ +# binding + +binding.androiddebugbridge.name = Android Debug Bridge Binding +binding.androiddebugbridge.description = This is the binding for connect to Android devices using the Android Debug Bridge protocol. + +# binding config + +binding.config.androiddebugbridge.discoveryIpRangeMax.label = Discovery Range IP Max +binding.config.androiddebugbridge.discoveryIpRangeMax.description = Used to limit the numbers of ips checked while discovering. +binding.config.androiddebugbridge.discoveryIpRangeMin.label = Discovery Range IP Min +binding.config.androiddebugbridge.discoveryIpRangeMin.description = Used to limit the numbers of ips checked while discovering. +binding.config.androiddebugbridge.discoveryPort.label = Discovery Port +binding.config.androiddebugbridge.discoveryPort.description = Port used on discovery to connect to the device through adb. +binding.config.androiddebugbridge.discoveryReachableMs.label = Discovery Reachable +binding.config.androiddebugbridge.discoveryReachableMs.description = Milliseconds to wait while discovering to determine if the ip is reachable. + +# thing types + +thing-type.androiddebugbridge.android.label = Android Device Thing +thing-type.androiddebugbridge.android.description = Android Device Thing for Android Debug Bridge Binding + +# thing types config + +thing-type.config.androiddebugbridge.android.ip.label = IP Address +thing-type.config.androiddebugbridge.android.ip.description = Device ip address. +thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.label = Media State Config +thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.description = JSON config that allows to modify the media state detection strategy for each app. Refer to the binding documentation. +thing-type.config.androiddebugbridge.android.port.label = Port +thing-type.config.androiddebugbridge.android.port.description = Device port listening to adb connections. +thing-type.config.androiddebugbridge.android.refreshTime.label = Refresh Time +thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes. +thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout +thing-type.config.androiddebugbridge.android.timeout.description = Command timeout seconds. + +# channel types + +channel-type.androiddebugbridge.awake-state-channel.label = Awake State +channel-type.androiddebugbridge.awake-state-channel.description = Awake State +channel-type.androiddebugbridge.current-package-channel.label = Current Package +channel-type.androiddebugbridge.current-package-channel.description = Package name of the top application in screen +channel-type.androiddebugbridge.key-event-channel.label = Send Key Event +channel-type.androiddebugbridge.key-event-channel.description = Send key event to android device +channel-type.androiddebugbridge.key-event-channel.state.option.7 = KEYCODE_0 +channel-type.androiddebugbridge.key-event-channel.state.option.8 = KEYCODE_1 +channel-type.androiddebugbridge.key-event-channel.state.option.227 = KEYCODE_11 +channel-type.androiddebugbridge.key-event-channel.state.option.228 = KEYCODE_12 +channel-type.androiddebugbridge.key-event-channel.state.option.9 = KEYCODE_2 +channel-type.androiddebugbridge.key-event-channel.state.option.10 = KEYCODE_3 +channel-type.androiddebugbridge.key-event-channel.state.option.206 = KEYCODE_3D_MODE +channel-type.androiddebugbridge.key-event-channel.state.option.11 = KEYCODE_4 +channel-type.androiddebugbridge.key-event-channel.state.option.12 = KEYCODE_5 +channel-type.androiddebugbridge.key-event-channel.state.option.13 = KEYCODE_6 +channel-type.androiddebugbridge.key-event-channel.state.option.14 = KEYCODE_7 +channel-type.androiddebugbridge.key-event-channel.state.option.15 = KEYCODE_8 +channel-type.androiddebugbridge.key-event-channel.state.option.16 = KEYCODE_9 +channel-type.androiddebugbridge.key-event-channel.state.option.29 = KEYCODE_A +channel-type.androiddebugbridge.key-event-channel.state.option.284 = KEYCODE_ALL_APPS +channel-type.androiddebugbridge.key-event-channel.state.option.57 = KEYCODE_ALT_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.58 = KEYCODE_ALT_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.75 = KEYCODE_APOSTROPHE +channel-type.androiddebugbridge.key-event-channel.state.option.187 = KEYCODE_APP_SWITCH +channel-type.androiddebugbridge.key-event-channel.state.option.219 = KEYCODE_ASSIST +channel-type.androiddebugbridge.key-event-channel.state.option.77 = KEYCODE_AT +channel-type.androiddebugbridge.key-event-channel.state.option.182 = KEYCODE_AVR_INPUT +channel-type.androiddebugbridge.key-event-channel.state.option.181 = KEYCODE_AVR_POWER +channel-type.androiddebugbridge.key-event-channel.state.option.30 = KEYCODE_B +channel-type.androiddebugbridge.key-event-channel.state.option.4 = KEYCODE_BACK +channel-type.androiddebugbridge.key-event-channel.state.option.73 = KEYCODE_BACKSLASH +channel-type.androiddebugbridge.key-event-channel.state.option.174 = KEYCODE_BOOKMARK +channel-type.androiddebugbridge.key-event-channel.state.option.121 = KEYCODE_BREAK +channel-type.androiddebugbridge.key-event-channel.state.option.220 = KEYCODE_BRIGHTNESS_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.221 = KEYCODE_BRIGHTNESS_UP +channel-type.androiddebugbridge.key-event-channel.state.option.188 = KEYCODE_BUTTON_1 +channel-type.androiddebugbridge.key-event-channel.state.option.197 = KEYCODE_BUTTON_10 +channel-type.androiddebugbridge.key-event-channel.state.option.198 = KEYCODE_BUTTON_11 +channel-type.androiddebugbridge.key-event-channel.state.option.199 = KEYCODE_BUTTON_12 +channel-type.androiddebugbridge.key-event-channel.state.option.200 = KEYCODE_BUTTON_13 +channel-type.androiddebugbridge.key-event-channel.state.option.201 = KEYCODE_BUTTON_14 +channel-type.androiddebugbridge.key-event-channel.state.option.202 = KEYCODE_BUTTON_15 +channel-type.androiddebugbridge.key-event-channel.state.option.203 = KEYCODE_BUTTON_16 +channel-type.androiddebugbridge.key-event-channel.state.option.189 = KEYCODE_BUTTON_2 +channel-type.androiddebugbridge.key-event-channel.state.option.190 = KEYCODE_BUTTON_3 +channel-type.androiddebugbridge.key-event-channel.state.option.191 = KEYCODE_BUTTON_4 +channel-type.androiddebugbridge.key-event-channel.state.option.192 = KEYCODE_BUTTON_5 +channel-type.androiddebugbridge.key-event-channel.state.option.193 = KEYCODE_BUTTON_6 +channel-type.androiddebugbridge.key-event-channel.state.option.194 = KEYCODE_BUTTON_7 +channel-type.androiddebugbridge.key-event-channel.state.option.195 = KEYCODE_BUTTON_8 +channel-type.androiddebugbridge.key-event-channel.state.option.196 = KEYCODE_BUTTON_9 +channel-type.androiddebugbridge.key-event-channel.state.option.96 = KEYCODE_BUTTON_A +channel-type.androiddebugbridge.key-event-channel.state.option.97 = KEYCODE_BUTTON_B +channel-type.androiddebugbridge.key-event-channel.state.option.98 = KEYCODE_BUTTON_C +channel-type.androiddebugbridge.key-event-channel.state.option.102 = KEYCODE_BUTTON_L1 +channel-type.androiddebugbridge.key-event-channel.state.option.104 = KEYCODE_BUTTON_L2 +channel-type.androiddebugbridge.key-event-channel.state.option.110 = KEYCODE_BUTTON_MODE +channel-type.androiddebugbridge.key-event-channel.state.option.103 = KEYCODE_BUTTON_R1 +channel-type.androiddebugbridge.key-event-channel.state.option.105 = KEYCODE_BUTTON_R2 +channel-type.androiddebugbridge.key-event-channel.state.option.109 = KEYCODE_BUTTON_SELECT +channel-type.androiddebugbridge.key-event-channel.state.option.108 = KEYCODE_BUTTON_START +channel-type.androiddebugbridge.key-event-channel.state.option.106 = KEYCODE_BUTTON_THUMBL +channel-type.androiddebugbridge.key-event-channel.state.option.107 = KEYCODE_BUTTON_THUMBR +channel-type.androiddebugbridge.key-event-channel.state.option.99 = KEYCODE_BUTTON_X +channel-type.androiddebugbridge.key-event-channel.state.option.100 = KEYCODE_BUTTON_Y +channel-type.androiddebugbridge.key-event-channel.state.option.101 = KEYCODE_BUTTON_Z +channel-type.androiddebugbridge.key-event-channel.state.option.31 = KEYCODE_C +channel-type.androiddebugbridge.key-event-channel.state.option.210 = KEYCODE_CALCULATOR +channel-type.androiddebugbridge.key-event-channel.state.option.208 = KEYCODE_CALENDAR +channel-type.androiddebugbridge.key-event-channel.state.option.5 = KEYCODE_CALL +channel-type.androiddebugbridge.key-event-channel.state.option.27 = KEYCODE_CAMERA +channel-type.androiddebugbridge.key-event-channel.state.option.115 = KEYCODE_CAPS_LOCK +channel-type.androiddebugbridge.key-event-channel.state.option.175 = KEYCODE_CAPTIONS +channel-type.androiddebugbridge.key-event-channel.state.option.167 = KEYCODE_CHANNEL_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.166 = KEYCODE_CHANNEL_UP +channel-type.androiddebugbridge.key-event-channel.state.option.28 = KEYCODE_CLEAR +channel-type.androiddebugbridge.key-event-channel.state.option.55 = KEYCODE_COMMA +channel-type.androiddebugbridge.key-event-channel.state.option.207 = KEYCODE_CONTACTS +channel-type.androiddebugbridge.key-event-channel.state.option.278 = KEYCODE_COPY +channel-type.androiddebugbridge.key-event-channel.state.option.113 = KEYCODE_CTRL_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.114 = KEYCODE_CTRL_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.277 = KEYCODE_CUT +channel-type.androiddebugbridge.key-event-channel.state.option.32 = KEYCODE_D +channel-type.androiddebugbridge.key-event-channel.state.option.67 = KEYCODE_DEL +channel-type.androiddebugbridge.key-event-channel.state.option.23 = KEYCODE_DPAD_CENTER +channel-type.androiddebugbridge.key-event-channel.state.option.20 = KEYCODE_DPAD_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.269 = KEYCODE_DPAD_DOWN_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.271 = KEYCODE_DPAD_DOWN_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.21 = KEYCODE_DPAD_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.22 = KEYCODE_DPAD_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.19 = KEYCODE_DPAD_UP +channel-type.androiddebugbridge.key-event-channel.state.option.268 = KEYCODE_DPAD_UP_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.270 = KEYCODE_DPAD_UP_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.173 = KEYCODE_DVR +channel-type.androiddebugbridge.key-event-channel.state.option.33 = KEYCODE_E +channel-type.androiddebugbridge.key-event-channel.state.option.212 = KEYCODE_EISU +channel-type.androiddebugbridge.key-event-channel.state.option.6 = KEYCODE_ENDCALL +channel-type.androiddebugbridge.key-event-channel.state.option.66 = KEYCODE_ENTER +channel-type.androiddebugbridge.key-event-channel.state.option.65 = KEYCODE_ENVELOPE +channel-type.androiddebugbridge.key-event-channel.state.option.70 = KEYCODE_EQUALS +channel-type.androiddebugbridge.key-event-channel.state.option.111 = KEYCODE_ESCAPE +channel-type.androiddebugbridge.key-event-channel.state.option.64 = KEYCODE_EXPLORER +channel-type.androiddebugbridge.key-event-channel.state.option.34 = KEYCODE_F +channel-type.androiddebugbridge.key-event-channel.state.option.131 = KEYCODE_F1 +channel-type.androiddebugbridge.key-event-channel.state.option.140 = KEYCODE_F10 +channel-type.androiddebugbridge.key-event-channel.state.option.141 = KEYCODE_F11 +channel-type.androiddebugbridge.key-event-channel.state.option.142 = KEYCODE_F12 +channel-type.androiddebugbridge.key-event-channel.state.option.132 = KEYCODE_F2 +channel-type.androiddebugbridge.key-event-channel.state.option.133 = KEYCODE_F3 +channel-type.androiddebugbridge.key-event-channel.state.option.134 = KEYCODE_F4 +channel-type.androiddebugbridge.key-event-channel.state.option.135 = KEYCODE_F5 +channel-type.androiddebugbridge.key-event-channel.state.option.136 = KEYCODE_F6 +channel-type.androiddebugbridge.key-event-channel.state.option.137 = KEYCODE_F7 +channel-type.androiddebugbridge.key-event-channel.state.option.138 = KEYCODE_F8 +channel-type.androiddebugbridge.key-event-channel.state.option.139 = KEYCODE_F9 +channel-type.androiddebugbridge.key-event-channel.state.option.80 = KEYCODE_FOCUS +channel-type.androiddebugbridge.key-event-channel.state.option.125 = KEYCODE_FORWARD +channel-type.androiddebugbridge.key-event-channel.state.option.112 = KEYCODE_FORWARD_DEL +channel-type.androiddebugbridge.key-event-channel.state.option.119 = KEYCODE_FUNCTION +channel-type.androiddebugbridge.key-event-channel.state.option.35 = KEYCODE_G +channel-type.androiddebugbridge.key-event-channel.state.option.68 = KEYCODE_GRAVE +channel-type.androiddebugbridge.key-event-channel.state.option.172 = KEYCODE_GUIDE +channel-type.androiddebugbridge.key-event-channel.state.option.36 = KEYCODE_H +channel-type.androiddebugbridge.key-event-channel.state.option.79 = KEYCODE_HEADSETHOOK +channel-type.androiddebugbridge.key-event-channel.state.option.259 = KEYCODE_HELP +channel-type.androiddebugbridge.key-event-channel.state.option.214 = KEYCODE_HENKAN +channel-type.androiddebugbridge.key-event-channel.state.option.3 = KEYCODE_HOME +channel-type.androiddebugbridge.key-event-channel.state.option.37 = KEYCODE_I +channel-type.androiddebugbridge.key-event-channel.state.option.165 = KEYCODE_INFO +channel-type.androiddebugbridge.key-event-channel.state.option.124 = KEYCODE_INSERT +channel-type.androiddebugbridge.key-event-channel.state.option.38 = KEYCODE_J +channel-type.androiddebugbridge.key-event-channel.state.option.39 = KEYCODE_K +channel-type.androiddebugbridge.key-event-channel.state.option.218 = KEYCODE_KANA +channel-type.androiddebugbridge.key-event-channel.state.option.215 = KEYCODE_KATAKANA_HIRAGANA +channel-type.androiddebugbridge.key-event-channel.state.option.40 = KEYCODE_L +channel-type.androiddebugbridge.key-event-channel.state.option.204 = KEYCODE_LANGUAGE_SWITCH +channel-type.androiddebugbridge.key-event-channel.state.option.229 = KEYCODE_LAST_CHANNEL +channel-type.androiddebugbridge.key-event-channel.state.option.71 = KEYCODE_LEFT_BRACKET +channel-type.androiddebugbridge.key-event-channel.state.option.41 = KEYCODE_M +channel-type.androiddebugbridge.key-event-channel.state.option.205 = KEYCODE_MANNER_MODE +channel-type.androiddebugbridge.key-event-channel.state.option.222 = KEYCODE_MEDIA_AUDIO_TRACK +channel-type.androiddebugbridge.key-event-channel.state.option.128 = KEYCODE_MEDIA_CLOSE +channel-type.androiddebugbridge.key-event-channel.state.option.129 = KEYCODE_MEDIA_EJECT +channel-type.androiddebugbridge.key-event-channel.state.option.90 = KEYCODE_MEDIA_FAST_FORWARD +channel-type.androiddebugbridge.key-event-channel.state.option.87 = KEYCODE_MEDIA_NEXT +channel-type.androiddebugbridge.key-event-channel.state.option.127 = KEYCODE_MEDIA_PAUSE +channel-type.androiddebugbridge.key-event-channel.state.option.126 = KEYCODE_MEDIA_PLAY +channel-type.androiddebugbridge.key-event-channel.state.option.85 = KEYCODE_MEDIA_PLAY_PAUSE +channel-type.androiddebugbridge.key-event-channel.state.option.88 = KEYCODE_MEDIA_PREVIOUS +channel-type.androiddebugbridge.key-event-channel.state.option.130 = KEYCODE_MEDIA_RECORD +channel-type.androiddebugbridge.key-event-channel.state.option.89 = KEYCODE_MEDIA_REWIND +channel-type.androiddebugbridge.key-event-channel.state.option.273 = KEYCODE_MEDIA_SKIP_BACKWARD +channel-type.androiddebugbridge.key-event-channel.state.option.272 = KEYCODE_MEDIA_SKIP_FORWARD +channel-type.androiddebugbridge.key-event-channel.state.option.275 = KEYCODE_MEDIA_STEP_BACKWARD +channel-type.androiddebugbridge.key-event-channel.state.option.274 = KEYCODE_MEDIA_STEP_FORWARD +channel-type.androiddebugbridge.key-event-channel.state.option.86 = KEYCODE_MEDIA_STOP +channel-type.androiddebugbridge.key-event-channel.state.option.226 = KEYCODE_MEDIA_TOP_MENU +channel-type.androiddebugbridge.key-event-channel.state.option.82 = KEYCODE_MENU +channel-type.androiddebugbridge.key-event-channel.state.option.117 = KEYCODE_META_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.118 = KEYCODE_META_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.69 = KEYCODE_MINUS +channel-type.androiddebugbridge.key-event-channel.state.option.123 = KEYCODE_MOVE_END +channel-type.androiddebugbridge.key-event-channel.state.option.122 = KEYCODE_MOVE_HOME +channel-type.androiddebugbridge.key-event-channel.state.option.213 = KEYCODE_MUHENKAN +channel-type.androiddebugbridge.key-event-channel.state.option.209 = KEYCODE_MUSIC +channel-type.androiddebugbridge.key-event-channel.state.option.91 = KEYCODE_MUTE +channel-type.androiddebugbridge.key-event-channel.state.option.42 = KEYCODE_N +channel-type.androiddebugbridge.key-event-channel.state.option.262 = KEYCODE_NAVIGATE_IN +channel-type.androiddebugbridge.key-event-channel.state.option.261 = KEYCODE_NAVIGATE_NEXT +channel-type.androiddebugbridge.key-event-channel.state.option.263 = KEYCODE_NAVIGATE_OUT +channel-type.androiddebugbridge.key-event-channel.state.option.260 = KEYCODE_NAVIGATE_PREVIOUS +channel-type.androiddebugbridge.key-event-channel.state.option.83 = KEYCODE_NOTIFICATION +channel-type.androiddebugbridge.key-event-channel.state.option.78 = KEYCODE_NUM +channel-type.androiddebugbridge.key-event-channel.state.option.144 = KEYCODE_NUMPAD_0 +channel-type.androiddebugbridge.key-event-channel.state.option.145 = KEYCODE_NUMPAD_1 +channel-type.androiddebugbridge.key-event-channel.state.option.146 = KEYCODE_NUMPAD_2 +channel-type.androiddebugbridge.key-event-channel.state.option.147 = KEYCODE_NUMPAD_3 +channel-type.androiddebugbridge.key-event-channel.state.option.148 = KEYCODE_NUMPAD_4 +channel-type.androiddebugbridge.key-event-channel.state.option.149 = KEYCODE_NUMPAD_5 +channel-type.androiddebugbridge.key-event-channel.state.option.150 = KEYCODE_NUMPAD_6 +channel-type.androiddebugbridge.key-event-channel.state.option.151 = KEYCODE_NUMPAD_7 +channel-type.androiddebugbridge.key-event-channel.state.option.152 = KEYCODE_NUMPAD_8 +channel-type.androiddebugbridge.key-event-channel.state.option.153 = KEYCODE_NUMPAD_9 +channel-type.androiddebugbridge.key-event-channel.state.option.157 = KEYCODE_NUMPAD_ADD +channel-type.androiddebugbridge.key-event-channel.state.option.159 = KEYCODE_NUMPAD_COMMA +channel-type.androiddebugbridge.key-event-channel.state.option.154 = KEYCODE_NUMPAD_DIVIDE +channel-type.androiddebugbridge.key-event-channel.state.option.158 = KEYCODE_NUMPAD_DOT +channel-type.androiddebugbridge.key-event-channel.state.option.160 = KEYCODE_NUMPAD_ENTER +channel-type.androiddebugbridge.key-event-channel.state.option.161 = KEYCODE_NUMPAD_EQUALS +channel-type.androiddebugbridge.key-event-channel.state.option.162 = KEYCODE_NUMPAD_LEFT_PAREN +channel-type.androiddebugbridge.key-event-channel.state.option.155 = KEYCODE_NUMPAD_MULTIPLY +channel-type.androiddebugbridge.key-event-channel.state.option.163 = KEYCODE_NUMPAD_RIGHT_PAREN +channel-type.androiddebugbridge.key-event-channel.state.option.156 = KEYCODE_NUMPAD_SUBTRACT +channel-type.androiddebugbridge.key-event-channel.state.option.143 = KEYCODE_NUM_LOCK +channel-type.androiddebugbridge.key-event-channel.state.option.43 = KEYCODE_O +channel-type.androiddebugbridge.key-event-channel.state.option.44 = KEYCODE_P +channel-type.androiddebugbridge.key-event-channel.state.option.93 = KEYCODE_PAGE_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.92 = KEYCODE_PAGE_UP +channel-type.androiddebugbridge.key-event-channel.state.option.225 = KEYCODE_PAIRING +channel-type.androiddebugbridge.key-event-channel.state.option.279 = KEYCODE_PASTE +channel-type.androiddebugbridge.key-event-channel.state.option.56 = KEYCODE_PERIOD +channel-type.androiddebugbridge.key-event-channel.state.option.94 = KEYCODE_PICTSYMBOLS +channel-type.androiddebugbridge.key-event-channel.state.option.81 = KEYCODE_PLUS +channel-type.androiddebugbridge.key-event-channel.state.option.18 = KEYCODE_POUND +channel-type.androiddebugbridge.key-event-channel.state.option.26 = KEYCODE_POWER +channel-type.androiddebugbridge.key-event-channel.state.option.288 = KEYCODE_PROFILE_SWITCH +channel-type.androiddebugbridge.key-event-channel.state.option.186 = KEYCODE_PROG_BLUE +channel-type.androiddebugbridge.key-event-channel.state.option.184 = KEYCODE_PROG_GREEN +channel-type.androiddebugbridge.key-event-channel.state.option.183 = KEYCODE_PROG_RED +channel-type.androiddebugbridge.key-event-channel.state.option.185 = KEYCODE_PROG_YELLOW +channel-type.androiddebugbridge.key-event-channel.state.option.45 = KEYCODE_Q +channel-type.androiddebugbridge.key-event-channel.state.option.46 = KEYCODE_R +channel-type.androiddebugbridge.key-event-channel.state.option.285 = KEYCODE_REFRESH +channel-type.androiddebugbridge.key-event-channel.state.option.72 = KEYCODE_RIGHT_BRACKET +channel-type.androiddebugbridge.key-event-channel.state.option.217 = KEYCODE_RO +channel-type.androiddebugbridge.key-event-channel.state.option.47 = KEYCODE_S +channel-type.androiddebugbridge.key-event-channel.state.option.116 = KEYCODE_SCROLL_LOCK +channel-type.androiddebugbridge.key-event-channel.state.option.84 = KEYCODE_SEARCH +channel-type.androiddebugbridge.key-event-channel.state.option.74 = KEYCODE_SEMICOLON +channel-type.androiddebugbridge.key-event-channel.state.option.176 = KEYCODE_SETTINGS +channel-type.androiddebugbridge.key-event-channel.state.option.59 = KEYCODE_SHIFT_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.60 = KEYCODE_SHIFT_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.76 = KEYCODE_SLASH +channel-type.androiddebugbridge.key-event-channel.state.option.223 = KEYCODE_SLEEP +channel-type.androiddebugbridge.key-event-channel.state.option.1 = KEYCODE_SOFT_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.2 = KEYCODE_SOFT_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.276 = KEYCODE_SOFT_SLEEP +channel-type.androiddebugbridge.key-event-channel.state.option.62 = KEYCODE_SPACE +channel-type.androiddebugbridge.key-event-channel.state.option.17 = KEYCODE_STAR +channel-type.androiddebugbridge.key-event-channel.state.option.180 = KEYCODE_STB_INPUT +channel-type.androiddebugbridge.key-event-channel.state.option.179 = KEYCODE_STB_POWER +channel-type.androiddebugbridge.key-event-channel.state.option.265 = KEYCODE_STEM_1 +channel-type.androiddebugbridge.key-event-channel.state.option.266 = KEYCODE_STEM_2 +channel-type.androiddebugbridge.key-event-channel.state.option.267 = KEYCODE_STEM_3 +channel-type.androiddebugbridge.key-event-channel.state.option.264 = KEYCODE_STEM_PRIMARY +channel-type.androiddebugbridge.key-event-channel.state.option.95 = KEYCODE_SWITCH_CHARSET +channel-type.androiddebugbridge.key-event-channel.state.option.63 = KEYCODE_SYM +channel-type.androiddebugbridge.key-event-channel.state.option.120 = KEYCODE_SYSRQ +channel-type.androiddebugbridge.key-event-channel.state.option.281 = KEYCODE_SYSTEM_NAVIGATION_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.282 = KEYCODE_SYSTEM_NAVIGATION_LEFT +channel-type.androiddebugbridge.key-event-channel.state.option.283 = KEYCODE_SYSTEM_NAVIGATION_RIGHT +channel-type.androiddebugbridge.key-event-channel.state.option.280 = KEYCODE_SYSTEM_NAVIGATION_UP +channel-type.androiddebugbridge.key-event-channel.state.option.48 = KEYCODE_T +channel-type.androiddebugbridge.key-event-channel.state.option.61 = KEYCODE_TAB +channel-type.androiddebugbridge.key-event-channel.state.option.287 = KEYCODE_THUMBS_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.286 = KEYCODE_THUMBS_UP +channel-type.androiddebugbridge.key-event-channel.state.option.170 = KEYCODE_TV +channel-type.androiddebugbridge.key-event-channel.state.option.242 = KEYCODE_TV_ANTENNA_CABLE +channel-type.androiddebugbridge.key-event-channel.state.option.252 = KEYCODE_TV_AUDIO_DESCRIPTION +channel-type.androiddebugbridge.key-event-channel.state.option.254 = KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.253 = KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP +channel-type.androiddebugbridge.key-event-channel.state.option.256 = KEYCODE_TV_CONTENTS_MENU +channel-type.androiddebugbridge.key-event-channel.state.option.230 = KEYCODE_TV_DATA_SERVICE +channel-type.androiddebugbridge.key-event-channel.state.option.178 = KEYCODE_TV_INPUT +channel-type.androiddebugbridge.key-event-channel.state.option.249 = KEYCODE_TV_INPUT_COMPONENT_1 +channel-type.androiddebugbridge.key-event-channel.state.option.250 = KEYCODE_TV_INPUT_COMPONENT_2 +channel-type.androiddebugbridge.key-event-channel.state.option.247 = KEYCODE_TV_INPUT_COMPOSITE_1 +channel-type.androiddebugbridge.key-event-channel.state.option.248 = KEYCODE_TV_INPUT_COMPOSITE_2 +channel-type.androiddebugbridge.key-event-channel.state.option.243 = KEYCODE_TV_INPUT_HDMI_1 +channel-type.androiddebugbridge.key-event-channel.state.option.244 = KEYCODE_TV_INPUT_HDMI_2 +channel-type.androiddebugbridge.key-event-channel.state.option.245 = KEYCODE_TV_INPUT_HDMI_3 +channel-type.androiddebugbridge.key-event-channel.state.option.246 = KEYCODE_TV_INPUT_HDMI_4 +channel-type.androiddebugbridge.key-event-channel.state.option.251 = KEYCODE_TV_INPUT_VGA_1 +channel-type.androiddebugbridge.key-event-channel.state.option.257 = KEYCODE_TV_MEDIA_CONTEXT_MENU +channel-type.androiddebugbridge.key-event-channel.state.option.241 = KEYCODE_TV_NETWORK +channel-type.androiddebugbridge.key-event-channel.state.option.234 = KEYCODE_TV_NUMBER_ENTRY +channel-type.androiddebugbridge.key-event-channel.state.option.177 = KEYCODE_TV_POWER +channel-type.androiddebugbridge.key-event-channel.state.option.232 = KEYCODE_TV_RADIO_SERVICE +channel-type.androiddebugbridge.key-event-channel.state.option.237 = KEYCODE_TV_SATELLITE +channel-type.androiddebugbridge.key-event-channel.state.option.238 = KEYCODE_TV_SATELLITE_BS +channel-type.androiddebugbridge.key-event-channel.state.option.239 = KEYCODE_TV_SATELLITE_CS +channel-type.androiddebugbridge.key-event-channel.state.option.240 = KEYCODE_TV_SATELLITE_SERVICE +channel-type.androiddebugbridge.key-event-channel.state.option.233 = KEYCODE_TV_TELETEXT +channel-type.androiddebugbridge.key-event-channel.state.option.235 = KEYCODE_TV_TERRESTRIAL_ANALOG +channel-type.androiddebugbridge.key-event-channel.state.option.236 = KEYCODE_TV_TERRESTRIAL_DIGITAL +channel-type.androiddebugbridge.key-event-channel.state.option.258 = KEYCODE_TV_TIMER_PROGRAMMING +channel-type.androiddebugbridge.key-event-channel.state.option.255 = KEYCODE_TV_ZOOM_MODE +channel-type.androiddebugbridge.key-event-channel.state.option.49 = KEYCODE_U +channel-type.androiddebugbridge.key-event-channel.state.option.0 = KEYCODE_UNKNOWN +channel-type.androiddebugbridge.key-event-channel.state.option.50 = KEYCODE_V +channel-type.androiddebugbridge.key-event-channel.state.option.231 = KEYCODE_VOICE_ASSIST +channel-type.androiddebugbridge.key-event-channel.state.option.25 = KEYCODE_VOLUME_DOWN +channel-type.androiddebugbridge.key-event-channel.state.option.164 = KEYCODE_VOLUME_MUTE +channel-type.androiddebugbridge.key-event-channel.state.option.24 = KEYCODE_VOLUME_UP +channel-type.androiddebugbridge.key-event-channel.state.option.51 = KEYCODE_W +channel-type.androiddebugbridge.key-event-channel.state.option.224 = KEYCODE_WAKEUP +channel-type.androiddebugbridge.key-event-channel.state.option.171 = KEYCODE_WINDOW +channel-type.androiddebugbridge.key-event-channel.state.option.52 = KEYCODE_X +channel-type.androiddebugbridge.key-event-channel.state.option.53 = KEYCODE_Y +channel-type.androiddebugbridge.key-event-channel.state.option.216 = KEYCODE_YEN +channel-type.androiddebugbridge.key-event-channel.state.option.54 = KEYCODE_Z +channel-type.androiddebugbridge.key-event-channel.state.option.211 = KEYCODE_ZENKAKU_HANKAKU +channel-type.androiddebugbridge.key-event-channel.state.option.168 = KEYCODE_ZOOM_IN +channel-type.androiddebugbridge.key-event-channel.state.option.16 = KEYCODE_ZOOM_OUT +channel-type.androiddebugbridge.screen-state-channel.label = Screen State +channel-type.androiddebugbridge.screen-state-channel.description = Screen Power State +channel-type.androiddebugbridge.shutdown-channel.label = Shutdown +channel-type.androiddebugbridge.shutdown-channel.description = Shutdown/Reboot Device +channel-type.androiddebugbridge.shutdown-channel.state.option.POWER_OFF = POWER_OFF +channel-type.androiddebugbridge.shutdown-channel.state.option.REBOOT = REBOOT +channel-type.androiddebugbridge.start-package-channel.label = Start Package +channel-type.androiddebugbridge.start-package-channel.description = Run application by package name +channel-type.androiddebugbridge.stop-current-package-channel.label = Stop Current Package +channel-type.androiddebugbridge.stop-current-package-channel.description = Stops the top application in screen when receives an OFF command +channel-type.androiddebugbridge.stop-package-channel.label = Stop Package +channel-type.androiddebugbridge.stop-package-channel.description = Stop application by package name +channel-type.androiddebugbridge.tap-channel.label = Send Tap +channel-type.androiddebugbridge.tap-channel.description = Send tap event to android device +channel-type.androiddebugbridge.text-channel.label = Send Text +channel-type.androiddebugbridge.text-channel.description = Send text to android device +channel-type.androiddebugbridge.wake-lock-channel.label = Wake Lock +channel-type.androiddebugbridge.wake-lock-channel.description = Power Wake Lock State diff --git a/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/i18n/anel.properties b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/i18n/anel.properties new file mode 100644 index 0000000000000..022b05c3e08b2 --- /dev/null +++ b/bundles/org.openhab.binding.anel/src/main/resources/OH-INF/i18n/anel.properties @@ -0,0 +1,62 @@ +# binding + +binding.anel.name = Anel NET-PwrCtrl Binding +binding.anel.description = This is the binding for Anel NET-PwrCtrl devices. + +# thing types + +thing-type.anel.advanced-firmware.label = ADV / IO / HUT +thing-type.anel.advanced-firmware.description = Anel device with 8 controllable outlets / relays and possibly 8 IO ports. +thing-type.anel.home.label = HOME +thing-type.anel.home.description = Anel device with 3 controllable outlets without IO ports. +thing-type.anel.simple-firmware.label = PRO / POWER +thing-type.anel.simple-firmware.description = Anel device with 8 controllable outlets without IO ports. + +# thing types config + +thing-type.config.anel.config.hostname.label = Hostname / IP address +thing-type.config.anel.config.hostname.description = Hostname or IP address of the device +thing-type.config.anel.config.password.label = Password +thing-type.config.anel.config.password.description = Password to access the device +thing-type.config.anel.config.udpReceivePort.label = Receive Port +thing-type.config.anel.config.udpReceivePort.description = UDP port to receive data from the device (in the anel web UI, it's the send port!) +thing-type.config.anel.config.udpSendPort.label = Send Port +thing-type.config.anel.config.udpSendPort.description = UDP port to send data to the device (in the anel web UI, it's the receive port!) +thing-type.config.anel.config.user.label = User +thing-type.config.anel.config.user.description = User to access the device (make sure it has rights to change relay / IO states!) + +# channel group types + +channel-group-type.anel.ioGroup.label = I/O Port +channel-group-type.anel.ioGroup.description = An Input / Output Port +channel-group-type.anel.propertiesGroup.label = Device Properties +channel-group-type.anel.propertiesGroup.description = Device properties +channel-group-type.anel.relayGroup.label = Relay / Socket +channel-group-type.anel.relayGroup.description = A relay / socket +channel-group-type.anel.sensorGroup.label = Sensor +channel-group-type.anel.sensorGroup.description = Optional sensor values + +# channel types + +channel-type.anel.ioMode-channel.label = IO is Input +channel-type.anel.ioMode-channel.description = Whether the port is configured as input (true) or output (false) +channel-type.anel.ioName-channel.label = IO Name +channel-type.anel.ioName-channel.description = The name of the I/O port +channel-type.anel.ioState-channel.label = IO State +channel-type.anel.ioState-channel.description = The state of the I/O port (read-only for input ports) +channel-type.anel.name-channel.label = Device Name +channel-type.anel.name-channel.description = The name of the Anel device +channel-type.anel.relayLocked-channel.label = Relay Locked +channel-type.anel.relayLocked-channel.description = Whether or not the relay is locked +channel-type.anel.relayName-channel.label = Relay Name +channel-type.anel.relayName-channel.description = The name of the relay / socket +channel-type.anel.relayState-channel.label = Relay State +channel-type.anel.relayState-channel.description = The state of the relay / socket (read-only if locked!) +channel-type.anel.sensorBrightness-channel.label = Sensor Brightness +channel-type.anel.sensorBrightness-channel.description = The brightness value of the optional sensor +channel-type.anel.sensorHumidity-channel.label = Sensor Humidity +channel-type.anel.sensorHumidity-channel.description = The humidity value of the optional sensor +channel-type.anel.sensorTemperature-channel.label = Sensor Temperature +channel-type.anel.sensorTemperature-channel.description = The temperature value of the optional sensor +channel-type.anel.temperature-channel.label = Anel Device Temperature +channel-type.anel.temperature-channel.description = The value of the built-in temperature sensor of the Anel device diff --git a/bundles/org.openhab.binding.atlona/src/main/resources/OH-INF/i18n/atlona.properties b/bundles/org.openhab.binding.atlona/src/main/resources/OH-INF/i18n/atlona.properties new file mode 100644 index 0000000000000..219e576c30af6 --- /dev/null +++ b/bundles/org.openhab.binding.atlona/src/main/resources/OH-INF/i18n/atlona.properties @@ -0,0 +1,236 @@ +# binding + +binding.atlona.name = Atlona Products +binding.atlona.description = Binding for Atlona PRO3 HDBaseT Matrix switches. + +# thing types + +thing-type.atlona.pro3-1616m.label = Atlona Pro3 16x16 HDBaseT Matrix +thing-type.atlona.pro3-1616m.description = Atlona Pro3 16x16 HDBaseT Matrix (Model AT-UHD-PRO3-1616M) +thing-type.atlona.pro3-1616m.group.mirror17.label = HDMI Port 17 +thing-type.atlona.pro3-1616m.group.mirror17.description = HDMI Port 17 Mirroring Channels +thing-type.atlona.pro3-1616m.group.mirror18.label = HDMI Port 18 +thing-type.atlona.pro3-1616m.group.mirror18.description = HDMI Port 18 Mirroring Channels +thing-type.atlona.pro3-1616m.group.mirror19.label = HDMI Port 19 +thing-type.atlona.pro3-1616m.group.mirror19.description = HDMI Port 19 Mirroring Channels +thing-type.atlona.pro3-1616m.group.mirror20.label = HDMI Port 20 +thing-type.atlona.pro3-1616m.group.mirror20.description = HDMI Port 20 Mirroring Channels +thing-type.atlona.pro3-1616m.group.port1.label = Port 1 +thing-type.atlona.pro3-1616m.group.port1.description = Output Port 1 Channels +thing-type.atlona.pro3-1616m.group.port2.label = Port 2 +thing-type.atlona.pro3-1616m.group.port2.description = Output Port 2 Channels +thing-type.atlona.pro3-1616m.group.port3.label = Port 3 +thing-type.atlona.pro3-1616m.group.port3.description = Output Port 3 Channels +thing-type.atlona.pro3-1616m.group.port4.label = Port 4 +thing-type.atlona.pro3-1616m.group.port4.description = Output Port 4 Channels +thing-type.atlona.pro3-1616m.group.port5.label = Port 5 +thing-type.atlona.pro3-1616m.group.port5.description = Output Port 5 Channels +thing-type.atlona.pro3-1616m.group.port6.label = Port 6 +thing-type.atlona.pro3-1616m.group.port6.description = Output Port 6 Channels +thing-type.atlona.pro3-1616m.group.port7.label = Port 7 +thing-type.atlona.pro3-1616m.group.port7.description = Output Port 7 Channels +thing-type.atlona.pro3-1616m.group.port8.label = Port 8 +thing-type.atlona.pro3-1616m.group.port8.description = Output Port 8 Channels +thing-type.atlona.pro3-1616m.group.port9.label = Port 9 +thing-type.atlona.pro3-1616m.group.port9.description = Output Port 9 Channels +thing-type.atlona.pro3-1616m.group.port10.label = Port 10 +thing-type.atlona.pro3-1616m.group.port10.description = Output Port 10 Channels +thing-type.atlona.pro3-1616m.group.port11.label = Port 11 +thing-type.atlona.pro3-1616m.group.port11.description = Output Port 11 Channels +thing-type.atlona.pro3-1616m.group.port12.label = Port 12 +thing-type.atlona.pro3-1616m.group.port12.description = Output Port 12 Channels +thing-type.atlona.pro3-1616m.group.port13.label = Port 13 +thing-type.atlona.pro3-1616m.group.port13.description = Output Port 13 Channels +thing-type.atlona.pro3-1616m.group.port14.label = Port 14 +thing-type.atlona.pro3-1616m.group.port14.description = Output Port 14 Channels +thing-type.atlona.pro3-1616m.group.port15.label = Port 15 +thing-type.atlona.pro3-1616m.group.port15.description = Output Port 15 Channels +thing-type.atlona.pro3-1616m.group.port16.label = Port 16 +thing-type.atlona.pro3-1616m.group.port16.description = Output Port 16 Channels +thing-type.atlona.pro3-1616m.group.port17.label = Port 17 +thing-type.atlona.pro3-1616m.group.port17.description = Output Port 17 Channels +thing-type.atlona.pro3-1616m.group.port18.label = Port 18 +thing-type.atlona.pro3-1616m.group.port18.description = Output Port 18 Channels +thing-type.atlona.pro3-1616m.group.port19.label = Port 19 +thing-type.atlona.pro3-1616m.group.port19.description = Output Port 19 Channels +thing-type.atlona.pro3-1616m.group.port20.label = Port 20 +thing-type.atlona.pro3-1616m.group.port20.description = Output Port 20 Channels +thing-type.atlona.pro3-1616m.group.volume1.label = Volume 1 +thing-type.atlona.pro3-1616m.group.volume1.description = Volume 1 channels +thing-type.atlona.pro3-1616m.group.volume2.label = Volume 2 +thing-type.atlona.pro3-1616m.group.volume2.description = Volume 2 channels +thing-type.atlona.pro3-1616m.group.volume3.label = Volume 3 +thing-type.atlona.pro3-1616m.group.volume3.description = Volume 3 channels +thing-type.atlona.pro3-1616m.group.volume4.label = Volume 4 +thing-type.atlona.pro3-1616m.group.volume4.description = Volume 4 channels +thing-type.atlona.pro3-1616m.group.volume5.label = Volume 5 +thing-type.atlona.pro3-1616m.group.volume5.description = Volume 5 channels +thing-type.atlona.pro3-1616m.group.volume6.label = Volume 6 +thing-type.atlona.pro3-1616m.group.volume6.description = Volume 6 channels +thing-type.atlona.pro3-1616m.group.volume7.label = Volume 7 +thing-type.atlona.pro3-1616m.group.volume7.description = Volume 7 channels +thing-type.atlona.pro3-1616m.group.volume8.label = Volume 8 +thing-type.atlona.pro3-1616m.group.volume8.description = Volume 8 channels +thing-type.atlona.pro3-1616m.group.volume9.label = Volume 9 +thing-type.atlona.pro3-1616m.group.volume9.description = Volume 9 channels +thing-type.atlona.pro3-1616m.group.volume10.label = Volume 10 +thing-type.atlona.pro3-1616m.group.volume10.description = Volume 10 channels +thing-type.atlona.pro3-1616m.group.volume11.label = Volume 11 +thing-type.atlona.pro3-1616m.group.volume11.description = Volume 11 channels +thing-type.atlona.pro3-1616m.group.volume12.label = Volume 12 +thing-type.atlona.pro3-1616m.group.volume12.description = Volume 12 channels +thing-type.atlona.pro3-44m.label = Atlona Pro3 4x4 HDBaseT Matrix +thing-type.atlona.pro3-44m.description = Atlona Pro3 4x4 HDBaseT Matrix (Model AT-UHD-PRO3-44M) +thing-type.atlona.pro3-44m.group.mirror5.label = HDMI Port 5 +thing-type.atlona.pro3-44m.group.mirror5.description = HDMI Port 5 Mirroring Channels +thing-type.atlona.pro3-44m.group.port1.label = Port 1 +thing-type.atlona.pro3-44m.group.port1.description = Output Port 1 Channels +thing-type.atlona.pro3-44m.group.port2.label = Port 2 +thing-type.atlona.pro3-44m.group.port2.description = Output Port 2 Channels +thing-type.atlona.pro3-44m.group.port3.label = Port 3 +thing-type.atlona.pro3-44m.group.port3.description = Output Port 3 Channels +thing-type.atlona.pro3-44m.group.port4.label = Port 4 +thing-type.atlona.pro3-44m.group.port4.description = Output Port 4 Channels +thing-type.atlona.pro3-44m.group.port5.label = Port 5 +thing-type.atlona.pro3-44m.group.port5.description = Output Port 5 Channels +thing-type.atlona.pro3-44m.group.volume1.label = Volume 1 +thing-type.atlona.pro3-44m.group.volume1.description = Volume 1 channels +thing-type.atlona.pro3-44m.group.volume2.label = Volume 2 +thing-type.atlona.pro3-44m.group.volume2.description = Volume 2 channels +thing-type.atlona.pro3-44m.group.volume3.label = Volume 3 +thing-type.atlona.pro3-44m.group.volume3.description = Volume 3 channels +thing-type.atlona.pro3-66m.label = Atlona Pro3 6x6 HDBaseT Matrix +thing-type.atlona.pro3-66m.description = Atlona Pro3 6x6 HDBaseT Matrix (Model AT-UHD-PRO3-66M) +thing-type.atlona.pro3-66m.group.mirror6.label = HDMI Port 6 +thing-type.atlona.pro3-66m.group.mirror6.description = HDMI Port 6 Mirroring Channels +thing-type.atlona.pro3-66m.group.mirror8.label = HDMI Port 8 +thing-type.atlona.pro3-66m.group.mirror8.description = HDMI Port 8 Mirroring Channels +thing-type.atlona.pro3-66m.group.port1.label = Port 1 +thing-type.atlona.pro3-66m.group.port1.description = Output Port 1 Channels +thing-type.atlona.pro3-66m.group.port2.label = Port 2 +thing-type.atlona.pro3-66m.group.port2.description = Output Port 2 Channels +thing-type.atlona.pro3-66m.group.port3.label = Port 3 +thing-type.atlona.pro3-66m.group.port3.description = Output Port 3 Channels +thing-type.atlona.pro3-66m.group.port4.label = Port 4 +thing-type.atlona.pro3-66m.group.port4.description = Output Port 4 Channels +thing-type.atlona.pro3-66m.group.port5.label = Port 5 +thing-type.atlona.pro3-66m.group.port5.description = Output Port 5 Channels +thing-type.atlona.pro3-66m.group.port6.label = Port 6 +thing-type.atlona.pro3-66m.group.port6.description = Output Port 6 Channels +thing-type.atlona.pro3-66m.group.port7.label = Port 7 +thing-type.atlona.pro3-66m.group.port7.description = Output Port 7 Channels +thing-type.atlona.pro3-66m.group.port8.label = Port 8 +thing-type.atlona.pro3-66m.group.port8.description = Output Port 8 Channels +thing-type.atlona.pro3-66m.group.volume1.label = Volume 1 +thing-type.atlona.pro3-66m.group.volume1.description = Volume 1 channels +thing-type.atlona.pro3-66m.group.volume2.label = Volume 2 +thing-type.atlona.pro3-66m.group.volume2.description = Volume 2 channels +thing-type.atlona.pro3-66m.group.volume3.label = Volume 3 +thing-type.atlona.pro3-66m.group.volume3.description = Volume 3 channels +thing-type.atlona.pro3-66m.group.volume4.label = Volume 4 +thing-type.atlona.pro3-66m.group.volume4.description = Volume 4 channels +thing-type.atlona.pro3-88m.label = Atlona Pro3 8x8 HDBaseT Matrix +thing-type.atlona.pro3-88m.description = Atlona Pro3 8x8 HDBaseT Matrix (Model AT-UHD-PRO3-66M) +thing-type.atlona.pro3-88m.group.mirror8.label = HDMI Port 8 +thing-type.atlona.pro3-88m.group.mirror8.description = HDMI Port 8 Mirroring Channels +thing-type.atlona.pro3-88m.group.mirror10.label = HDMI Port 10 +thing-type.atlona.pro3-88m.group.mirror10.description = HDMI Port 10 Mirroring Channels +thing-type.atlona.pro3-88m.group.port1.label = Port 1 +thing-type.atlona.pro3-88m.group.port1.description = Output Port 1 Channels +thing-type.atlona.pro3-88m.group.port2.label = Port 2 +thing-type.atlona.pro3-88m.group.port2.description = Output Port 2 Channels +thing-type.atlona.pro3-88m.group.port3.label = Port 3 +thing-type.atlona.pro3-88m.group.port3.description = Output Port 3 Channels +thing-type.atlona.pro3-88m.group.port4.label = Port 4 +thing-type.atlona.pro3-88m.group.port4.description = Output Port 4 Channels +thing-type.atlona.pro3-88m.group.port5.label = Port 5 +thing-type.atlona.pro3-88m.group.port5.description = Output Port 5 Channels +thing-type.atlona.pro3-88m.group.port6.label = Port 6 +thing-type.atlona.pro3-88m.group.port6.description = Output Port 6 Channels +thing-type.atlona.pro3-88m.group.port7.label = Port 7 +thing-type.atlona.pro3-88m.group.port7.description = Output Port 7 Channels +thing-type.atlona.pro3-88m.group.port8.label = Port 8 +thing-type.atlona.pro3-88m.group.port8.description = Output Port 8 Channels +thing-type.atlona.pro3-88m.group.port9.label = Port 9 +thing-type.atlona.pro3-88m.group.port9.description = Output Port 9 Channels +thing-type.atlona.pro3-88m.group.port10.label = Port 10 +thing-type.atlona.pro3-88m.group.port10.description = Output Port 10 Channels +thing-type.atlona.pro3-88m.group.volume1.label = Volume 1 +thing-type.atlona.pro3-88m.group.volume1.description = Volume 1 channels +thing-type.atlona.pro3-88m.group.volume2.label = Volume 2 +thing-type.atlona.pro3-88m.group.volume2.description = Volume 2 channels +thing-type.atlona.pro3-88m.group.volume3.label = Volume 3 +thing-type.atlona.pro3-88m.group.volume3.description = Volume 3 channels +thing-type.atlona.pro3-88m.group.volume4.label = Volume 4 +thing-type.atlona.pro3-88m.group.volume4.description = Volume 4 channels +thing-type.atlona.pro3-88m.group.volume5.label = Volume 5 +thing-type.atlona.pro3-88m.group.volume5.description = Volume 5 channels +thing-type.atlona.pro3-88m.group.volume6.label = Volume 6 +thing-type.atlona.pro3-88m.group.volume6.description = Volume 6 channels +thing-type.atlona.pro3-hd66m.label = Atlona Pro3 HD 6x6 HDBaseT Matrix +thing-type.atlona.pro3-hd66m.description = Atlona Pro3 6x6 HDBaseT Matrix (Model AT-PRO3HD66M) +thing-type.atlona.pro3-hd66m.group.port1.label = Port 1 +thing-type.atlona.pro3-hd66m.group.port1.description = Output Port 1 Channels +thing-type.atlona.pro3-hd66m.group.port2.label = Port 2 +thing-type.atlona.pro3-hd66m.group.port2.description = Output Port 2 Channels +thing-type.atlona.pro3-hd66m.group.port3.label = Port 3 +thing-type.atlona.pro3-hd66m.group.port3.description = Output Port 3 Channels +thing-type.atlona.pro3-hd66m.group.port4.label = Port 4 +thing-type.atlona.pro3-hd66m.group.port4.description = Output Port 4 Channels +thing-type.atlona.pro3-hd66m.group.port5.label = Port 5 +thing-type.atlona.pro3-hd66m.group.port5.description = Output Port 5 Channels +thing-type.atlona.pro3-hd66m.group.port6.label = Port 6 +thing-type.atlona.pro3-hd66m.group.port6.description = Output Port 6 Channels + +# thing types config + +thing-type.config.altona.hdmimatrix.ipAddress.label = IP or Host Name +thing-type.config.altona.hdmimatrix.ipAddress.description = IP or Host name of Atlona Matrix Switch +thing-type.config.altona.hdmimatrix.password.label = Password +thing-type.config.altona.hdmimatrix.password.description = Password to login with if Telnet Login is on +thing-type.config.altona.hdmimatrix.ping.label = Ping Interval +thing-type.config.altona.hdmimatrix.ping.description = Ping Interval (in seconds) to keep the connection alive +thing-type.config.altona.hdmimatrix.polling.label = Polling Interval +thing-type.config.altona.hdmimatrix.polling.description = Interval (in seconds) to poll the actual state of the Matrix +thing-type.config.altona.hdmimatrix.retryPolling.label = Polling Interval to Try to Reconnect +thing-type.config.altona.hdmimatrix.retryPolling.description = Interval (in seconds) to try to (re)connect to the Matrix +thing-type.config.altona.hdmimatrix.userName.label = User Name +thing-type.config.altona.hdmimatrix.userName.description = User Name to login with if Telnet Login is on + +# channel group types + +channel-group-type.atlona.hd-portgroup.label = Port +channel-group-type.atlona.hd-portgroup.description = Output Port Channels +channel-group-type.atlona.mirrorgroup.label = HDMI Port +channel-group-type.atlona.mirrorgroup.description = HDMI Port Mirroring Channels +channel-group-type.atlona.portgroup.label = Port +channel-group-type.atlona.portgroup.description = Output Port Channels +channel-group-type.atlona.primarygroup.label = Primary Channels +channel-group-type.atlona.primarygroup.description = Primary Channels +channel-group-type.atlona.volumegroup.label = Volume +channel-group-type.atlona.volumegroup.description = Volume channels + +# channel types + +channel-type.atlona.irenable.label = IR Enable +channel-type.atlona.irenable.description = Enables or Disables IR +channel-type.atlona.matrixcmd.label = Matrix Command +channel-type.atlona.matrixcmd.description = Send a matrix command ("resetmatrix", "resetports", "allportsX") +channel-type.atlona.panellock.label = Panel Lock +channel-type.atlona.panellock.description = Whether the front panel buttons are locked or not +channel-type.atlona.portmirror.label = Mirror Port +channel-type.atlona.portmirror.description = Sets the port to be mirrored on the output port +channel-type.atlona.portmirrorenabled.label = Mirror Enabled +channel-type.atlona.portmirrorenabled.description = Whether the HDMI port mirroring is enabled or not +channel-type.atlona.portoutput.label = Output Port +channel-type.atlona.portoutput.description = Sets the output port to the input port +channel-type.atlona.portpower.label = Output Port Power +channel-type.atlona.portpower.description = Turns on/off the output port +channel-type.atlona.power.label = Power +channel-type.atlona.power.description = Whether the matrix is on or not +channel-type.atlona.presetcmd.label = Preset Command +channel-type.atlona.presetcmd.description = Send a preset command ("saveX", "recallX", "clearX") +channel-type.atlona.volume.label = Output Volume +channel-type.atlona.volume.description = Sets the volume (in db) of the output port (default: -40db with range from -79db to 15db) +channel-type.atlona.volumemute.label = Mute +channel-type.atlona.volumemute.description = Sets the output to muted or not diff --git a/bundles/org.openhab.binding.autelis/src/main/resources/OH-INF/i18n/autelis.properties b/bundles/org.openhab.binding.autelis/src/main/resources/OH-INF/i18n/autelis.properties new file mode 100644 index 0000000000000..8847540f20db7 --- /dev/null +++ b/bundles/org.openhab.binding.autelis/src/main/resources/OH-INF/i18n/autelis.properties @@ -0,0 +1,369 @@ +# binding + +binding.autelis.name = Autelis Pool Control Binding +binding.autelis.description = This is the binding for a Autelis pool controller. + +# thing types + +thing-type.autelis.jandy.label = Jandy Pool Controller +thing-type.autelis.jandy.description = A Jandy pool control thing represents a Autelis pool controller for Jandy systems +thing-type.autelis.jandy.channel.equipment-aux1.label = Auxiliary 1 +thing-type.autelis.jandy.channel.equipment-aux1.description = The current state of auxiliary 1 +thing-type.autelis.jandy.channel.equipment-aux2.label = Auxiliary 2 +thing-type.autelis.jandy.channel.equipment-aux2.description = The current state of auxiliary 2 +thing-type.autelis.jandy.channel.equipment-aux3.label = Auxiliary 3 +thing-type.autelis.jandy.channel.equipment-aux3.description = The current state of auxiliary 3 +thing-type.autelis.jandy.channel.equipment-aux4.label = Auxiliary 4 +thing-type.autelis.jandy.channel.equipment-aux4.description = The current state of auxiliary 4 +thing-type.autelis.jandy.channel.equipment-aux5.label = Auxiliary 5 +thing-type.autelis.jandy.channel.equipment-aux5.description = The current state of auxiliary 5 +thing-type.autelis.jandy.channel.equipment-aux6.label = Auxiliary 6 +thing-type.autelis.jandy.channel.equipment-aux6.description = The current state of auxiliary 6 +thing-type.autelis.jandy.channel.equipment-aux7.label = Auxiliary 7 +thing-type.autelis.jandy.channel.equipment-aux7.description = The current state of auxiliary 7 +thing-type.autelis.jandy.channel.equipment-aux8.label = Auxiliary 8 +thing-type.autelis.jandy.channel.equipment-aux8.description = The current state of auxiliary 8 +thing-type.autelis.jandy.channel.equipment-aux9.label = Auxiliary 9 +thing-type.autelis.jandy.channel.equipment-aux9.description = The current state of auxiliary 9 +thing-type.autelis.jandy.channel.equipment-aux10.label = Auxiliary 10 +thing-type.autelis.jandy.channel.equipment-aux10.description = The current state of auxiliary 10 +thing-type.autelis.jandy.channel.equipment-aux11.label = Auxiliary 11 +thing-type.autelis.jandy.channel.equipment-aux11.description = The current state of auxiliary 11 +thing-type.autelis.jandy.channel.equipment-aux12.label = Auxiliary 12 +thing-type.autelis.jandy.channel.equipment-aux12.description = The current state of auxiliary 12 +thing-type.autelis.jandy.channel.equipment-aux13.label = Auxiliary 13 +thing-type.autelis.jandy.channel.equipment-aux13.description = The current state of auxiliary 13 +thing-type.autelis.jandy.channel.equipment-aux14.label = Auxiliary 14 +thing-type.autelis.jandy.channel.equipment-aux14.description = The current state of auxiliary 14 +thing-type.autelis.jandy.channel.equipment-aux15.label = Auxiliary 15 +thing-type.autelis.jandy.channel.equipment-aux15.description = The current state of auxiliary 15 +thing-type.autelis.jandy.channel.equipment-aux16.label = Auxiliary 16 +thing-type.autelis.jandy.channel.equipment-aux16.description = The current state of auxiliary 16 +thing-type.autelis.jandy.channel.equipment-aux17.label = Auxiliary 17 +thing-type.autelis.jandy.channel.equipment-aux17.description = The current state of auxiliary 17 +thing-type.autelis.jandy.channel.equipment-aux18.label = Auxiliary 18 +thing-type.autelis.jandy.channel.equipment-aux18.description = The current state of auxiliary 18 +thing-type.autelis.jandy.channel.equipment-aux19.label = Auxiliary 19 +thing-type.autelis.jandy.channel.equipment-aux19.description = The current state of auxiliary 19 +thing-type.autelis.jandy.channel.equipment-aux20.label = Auxiliary 20 +thing-type.autelis.jandy.channel.equipment-aux20.description = The current state of auxiliary 20 +thing-type.autelis.jandy.channel.equipment-aux21.label = Auxiliary 21 +thing-type.autelis.jandy.channel.equipment-aux21.description = The current state of auxiliary 21 +thing-type.autelis.jandy.channel.equipment-aux22.label = Auxiliary 22 +thing-type.autelis.jandy.channel.equipment-aux22.description = The current state of auxiliary 22 +thing-type.autelis.jandy.channel.equipment-aux23.label = Auxiliary 23 +thing-type.autelis.jandy.channel.equipment-aux23.description = The current state of auxiliary 23 +thing-type.autelis.jandy.channel.equipment-cleaner.label = Cleaner Pump +thing-type.autelis.jandy.channel.equipment-cleaner.description = The current state of the cleaner pump +thing-type.autelis.jandy.channel.equipment-htpmp.label = Heat Pump +thing-type.autelis.jandy.channel.equipment-htpmp.description = The current state of the heat pump +thing-type.autelis.jandy.channel.equipment-poolht.label = Pool Heater +thing-type.autelis.jandy.channel.equipment-poolht.description = The current state of the pool heater +thing-type.autelis.jandy.channel.equipment-poolht2.label = Pool Heater @ +thing-type.autelis.jandy.channel.equipment-poolht2.description = The current state of the pool heater 2 +thing-type.autelis.jandy.channel.equipment-pump.label = Pump +thing-type.autelis.jandy.channel.equipment-pump.description = The current state of the pump +thing-type.autelis.jandy.channel.equipment-pumplo.label = Lowspeed Pump +thing-type.autelis.jandy.channel.equipment-pumplo.description = The current state of the lowspeed pump +thing-type.autelis.jandy.channel.equipment-solarht.label = Solar Heater +thing-type.autelis.jandy.channel.equipment-solarht.description = The current state of the solar heater +thing-type.autelis.jandy.channel.equipment-spa.label = Spa Pump +thing-type.autelis.jandy.channel.equipment-spa.description = The current state of the spa pump +thing-type.autelis.jandy.channel.equipment-spaht.label = Spa Heater +thing-type.autelis.jandy.channel.equipment-spaht.description = The current state of the spa heater +thing-type.autelis.jandy.channel.equipment-waterfall.label = Waterfall Pump +thing-type.autelis.jandy.channel.equipment-waterfall.description = The current state of the waterfall pump +thing-type.autelis.jandy.channel.temp-airtemp.label = Air Temperature +thing-type.autelis.jandy.channel.temp-airtemp.description = The current air temperature +thing-type.autelis.jandy.channel.temp-poolsp.label = Pool Setpoint +thing-type.autelis.jandy.channel.temp-poolsp.description = The current pool setpoint +thing-type.autelis.jandy.channel.temp-poolsp2.label = Pool Setpoint 2 +thing-type.autelis.jandy.channel.temp-poolsp2.description = The current pool setpoint 2 +thing-type.autelis.jandy.channel.temp-pooltemp.label = Pool Temperature +thing-type.autelis.jandy.channel.temp-pooltemp.description = The current pool temperature. Note: Only accurate when pool is running +thing-type.autelis.jandy.channel.temp-solartemp.label = Solar Temperature +thing-type.autelis.jandy.channel.temp-solartemp.description = The current solar temperature +thing-type.autelis.jandy.channel.temp-spasp.label = Spa Setpoint +thing-type.autelis.jandy.channel.temp-spasp.description = The current spa setpoint +thing-type.autelis.jandy.channel.temp-spatemp.label = Spa Temperature +thing-type.autelis.jandy.channel.temp-spatemp.description = The current spa temperature. Note: Only accurate when spa is running +thing-type.autelis.pentair.label = Pentair Pool Controller +thing-type.autelis.pentair.description = A Pentair pool control thing represents an Autelis pool controller for Pentair systems +thing-type.autelis.pentair.channel.equipment-circuit1.label = Circuit 1 +thing-type.autelis.pentair.channel.equipment-circuit1.description = The current state of circuit 1 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit2.label = Circuit 2 +thing-type.autelis.pentair.channel.equipment-circuit2.description = The current state of circuit 2 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit3.label = Circuit 3 +thing-type.autelis.pentair.channel.equipment-circuit3.description = The current state of circuit 3 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit4.label = Circuit 4 +thing-type.autelis.pentair.channel.equipment-circuit4.description = The current state of circuit 4 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit5.label = Circuit 5 +thing-type.autelis.pentair.channel.equipment-circuit5.description = The current state of circuit 5 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit6.label = Circuit 6 +thing-type.autelis.pentair.channel.equipment-circuit6.description = The current state of circuit 6 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit7.label = Circuit 7 +thing-type.autelis.pentair.channel.equipment-circuit7.description = The current state of circuit 7 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit8.label = Circuit 8 +thing-type.autelis.pentair.channel.equipment-circuit8.description = The current state of circuit 8 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit9.label = Circuit 9 +thing-type.autelis.pentair.channel.equipment-circuit9.description = The current state of circuit 9 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-circuit10.label = Circuit 10 +thing-type.autelis.pentair.channel.equipment-circuit10.description = The current state of circuit 10 (Spa or Lo-Temp) +thing-type.autelis.pentair.channel.equipment-feature1.label = Feature 1 +thing-type.autelis.pentair.channel.equipment-feature1.description = The current state of feature/macro 1 +thing-type.autelis.pentair.channel.equipment-feature2.label = Feature 2 +thing-type.autelis.pentair.channel.equipment-feature2.description = The current state of feature/macro 2 +thing-type.autelis.pentair.channel.equipment-feature3.label = Feature 3 +thing-type.autelis.pentair.channel.equipment-feature3.description = The current state of feature/macro 3 +thing-type.autelis.pentair.channel.equipment-feature4.label = Feature 4 +thing-type.autelis.pentair.channel.equipment-feature4.description = The current state of feature/macro 4 +thing-type.autelis.pentair.channel.equipment-feature5.label = Feature 5 +thing-type.autelis.pentair.channel.equipment-feature5.description = The current state of feature/macro 5 +thing-type.autelis.pentair.channel.equipment-feature6.label = Feature 6 +thing-type.autelis.pentair.channel.equipment-feature6.description = The current state of feature/macro 6 +thing-type.autelis.pentair.channel.equipment-feature7.label = Feature 7 +thing-type.autelis.pentair.channel.equipment-feature7.description = The current state of feature/macro 7 +thing-type.autelis.pentair.channel.equipment-feature8.label = Feature 8 +thing-type.autelis.pentair.channel.equipment-feature8.description = The current state of feature/macro 8 +thing-type.autelis.pentair.channel.equipment-feature9.label = Feature 9 +thing-type.autelis.pentair.channel.equipment-feature9.description = The current state of feature/macro 9 +thing-type.autelis.pentair.channel.equipment-feature10.label = Feature 10 +thing-type.autelis.pentair.channel.equipment-feature10.description = The current state of feature/macro 10 +thing-type.autelis.pentair.channel.pumps-pump2.label = Pump 2 +thing-type.autelis.pentair.channel.pumps-pump2.description = Pump 2 +thing-type.autelis.pentair.channel.pumps-pump3.label = Pump 3 +thing-type.autelis.pentair.channel.pumps-pump3.description = Pump 3 +thing-type.autelis.pentair.channel.pumps-pump4.label = Pump 4 +thing-type.autelis.pentair.channel.pumps-pump4.description = Pump 4 +thing-type.autelis.pentair.channel.pumps-pump5.label = Pump 5 +thing-type.autelis.pentair.channel.pumps-pump5.description = Pump 5 +thing-type.autelis.pentair.channel.pumps-pump6.label = Pump 6 +thing-type.autelis.pentair.channel.pumps-pump6.description = Pump 6 +thing-type.autelis.pentair.channel.pumps-pump7.label = Pump 7 +thing-type.autelis.pentair.channel.pumps-pump7.description = Pump 7 +thing-type.autelis.pentair.channel.pumps-pump8.label = Pump 8 +thing-type.autelis.pentair.channel.pumps-pump8.description = Pump 8 +thing-type.autelis.pentair.channel.system-sensor1.label = Sensor 1 +thing-type.autelis.pentair.channel.system-sensor1.description = The state of sensor 1 (water sensor) +thing-type.autelis.pentair.channel.system-sensor2.label = Sensor 2 +thing-type.autelis.pentair.channel.system-sensor2.description = The state of sensor 2 (water sensor) +thing-type.autelis.pentair.channel.system-sensor3.label = Sensor 3 +thing-type.autelis.pentair.channel.system-sensor3.description = The state of sensor 3 (water sensor) +thing-type.autelis.pentair.channel.system-sensor4.label = Sensor 4 +thing-type.autelis.pentair.channel.system-sensor4.description = The state of sensor 4 (water sensor) +thing-type.autelis.pentair.channel.system-sensor5.label = Sensor 5 +thing-type.autelis.pentair.channel.system-sensor5.description = The state of sensor 5 (water sensor) +thing-type.autelis.pentair.channel.temp-poolht.label = Pool Heater Status +thing-type.autelis.pentair.channel.temp-poolht.description = The current pool/hi-temp heater settings +thing-type.autelis.pentair.channel.temp-spaht.label = Spa Heater Status +thing-type.autelis.pentair.channel.temp-spaht.description = The current spa/hi-temp heater settings + +# thing types config + +thing-type.config.autelis.jandy.host.label = Host or IP +thing-type.config.autelis.jandy.host.description = The host name or IP address of the Autelis Controller. +thing-type.config.autelis.jandy.password.label = Password +thing-type.config.autelis.jandy.password.description = The password to use when connecting to a Autelis Controller. +thing-type.config.autelis.jandy.port.label = Port +thing-type.config.autelis.jandy.port.description = The port the Autelis Controller is listening on. +thing-type.config.autelis.jandy.refresh.label = Refresh Interval +thing-type.config.autelis.jandy.refresh.description = Specifies the refresh interval in seconds +thing-type.config.autelis.jandy.user.label = User Name +thing-type.config.autelis.jandy.user.description = The user name to use when connecting to a Autelis Controller. +thing-type.config.autelis.pentair.host.label = Host or IP +thing-type.config.autelis.pentair.host.description = The host name or IP address of the Autelis Controller. +thing-type.config.autelis.pentair.password.label = Password +thing-type.config.autelis.pentair.password.description = The password to use when connecting to a Autelis Controller. +thing-type.config.autelis.pentair.port.label = Port +thing-type.config.autelis.pentair.port.description = The port the Autelis Controller is listening on. +thing-type.config.autelis.pentair.refresh.label = Refresh Interval +thing-type.config.autelis.pentair.refresh.description = Specifies the refresh interval in seconds +thing-type.config.autelis.pentair.user.label = User Name +thing-type.config.autelis.pentair.user.description = The user name to use when connecting to a Autelis Controller. + +# channel types + +channel-type.autelis.chem-avail.label = Equipment Is Available +channel-type.autelis.chem-avail.description = Indicates what equipment is available +channel-type.autelis.chem-chlrp.label = Pool Chlorination Setpoint +channel-type.autelis.chem-chlrp.description = Pool chlorination setpoint +channel-type.autelis.chem-chlrs.label = Spa Chlorination Setpoint +channel-type.autelis.chem-chlrs.description = Spa chlorination setpoint +channel-type.autelis.chem-orp1.label = ORP Unit 1 +channel-type.autelis.chem-orp1.description = ORP reading from unit 1 +channel-type.autelis.chem-orp2.label = ORP Unit 2 +channel-type.autelis.chem-orp2.description = ORP reading from unit 2 +channel-type.autelis.chem-orpfd1.label = ORP Feed Unit 1 +channel-type.autelis.chem-orpfd1.description = ORP feed from unit 1 +channel-type.autelis.chem-orpfd2.label = ORP Feed Unit 2 +channel-type.autelis.chem-orpfd2.description = ORP feed from unit 2 +channel-type.autelis.chem-ph1.label = PH Unit 1 +channel-type.autelis.chem-ph1.description = PH reading from unit 1 +channel-type.autelis.chem-ph2.label = PH Unit 2 +channel-type.autelis.chem-ph2.description = PH reading from unit 2 +channel-type.autelis.chem-phfd1.label = PH Feed Unit 1 +channel-type.autelis.chem-phfd1.description = PH feed from unit 1 +channel-type.autelis.chem-phfd2.label = PH Feed Unit 2 +channel-type.autelis.chem-phfd2.description = PH feed from unit 2 +channel-type.autelis.chem-saltp.label = Pool Salt Level +channel-type.autelis.chem-saltp.description = Pool salt level +channel-type.autelis.chem-salts.label = Spa Salt Level +channel-type.autelis.chem-salts.description = Spa salt level +channel-type.autelis.chlor-chloren.label = Chlorine +channel-type.autelis.chlor-chloren.description = Chlorine +channel-type.autelis.chlor-chlorerr.label = Chlorine Error +channel-type.autelis.chlor-chlorerr.description = Chlorine Error value +channel-type.autelis.chlor-chlorname.label = Chlorine Model Name +channel-type.autelis.chlor-chlorname.description = Chlorine Model Name +channel-type.autelis.chlor-poolsp.label = Chlorine Pool Setpoint +channel-type.autelis.chlor-poolsp.description = Chlorine Pool Setpoint +channel-type.autelis.chlor-salt.label = Chlorine Salt Level +channel-type.autelis.chlor-salt.description = Chlorine Salt Level +channel-type.autelis.chlor-spasp.label = Chlorine Spa Setpoint +channel-type.autelis.chlor-spasp.description = Chlorine Sap Setpoint +channel-type.autelis.chlor-super.label = Chlorine Super Level +channel-type.autelis.chlor-super.description = Chlorine Super Level +channel-type.autelis.equipment-aux.label = Auxiliary +channel-type.autelis.equipment-aux.description = The current state of auxiliary channel +channel-type.autelis.equipment-aux.state.option.0 = Off +channel-type.autelis.equipment-aux.state.option.1 = On +channel-type.autelis.equipment-aux.state.option.25 = 25% +channel-type.autelis.equipment-aux.state.option.50 = 50% +channel-type.autelis.equipment-aux.state.option.75 = 75% +channel-type.autelis.equipment-aux.state.option.100 = 100% +channel-type.autelis.equipment-circuit.label = Circuit 1 +channel-type.autelis.equipment-circuit.description = The current state of a circuit (Spa or Lo-Temp) +channel-type.autelis.equipment-feature.label = Feature +channel-type.autelis.equipment-feature.description = The current state of a feature/macro +channel-type.autelis.equipment-ht.label = Heater +channel-type.autelis.equipment-ht.description = The current state of the heater +channel-type.autelis.equipment-ht.state.option.0 = Off +channel-type.autelis.equipment-ht.state.option.1 = Enabled +channel-type.autelis.equipment-ht.state.option.2 = On +channel-type.autelis.equipment-switch.label = Equipment Switch +channel-type.autelis.equipment-switch.description = The current state of a equipment switch +channel-type.autelis.lightscmd.label = Lighting Cmd +channel-type.autelis.lightscmd.description = Send A lighting command +channel-type.autelis.lightscmd.state.option.alloff = All Off +channel-type.autelis.lightscmd.state.option.allon = All On +channel-type.autelis.lightscmd.state.option.csync = C Sync +channel-type.autelis.lightscmd.state.option.cset = C Set +channel-type.autelis.lightscmd.state.option.cswim = C Swim +channel-type.autelis.lightscmd.state.option.party = Party +channel-type.autelis.lightscmd.state.option.romance = Romance +channel-type.autelis.lightscmd.state.option.caribbean = Caribbean +channel-type.autelis.lightscmd.state.option.american = American +channel-type.autelis.lightscmd.state.option.sunset = Sunset +channel-type.autelis.lightscmd.state.option.royalty = Royalty +channel-type.autelis.lightscmd.state.option.blue = Blue +channel-type.autelis.lightscmd.state.option.green = Green +channel-type.autelis.lightscmd.state.option.red = Red +channel-type.autelis.lightscmd.state.option.white = White +channel-type.autelis.lightscmd.state.option.magenta = Magenta +channel-type.autelis.lightscmd.state.option.hold = Hold +channel-type.autelis.lightscmd.state.option.recall = Recall +channel-type.autelis.pumps-pump.label = Pump 2 +channel-type.autelis.pumps-pump.description = Pump 2 +channel-type.autelis.pumps-pump1-error.label = Pump 1 Error +channel-type.autelis.pumps-pump1-error.description = Pump 1 error status +channel-type.autelis.pumps-pump1-filter.label = Pump 1 Filter +channel-type.autelis.pumps-pump1-filter.description = Pump 1 +channel-type.autelis.pumps-pump1-gpm.label = Pump 1 GPM +channel-type.autelis.pumps-pump1-gpm.description = Pump 1 GPM +channel-type.autelis.pumps-pump1-rpm.label = Pump 1 RPM +channel-type.autelis.pumps-pump1-rpm.description = Pump 1 RPM +channel-type.autelis.pumps-pump1-watts.label = Pump 1 Watts +channel-type.autelis.pumps-pump1-watts.description = Pump 1 watts +channel-type.autelis.pumps-pump1.label = Pump 1 +channel-type.autelis.pumps-pump1.description = Pump 1 raw value +channel-type.autelis.pumps-vsp1.label = Pump 1 +channel-type.autelis.pumps-vsp1.description = Pump 1 +channel-type.autelis.pumps-vsp2.label = Pump 2 +channel-type.autelis.pumps-vsp2.description = Pump 2 +channel-type.autelis.pumps-vsp3.label = Pump 3 +channel-type.autelis.pumps-vsp3.description = Pump 3 +channel-type.autelis.pumps-vsp4.label = Pump 4 +channel-type.autelis.pumps-vsp4.description = Pump 4 +channel-type.autelis.reboot.label = Reboot Autelis Device +channel-type.autelis.reboot.description = Reboots the Autelis device. This will not reboot any actual pool equipment. +channel-type.autelis.reboot.label = Reboot Autelis Device +channel-type.autelis.reboot.description = Reboots the Autelis device. This will not reboot any actual pool equipment. +channel-type.autelis.system-dip.label = Dip Switches +channel-type.autelis.system-dip.description = The current state of the Aqualink® controller's dip switches. Possible values: 8 binary digits representing S1-S8 from left to right +channel-type.autelis.system-freeze.label = Freeze State +channel-type.autelis.system-freeze.description = The state of freeze protect +channel-type.autelis.system-freeze.state.option.0 = Off +channel-type.autelis.system-freeze.state.option.1 = On +channel-type.autelis.system-haddr.label = Hardware Address +channel-type.autelis.system-haddr.description = The controller's harware address +channel-type.autelis.system-lowbat.label = Battery State +channel-type.autelis.system-lowbat.description = The current state of the Aqualink® controller's battery +channel-type.autelis.system-lowbat.state.option.0 = Normal +channel-type.autelis.system-lowbat.state.option.1 = Low +channel-type.autelis.system-model.label = Model +channel-type.autelis.system-model.description = The model of the Intellitouch® controller +channel-type.autelis.system-model.label = Model +channel-type.autelis.system-model.description = The model number of the Aqualink® controller +channel-type.autelis.system-opmode.label = Operation Mode +channel-type.autelis.system-opmode.description = The current state of the Intellitouch® controller +channel-type.autelis.system-opmode.state.option.0 = Auto +channel-type.autelis.system-opmode.state.option.1 = Service/Timeout +channel-type.autelis.system-opmode.label = Operation Mode +channel-type.autelis.system-opmode.description = The current state of the Aqualink® controller +channel-type.autelis.system-opmode.state.option.0 = Auto +channel-type.autelis.system-opmode.state.option.1 = Service +channel-type.autelis.system-opmode.state.option.2 = Timeout +channel-type.autelis.system-runstate.label = Runstate +channel-type.autelis.system-runstate.description = The controller's runstate. 1 = Starting Up, 2-49 = Getting Data, 50 = Ready +channel-type.autelis.system-runstate.label = Runstate +channel-type.autelis.system-runstate.description = The controller's runstate. 1 = Not Connected, 2-7 = Startup Initialization Sequence, 8 = Connected and Ready, 9-12 = Connected and Busy Executing Command +channel-type.autelis.system-sensor.label = Sensor +channel-type.autelis.system-sensor.description = The state of a sensor (water sensor) +channel-type.autelis.system-sensor.state.option.0 = OK +channel-type.autelis.system-sensor.state.option.1 = ERROR +channel-type.autelis.system-time.label = Time +channel-type.autelis.system-time.description = The time as kept by the Pool Control device +channel-type.autelis.system-time.label = Time +channel-type.autelis.system-time.description = The time as kept by the Pool Control device +channel-type.autelis.system-vbat.label = Battery Voltage +channel-type.autelis.system-vbat.description = The voltage of the Aqualink® controller's battery +channel-type.autelis.system-version.label = Version +channel-type.autelis.system-version.description = The firmware version of the Pool Control device +channel-type.autelis.system-version.label = Version +channel-type.autelis.system-version.description = The firmware version of the Pool Control device +channel-type.autelis.temp-airtemp.label = Air Temperature +channel-type.autelis.temp-airtemp.description = The current temperature measured by the air sensor +channel-type.autelis.temp-airtemp.label = Air Temperature +channel-type.autelis.temp-airtemp.description = The current air temperature +channel-type.autelis.temp-ht.label = Heater Status +channel-type.autelis.temp-ht.description = The current hi-temp heater settings +channel-type.autelis.temp-ht.state.option.0 = Off +channel-type.autelis.temp-ht.state.option.1 = Heater +channel-type.autelis.temp-ht.state.option.2 = Solar Preferred +channel-type.autelis.temp-ht.state.option.3 = Solar Only +channel-type.autelis.temp-htpump.label = Heat Pump +channel-type.autelis.temp-htpump.description = Heat Pump +channel-type.autelis.temp-htstatus.label = Heat Status +channel-type.autelis.temp-htstatus.description = Heat Status +channel-type.autelis.temp-poolsp.label = Pool Heat Setpoint +channel-type.autelis.temp-poolsp.description = The current pool/hi-temp setpoint +channel-type.autelis.temp-pooltemp.label = Pool Temp +channel-type.autelis.temp-pooltemp.description = The current pool temperature. Note: Only accurate when pool is running +channel-type.autelis.temp-soltemp.label = Solar Temperature +channel-type.autelis.temp-soltemp.description = The current temperature measured by the solar sensor +channel-type.autelis.temp-sp.label = Setpoint +channel-type.autelis.temp-sp.description = The current setpoint +channel-type.autelis.temp-spasp.label = Spa Heat Setpoint +channel-type.autelis.temp-spasp.description = The current spa/lo-temp setpoint +channel-type.autelis.temp-spatemp.label = Spa Temperature +channel-type.autelis.temp-spatemp.description = The current spa temperature. Note: Only accurate when spa is running +channel-type.autelis.temp-temperature.label = Temperature +channel-type.autelis.temp-temperature.description = The current temperature. Note: Only accurate when pool is running +channel-type.autelis.temp-tempunits.label = Temperature Units +channel-type.autelis.temp-tempunits.description = The selected units for temperature +channel-type.autelis.temp-tempunits.state.option.F = Fahrenheit +channel-type.autelis.temp-tempunits.state.option.C = Celsius +channel-type.autelis.temp-tempunits.label = Temperature Units +channel-type.autelis.temp-tempunits.description = The selected units for temperature +channel-type.autelis.temp-tempunits.state.option.F = Fahrenheit +channel-type.autelis.temp-tempunits.state.option.C = Celsius diff --git a/bundles/org.openhab.binding.benqprojector/src/main/resources/OH-INF/i18n/benqprojector.properties b/bundles/org.openhab.binding.benqprojector/src/main/resources/OH-INF/i18n/benqprojector.properties new file mode 100644 index 0000000000000..20f95a3e99170 --- /dev/null +++ b/bundles/org.openhab.binding.benqprojector/src/main/resources/OH-INF/i18n/benqprojector.properties @@ -0,0 +1,83 @@ +# binding + +binding.benqprojector.name = BenQ Projector Binding +binding.benqprojector.description = This binding is compatible with BenQ projectors + +# thing types + +thing-type.benqprojector.projector-serial.label = BenQ Projector - Serial +thing-type.benqprojector.projector-serial.description = A BenQ projector connected via a serial port +thing-type.benqprojector.projector-tcp.label = BenQ Projector - TCP/IP +thing-type.benqprojector.projector-tcp.description = A BenQ projector connected via the built-in ethernet port or a serial over IP device + +# thing types config + +thing-type.config.benqprojector.projector-serial.pollingInterval.label = Polling Interval +thing-type.config.benqprojector.projector-serial.pollingInterval.description = Configures How Often to Poll the Projector for Updates (5-60; Default 10) +thing-type.config.benqprojector.projector-serial.serialPort.label = Serial Port +thing-type.config.benqprojector.projector-serial.serialPort.description = Serial Port to Use for Connecting to the BenQ Projector +thing-type.config.benqprojector.projector-tcp.host.label = Host +thing-type.config.benqprojector.projector-tcp.host.description = IP address for the projector or serial over IP device +thing-type.config.benqprojector.projector-tcp.pollingInterval.label = Polling Interval +thing-type.config.benqprojector.projector-tcp.pollingInterval.description = Configures How Often to Poll the Projector for Updates (5-60; Default 10) +thing-type.config.benqprojector.projector-tcp.port.label = Port +thing-type.config.benqprojector.projector-tcp.port.description = Port for the projector or serial over IP device + +# channel types + +channel-type.benqprojector.aspectratio.label = Aspect Ratio +channel-type.benqprojector.aspectratio.description = Retrieve or Set the Aspect Ratio +channel-type.benqprojector.aspectratio.state.option.4:3 = 4:3 +channel-type.benqprojector.aspectratio.state.option.16:9 = 16:9 +channel-type.benqprojector.aspectratio.state.option.auto = Auto +channel-type.benqprojector.aspectratio.state.option.lbox = Letterbox +channel-type.benqprojector.aspectratio.state.option.wide = Wide +channel-type.benqprojector.blank.label = Screen Blank +channel-type.benqprojector.blank.description = Turn the Screen Blank On or Off +channel-type.benqprojector.directcmd.label = Direct Command +channel-type.benqprojector.directcmd.description = Send a Command Directly to the Projector +channel-type.benqprojector.directcmd.state.option.mute=on = Mute On +channel-type.benqprojector.directcmd.state.option.mute=off = Mute Off +channel-type.benqprojector.directcmd.state.option.vol=+ = Volume + +channel-type.benqprojector.directcmd.state.option.vol=- = Volume - +channel-type.benqprojector.directcmd.state.option.zoomI = Zoom In +channel-type.benqprojector.directcmd.state.option.zoomO = Zoom Out +channel-type.benqprojector.directcmd.state.option.auto = Zoom Auto +channel-type.benqprojector.directcmd.state.option.menu=on = Menu On +channel-type.benqprojector.directcmd.state.option.menu=off = Menu Off +channel-type.benqprojector.directcmd.state.option.up = Up +channel-type.benqprojector.directcmd.state.option.down = Down +channel-type.benqprojector.directcmd.state.option.left = Left +channel-type.benqprojector.directcmd.state.option.right = Right +channel-type.benqprojector.directcmd.state.option.enter = Enter +channel-type.benqprojector.freeze.label = Freeze Image +channel-type.benqprojector.freeze.description = Turn the Freeze Image Mode On or Off +channel-type.benqprojector.lamptime.label = Lamp Time +channel-type.benqprojector.lamptime.description = Retrieves the Lamp Hours +channel-type.benqprojector.picturemode.label = Picture Mode +channel-type.benqprojector.picturemode.description = Retrieve or Set the Picture Mode +channel-type.benqprojector.picturemode.state.option.dynamic = Dynamic +channel-type.benqprojector.picturemode.state.option.preset = Presentation +channel-type.benqprojector.picturemode.state.option.srgb = sRGB +channel-type.benqprojector.picturemode.state.option.bright = Bright +channel-type.benqprojector.picturemode.state.option.livingroom = Living Room +channel-type.benqprojector.picturemode.state.option.game = Game +channel-type.benqprojector.picturemode.state.option.cine = Cinema +channel-type.benqprojector.picturemode.state.option.std = Standard/Vivid +channel-type.benqprojector.picturemode.state.option.football = Football +channel-type.benqprojector.picturemode.state.option.footballbt = Football Bright +channel-type.benqprojector.picturemode.state.option.user1 = User 1 +channel-type.benqprojector.picturemode.state.option.user2 = User 2 +channel-type.benqprojector.picturemode.state.option.user3 = User 3 +channel-type.benqprojector.picturemode.state.option.isfday = ISF Day +channel-type.benqprojector.picturemode.state.option.isfnight = ISF Night +channel-type.benqprojector.picturemode.state.option.threed = 3-D +channel-type.benqprojector.source.label = Source +channel-type.benqprojector.source.description = Retrieve or Set the Input Source +channel-type.benqprojector.source.state.option.hdmi = HDMI +channel-type.benqprojector.source.state.option.hdmi2 = HDMI2 +channel-type.benqprojector.source.state.option.ypbr = Component +channel-type.benqprojector.source.state.option.rgb = Computer/YPbPr +channel-type.benqprojector.source.state.option.rgb2 = Computer/YPbPr2 +channel-type.benqprojector.source.state.option.vid = Video +channel-type.benqprojector.source.state.option.svid = S-Video diff --git a/bundles/org.openhab.binding.bigassfan/src/main/resources/OH-INF/i18n/bigassfan.properties b/bundles/org.openhab.binding.bigassfan/src/main/resources/OH-INF/i18n/bigassfan.properties new file mode 100644 index 0000000000000..593800857578c --- /dev/null +++ b/bundles/org.openhab.binding.bigassfan/src/main/resources/OH-INF/i18n/bigassfan.properties @@ -0,0 +1,82 @@ +# binding + +binding.bigassfan.name = BigAssFan Binding +binding.bigassfan.description = This is the binding for BigAssFan. + +# thing types + +thing-type.bigassfan.controller.label = Controller +thing-type.bigassfan.controller.description = Wall controller for Big Ass Fan +thing-type.bigassfan.fan.label = BigAssFan +thing-type.bigassfan.fan.description = Big Ass Fan +thing-type.bigassfan.light.label = Light +thing-type.bigassfan.light.description = Light + +# thing types config + +thing-type.config.bigassfan.device.ipAddress.label = Network Address +thing-type.config.bigassfan.device.ipAddress.description = Enter the IP address of the device +thing-type.config.bigassfan.device.label.label = Name of Device +thing-type.config.bigassfan.device.label.description = Enter the name you've given to the device +thing-type.config.bigassfan.device.macAddress.label = MAC Address +thing-type.config.bigassfan.device.macAddress.description = Enter the MAC address of the device + +# channel types + +channel-type.bigassfan.fan-auto.label = Fan Auto Mode +channel-type.bigassfan.fan-auto.description = Enable or disable fan auto mode +channel-type.bigassfan.fan-direction.label = Fan Direction +channel-type.bigassfan.fan-direction.description = Forward or reverse +channel-type.bigassfan.fan-direction.state.option.FWD = Forward +channel-type.bigassfan.fan-direction.state.option.REV = Reverse +channel-type.bigassfan.fan-learn-speed-max.label = Maximum Fan Speed +channel-type.bigassfan.fan-learn-speed-max.description = Set the maximum fan speed when in Smart Cooling mode +channel-type.bigassfan.fan-learn-speed-min.label = Minimum Fan Speed +channel-type.bigassfan.fan-learn-speed-min.description = Set the minimum fan speed when in Smart Cooling mode +channel-type.bigassfan.fan-power.label = Fan Power +channel-type.bigassfan.fan-power.description = Turn the fan on and off +channel-type.bigassfan.fan-sleep.label = Sleep Mode +channel-type.bigassfan.fan-sleep.description = Enable or disable fan sleep mode +channel-type.bigassfan.fan-smartmode.label = Fan Smartmode +channel-type.bigassfan.fan-smartmode.description = Set Smartmode to OFF, COOLING, or HEATING +channel-type.bigassfan.fan-smartmode.state.option.OFF = OFF +channel-type.bigassfan.fan-smartmode.state.option.COOLING = COOLING +channel-type.bigassfan.fan-smartmode.state.option.HEATING = HEATING +channel-type.bigassfan.fan-speed-max.label = Maximum Fan Speed +channel-type.bigassfan.fan-speed-max.description = Set the maximum fan speed +channel-type.bigassfan.fan-speed-min.label = Minimum Fan Speed +channel-type.bigassfan.fan-speed-min.description = Set the minimum fan speed +channel-type.bigassfan.fan-speed.label = Fan Speed +channel-type.bigassfan.fan-speed.description = Control the speed of the fan +channel-type.bigassfan.fan-whoosh.label = Fan Whoosh Mode +channel-type.bigassfan.fan-whoosh.description = Enable or disable fan whoosh mode +channel-type.bigassfan.fan-wintermode.label = Fan Winter Mode +channel-type.bigassfan.fan-wintermode.description = Enable or disable fan winter mode +channel-type.bigassfan.light-auto.label = Light Auto Mode +channel-type.bigassfan.light-auto.description = Enable or disable light auto mode +channel-type.bigassfan.light-color.label = Light Color +channel-type.bigassfan.light-color.description = Light allows hue to be adjusted +channel-type.bigassfan.light-color.state.option.COLOR = Color +channel-type.bigassfan.light-color.state.option.NOCOLOR = No Color +channel-type.bigassfan.light-hue.label = Hue +channel-type.bigassfan.light-hue.description = Set the hue of the light +channel-type.bigassfan.light-level-max.label = Maximum Brightness +channel-type.bigassfan.light-level-max.description = Set the maximum brightness level when using Smarter Lighting +channel-type.bigassfan.light-level-min.label = Minimum Brightness +channel-type.bigassfan.light-level-min.description = Set the minimum brightness level when using Smarter Lighting +channel-type.bigassfan.light-level.label = Light Brightness +channel-type.bigassfan.light-level.description = The brightness level of the fan's light +channel-type.bigassfan.light-power.label = Light Power +channel-type.bigassfan.light-power.description = Turn the fan's light on and off +channel-type.bigassfan.light-present.label = Light Present +channel-type.bigassfan.light-present.description = Fan has the integrated light installed +channel-type.bigassfan.light-present.state.option.PRESENT = Present +channel-type.bigassfan.light-present.state.option.NOTPRESENT = Not Present +channel-type.bigassfan.light-smarter.label = Smarter Lighting +channel-type.bigassfan.light-smarter.description = Enable or disable Smarter Lighting +channel-type.bigassfan.motion.label = Motion Sensor +channel-type.bigassfan.motion.description = The fan's motion sensor has detected motion +channel-type.bigassfan.motion.state.option.ON = Triggered +channel-type.bigassfan.motion.state.option.OFF = Untriggered +channel-type.bigassfan.time.label = Time +channel-type.bigassfan.time.description = Time reported by the fan diff --git a/bundles/org.openhab.binding.bluetooth/src/main/resources/OH-INF/i18n/bluetooth.properties b/bundles/org.openhab.binding.bluetooth/src/main/resources/OH-INF/i18n/bluetooth.properties new file mode 100644 index 0000000000000..5db11c8d1bf37 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth/src/main/resources/OH-INF/i18n/bluetooth.properties @@ -0,0 +1,27 @@ +# binding + +binding.bluetooth.name = Bluetooth Binding +binding.bluetooth.description = This binding supports the Bluetooth protocol. + +# thing types + +thing-type.bluetooth.beacon.label = Bluetooth Device +thing-type.bluetooth.beacon.description = A generic Bluetooth device in beacon-mode +thing-type.bluetooth.connected.label = Connected Bluetooth Device +thing-type.bluetooth.connected.description = A generic Bluetooth device in connected-mode + +# thing types config + +thing-type.config.bluetooth.beacon.address.label = Address +thing-type.config.bluetooth.beacon.address.description = The unique Bluetooth address of the device +thing-type.config.bluetooth.connected.address.label = Address +thing-type.config.bluetooth.connected.address.description = The unique Bluetooth address of the device + +# channel types + +channel-type.bluetooth.adapter-location.label = Adapter Location +channel-type.bluetooth.adapter-location.description = Location of the nearest adapter to this device +channel-type.bluetooth.adapter-uid.label = Adapter UID +channel-type.bluetooth.adapter-uid.description = ThingUID of nearest adapter +channel-type.bluetooth.rssi.label = RSSI +channel-type.bluetooth.rssi.description = Received signal strength indicator diff --git a/bundles/org.openhab.binding.bmwconnecteddrive/src/main/resources/OH-INF/i18n/bmwconnecteddrive.properties b/bundles/org.openhab.binding.bmwconnecteddrive/src/main/resources/OH-INF/i18n/bmwconnecteddrive.properties new file mode 100644 index 0000000000000..da6ece511eb78 --- /dev/null +++ b/bundles/org.openhab.binding.bmwconnecteddrive/src/main/resources/OH-INF/i18n/bmwconnecteddrive.properties @@ -0,0 +1,253 @@ +# binding + +binding.bmwconnecteddrive.name = BMW ConnectedDrive +binding.bmwconnecteddrive.description = Provides access to your Vehicle Data via BMW Connected Drive Portal + +# thing types + +thing-type.bmwconnecteddrive.account.label = BMW ConnectedDrive Account +thing-type.bmwconnecteddrive.account.description = Access to BMW ConnectedDrive Portal for a specific user +thing-type.bmwconnecteddrive.bev.label = Electric Vehicle +thing-type.bmwconnecteddrive.bev.description = Battery Electric Vehicle (BEV) +thing-type.bmwconnecteddrive.bev_rex.label = Electric Vehicle with REX +thing-type.bmwconnecteddrive.bev_rex.description = Battery Electric Vehicle with Range Extender (BEV_REX) +thing-type.bmwconnecteddrive.conv.label = Conventional Vehicle +thing-type.bmwconnecteddrive.conv.description = Conventional Fuel Vehicle (CONV) +thing-type.bmwconnecteddrive.phev.label = Plug-In-Hybrid Electric Vehicle +thing-type.bmwconnecteddrive.phev.description = Conventional Fuel Vehicle with supporting Electric Engine (PHEV) + +# thing types config + +thing-type.config.bmwconnecteddrive.bridge.password.label = Password +thing-type.config.bmwconnecteddrive.bridge.password.description = BMW Connected Drive Password +thing-type.config.bmwconnecteddrive.bridge.preferMyBmw.label = Prefer MyBMW API +thing-type.config.bmwconnecteddrive.bridge.preferMyBmw.description = Prefer *MyBMW* API instead of *BMW Connected Drive* +thing-type.config.bmwconnecteddrive.bridge.region.label = Region +thing-type.config.bmwconnecteddrive.bridge.region.description = Select Region in order to connect to the appropriate BMW Server +thing-type.config.bmwconnecteddrive.bridge.region.option.NORTH_AMERICA = North America +thing-type.config.bmwconnecteddrive.bridge.region.option.CHINA = China +thing-type.config.bmwconnecteddrive.bridge.region.option.ROW = Rest of the World +thing-type.config.bmwconnecteddrive.bridge.userName.label = Username +thing-type.config.bmwconnecteddrive.bridge.userName.description = BMW Connected Drive Username +thing-type.config.bmwconnecteddrive.vehicle.imageSize.label = Image Picture Size +thing-type.config.bmwconnecteddrive.vehicle.imageSize.description = Vehicle Image size for width and length +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.label = Image Viewport +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.description = Viewport for Vehicle Image +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.option.FRONT = Front View +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.option.REAR = Rear View +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.option.SIDE = Side View +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.option.DASHBOARD = Dashboard View +thing-type.config.bmwconnecteddrive.vehicle.imageViewport.option.DRIVERDOOR = Driver Door View +thing-type.config.bmwconnecteddrive.vehicle.refreshInterval.label = Refresh Interval +thing-type.config.bmwconnecteddrive.vehicle.refreshInterval.description = Data Refresh Rate for your Vehicle data +thing-type.config.bmwconnecteddrive.vehicle.units.label = Unit Selection +thing-type.config.bmwconnecteddrive.vehicle.units.description = Units are selected via auto-detection but you can overrule +thing-type.config.bmwconnecteddrive.vehicle.units.option.AUTODETECT = Auto Detect +thing-type.config.bmwconnecteddrive.vehicle.units.option.METRIC = Metric +thing-type.config.bmwconnecteddrive.vehicle.units.option.IMPERIAL = Imperial +thing-type.config.bmwconnecteddrive.vehicle.vin.label = Vehicle Identification Number (VIN) +thing-type.config.bmwconnecteddrive.vehicle.vin.description = Unique VIN given by BMW + +# channel group types + +channel-group-type.bmwconnecteddrive.charge-values.label = Electric Charging +channel-group-type.bmwconnecteddrive.charge-values.description = Charge Profiles of Vehicle +channel-group-type.bmwconnecteddrive.check-control-values.label = Check Control Messages +channel-group-type.bmwconnecteddrive.check-control-values.description = Show the current active CheckControl Messages +channel-group-type.bmwconnecteddrive.conv-range-values.label = Range Data +channel-group-type.bmwconnecteddrive.conv-range-values.description = Provides Mileage, remaining range and fuel level values +channel-group-type.bmwconnecteddrive.destination-values.label = Destination List +channel-group-type.bmwconnecteddrive.destination-values.description = Shows Your Destinations in a List +channel-group-type.bmwconnecteddrive.door-values.label = Detailed Door Status +channel-group-type.bmwconnecteddrive.door-values.description = Detailed Status of all Doors and Windows +channel-group-type.bmwconnecteddrive.ev-last-trip-values.label = Last Trip Statistics +channel-group-type.bmwconnecteddrive.ev-last-trip-values.description = EV Consumption Values and Distances for the Last Trip +channel-group-type.bmwconnecteddrive.ev-lifetime-values.label = Lifetime Statistics +channel-group-type.bmwconnecteddrive.ev-lifetime-values.description = Consumption Values and Distances over Lifetime +channel-group-type.bmwconnecteddrive.ev-range-values.label = Electric Range Data +channel-group-type.bmwconnecteddrive.ev-range-values.description = Provides Mileage, remaining range and charge level values +channel-group-type.bmwconnecteddrive.ev-vehicle-status.label = Vehicle Status +channel-group-type.bmwconnecteddrive.ev-vehicle-status.description = Provides Status of Doors, Windows, Lock State, Service and Check Control Messages +channel-group-type.bmwconnecteddrive.hybrid-last-trip-values.label = Last Trip Statistics +channel-group-type.bmwconnecteddrive.hybrid-last-trip-values.description = Hybrid Consumption Values and Distances for the Last Trip +channel-group-type.bmwconnecteddrive.hybrid-lifetime-values.label = Lifetime Statistics +channel-group-type.bmwconnecteddrive.hybrid-lifetime-values.description = Consumption Values and Distances over Lifetime +channel-group-type.bmwconnecteddrive.hybrid-range-values.label = Hybrid Range Data +channel-group-type.bmwconnecteddrive.hybrid-range-values.description = Provides Mileage, remaining range and fuel and charge level values +channel-group-type.bmwconnecteddrive.image-values.label = Vehicle Image +channel-group-type.bmwconnecteddrive.image-values.description = Provides an Image of your Vehicle +channel-group-type.bmwconnecteddrive.location-values.label = Vehicle Location +channel-group-type.bmwconnecteddrive.location-values.description = Coordinates and Heading of the Vehcile +channel-group-type.bmwconnecteddrive.remote-services.label = Remote Services +channel-group-type.bmwconnecteddrive.remote-services.description = Services can be executed via BMW Server like Door lock/unlock, Air Conditioning and more +channel-group-type.bmwconnecteddrive.service-values.label = Vehicle Services +channel-group-type.bmwconnecteddrive.service-values.description = All future Service schedules +channel-group-type.bmwconnecteddrive.vehicle-status.label = Vehicle Status +channel-group-type.bmwconnecteddrive.vehicle-status.description = Provides Status of Doors, Windows, Lock State, Service and Check Control Messages + +# channel types + +channel-type.bmwconnecteddrive.average-combined-consumption-channel.label = Avg. Combined Consumption +channel-type.bmwconnecteddrive.average-combined-consumption-channel.description = Average combined consumption in liter per 100 km/mi +channel-type.bmwconnecteddrive.average-combined-consumption-channel.label = Avg. Combined Consumption +channel-type.bmwconnecteddrive.average-combined-consumption-channel.description = Average combined consumption in liter per 100 km/mi +channel-type.bmwconnecteddrive.average-consumption-channel.label = Avg. Power Consumption +channel-type.bmwconnecteddrive.average-consumption-channel.description = Average Combined Consumption electric power consumption per 100 km/mi +channel-type.bmwconnecteddrive.average-consumption-channel.label = Avg. Power Consumption +channel-type.bmwconnecteddrive.average-consumption-channel.description = Average electric power consumption per 100 km/mi +channel-type.bmwconnecteddrive.average-recuperation-channel.label = Avg. Combined Consumption Recuperation +channel-type.bmwconnecteddrive.average-recuperation-channel.description = Average electric recuperation per 100 km/mi +channel-type.bmwconnecteddrive.average-recuperation-channel.label = Avg. Recuperation +channel-type.bmwconnecteddrive.average-recuperation-channel.description = Average electric recuperation per 100 km/mi +channel-type.bmwconnecteddrive.charging-remaining-channel.label = Remaining Charging Time +channel-type.bmwconnecteddrive.charging-status-channel.label = Charging Status +channel-type.bmwconnecteddrive.check-control-channel.label = Check Control +channel-type.bmwconnecteddrive.checkcontrol-details-channel.label = CheckControl Details +channel-type.bmwconnecteddrive.checkcontrol-mileage-channel.label = Mileage Occurrence +channel-type.bmwconnecteddrive.checkcontrol-name-channel.label = CheckControl Description +channel-type.bmwconnecteddrive.destination-gps-channel.label = GPS Coordinates +channel-type.bmwconnecteddrive.destination-name-channel.label = Name +channel-type.bmwconnecteddrive.distance-channel.label = Last Trip Distance +channel-type.bmwconnecteddrive.distance-since-charging-channel.label = Distance since Charge +channel-type.bmwconnecteddrive.distance-since-charging-channel.description = Total distance driven since last charging +channel-type.bmwconnecteddrive.doors-channel.label = Overall Door Status +channel-type.bmwconnecteddrive.driver-front-channel.label = Driver Door +channel-type.bmwconnecteddrive.driver-rear-channel.label = Driver Door Rear +channel-type.bmwconnecteddrive.gps-channel.label = GPS Coordinates +channel-type.bmwconnecteddrive.heading-channel.label = Heading Angle +channel-type.bmwconnecteddrive.hood-channel.label = Hood +channel-type.bmwconnecteddrive.image-size-channel.label = Image Size +channel-type.bmwconnecteddrive.image-view-channel.label = Image Viewport +channel-type.bmwconnecteddrive.image-view-channel.command.option.FRONT = Front View +channel-type.bmwconnecteddrive.image-view-channel.command.option.REAR = Rear View +channel-type.bmwconnecteddrive.image-view-channel.command.option.SIDE = Side View +channel-type.bmwconnecteddrive.image-view-channel.command.option.DASHBOARD = Dashboard View +channel-type.bmwconnecteddrive.image-view-channel.command.option.DRIVERDOOR = Driver Door View +channel-type.bmwconnecteddrive.last-update-channel.label = Last Status Timestamp +channel-type.bmwconnecteddrive.last-update-channel.state.pattern = %1$tA, %1$td.%1$tm. %1$tH:%1$tM +channel-type.bmwconnecteddrive.last-update-reason-channel.label = Last Status Timestamp Reason +channel-type.bmwconnecteddrive.lock-channel.label = Doors Locked +channel-type.bmwconnecteddrive.mileage-channel.label = Total Distance Driven +channel-type.bmwconnecteddrive.next-service-date-channel.label = Next Service Date +channel-type.bmwconnecteddrive.next-service-date-channel.state.pattern = %1$tb %1$tY +channel-type.bmwconnecteddrive.next-service-mileage-channel.label = Mileage Till Next Service +channel-type.bmwconnecteddrive.override-departure-channel.label = OT Departure Time +channel-type.bmwconnecteddrive.override-departure-channel.description = Departure time for override timer +channel-type.bmwconnecteddrive.override-departure-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.override-enabled-channel.label = OT Enabled +channel-type.bmwconnecteddrive.override-enabled-channel.description = Override timer enabled +channel-type.bmwconnecteddrive.passenger-front-channel.label = Passenger Door +channel-type.bmwconnecteddrive.passenger-rear-channel.label = Passenger Door Rear +channel-type.bmwconnecteddrive.plug-connection-channel.label = Plug Connection Status +channel-type.bmwconnecteddrive.png-channel.label = Rendered Vehicle Image +channel-type.bmwconnecteddrive.profile-climate-channel.label = A/C at Departure Time +channel-type.bmwconnecteddrive.profile-mode-channel.label = Charge Mode +channel-type.bmwconnecteddrive.profile-mode-channel.description = Mode for selecting immediate or delyed charging +channel-type.bmwconnecteddrive.profile-mode-channel.command.option.IMMEDIATE_CHARGING = Immediate Charging +channel-type.bmwconnecteddrive.profile-mode-channel.command.option.DELAYED_CHARGING = Prefer Charging in Charging Window +channel-type.bmwconnecteddrive.profile-prefs-channel.label = Charge Preferences +channel-type.bmwconnecteddrive.profile-prefs-channel.description = Preferences for delayed charging +channel-type.bmwconnecteddrive.profile-prefs-channel.command.option.NO_PRESELECTION = No Preference +channel-type.bmwconnecteddrive.profile-prefs-channel.command.option.CHARGING_WINDOW = Charging Window +channel-type.bmwconnecteddrive.range-electric-channel.label = Electric Range +channel-type.bmwconnecteddrive.range-electric-max-channel.label = Electric Range if Fully Charged +channel-type.bmwconnecteddrive.range-fuel-channel.label = Fuel Range +channel-type.bmwconnecteddrive.range-hybrid-channel.label = Hybrid Range +channel-type.bmwconnecteddrive.range-hybrid-max-channel.label = Hybrid Range if Fully Charged +channel-type.bmwconnecteddrive.range-radius-electric-channel.label = Electric Range Radius if Fully Charged +channel-type.bmwconnecteddrive.range-radius-electric-max-channel.label = Electric Range Radius +channel-type.bmwconnecteddrive.range-radius-fuel-channel.label = Fuel Range Radius +channel-type.bmwconnecteddrive.range-radius-hybrid-channel.label = Hybrid Range Radius +channel-type.bmwconnecteddrive.range-radius-hybrid-max-channel.label = Hybrid Range Radius if Fully Charged +channel-type.bmwconnecteddrive.remaining-fuel-channel.label = Remaining Fuel +channel-type.bmwconnecteddrive.remote-command-channel.label = Remote Command +channel-type.bmwconnecteddrive.remote-state-channel.label = Service Execution State +channel-type.bmwconnecteddrive.service-date-channel.label = Service Date +channel-type.bmwconnecteddrive.service-date-channel.state.pattern = %1$tb %1$tY +channel-type.bmwconnecteddrive.service-details-channel.label = Service Details +channel-type.bmwconnecteddrive.service-mileage-channel.label = Mileage till Service +channel-type.bmwconnecteddrive.service-name-channel.label = Service Name +channel-type.bmwconnecteddrive.single-longest-distance-channel.label = Longest 1-Charge Distance +channel-type.bmwconnecteddrive.soc-channel.label = Battery Charge Level +channel-type.bmwconnecteddrive.soc-max-channel.label = Max Battery Capacity +channel-type.bmwconnecteddrive.sunroof-channel.label = Sunroof +channel-type.bmwconnecteddrive.timer1-day-fri-channel.label = T1 Friday +channel-type.bmwconnecteddrive.timer1-day-fri-channel.description = Friday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-mon-channel.label = T1 Monday +channel-type.bmwconnecteddrive.timer1-day-mon-channel.description = Monday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-sat-channel.label = T1 Saturday +channel-type.bmwconnecteddrive.timer1-day-sat-channel.description = Saturday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-sun-channel.label = T1 Sunday +channel-type.bmwconnecteddrive.timer1-day-sun-channel.description = Sunday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-thu-channel.label = T1 Thursday +channel-type.bmwconnecteddrive.timer1-day-thu-channel.description = Thursday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-tue-channel.label = T1 Tuesday +channel-type.bmwconnecteddrive.timer1-day-tue-channel.description = Tuesday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-day-wed-channel.label = T1 Wednesday +channel-type.bmwconnecteddrive.timer1-day-wed-channel.description = Wednesday scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-days-channel.label = T1 Days +channel-type.bmwconnecteddrive.timer1-days-channel.description = Days scheduled for timer 1 +channel-type.bmwconnecteddrive.timer1-departure-channel.label = T1 Departure Time +channel-type.bmwconnecteddrive.timer1-departure-channel.description = Departure time for regular schedule timer 1 +channel-type.bmwconnecteddrive.timer1-departure-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.timer1-enabled-channel.label = T1 Enabled +channel-type.bmwconnecteddrive.timer1-enabled-channel.description = Timer 1 enabled +channel-type.bmwconnecteddrive.timer2-day-fri-channel.label = T2 Friday +channel-type.bmwconnecteddrive.timer2-day-fri-channel.description = Friday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-mon-channel.label = T2 Monday +channel-type.bmwconnecteddrive.timer2-day-mon-channel.description = Monday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-sat-channel.label = T2 Saturday +channel-type.bmwconnecteddrive.timer2-day-sat-channel.description = Saturday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-sun-channel.label = T2 Sunday +channel-type.bmwconnecteddrive.timer2-day-sun-channel.description = Sunday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-thu-channel.label = T2 Thursday +channel-type.bmwconnecteddrive.timer2-day-thu-channel.description = Thursday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-tue-channel.label = T2 Tuesday +channel-type.bmwconnecteddrive.timer2-day-tue-channel.description = Tuesday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-day-wed-channel.label = T2 Wednesday +channel-type.bmwconnecteddrive.timer2-day-wed-channel.description = Wednesday scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-days-channel.label = T2 Days +channel-type.bmwconnecteddrive.timer2-days-channel.description = Days scheduled for timer 2 +channel-type.bmwconnecteddrive.timer2-departure-channel.label = T2 Departure Time +channel-type.bmwconnecteddrive.timer2-departure-channel.description = Departure time for regular schedule timer 2 +channel-type.bmwconnecteddrive.timer2-departure-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.timer2-enabled-channel.label = T2 Enabled +channel-type.bmwconnecteddrive.timer2-enabled-channel.description = Timer 2 enabled +channel-type.bmwconnecteddrive.timer3-day-fri-channel.label = T3 Friday +channel-type.bmwconnecteddrive.timer3-day-fri-channel.description = Friday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-mon-channel.label = T3 Monday +channel-type.bmwconnecteddrive.timer3-day-mon-channel.description = Monday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-sat-channel.label = T3 Saturday +channel-type.bmwconnecteddrive.timer3-day-sat-channel.description = Saturday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-sun-channel.label = T3 Sunday +channel-type.bmwconnecteddrive.timer3-day-sun-channel.description = Sunday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-thu-channel.label = T3 Thursday +channel-type.bmwconnecteddrive.timer3-day-thu-channel.description = Thursday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-tue-channel.label = T3 Tuesday +channel-type.bmwconnecteddrive.timer3-day-tue-channel.description = Tuesday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-day-wed-channel.label = T3 Wednesday +channel-type.bmwconnecteddrive.timer3-day-wed-channel.description = Wednesday scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-days-channel.label = T3 Days +channel-type.bmwconnecteddrive.timer3-days-channel.description = Days scheduled for timer 3 +channel-type.bmwconnecteddrive.timer3-departure-channel.label = T3 Departure Time +channel-type.bmwconnecteddrive.timer3-departure-channel.description = Departure time for regular schedule timer 3 +channel-type.bmwconnecteddrive.timer3-departure-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.timer3-enabled-channel.label = T3 Enabled +channel-type.bmwconnecteddrive.timer3-enabled-channel.description = Timer 3 enabled +channel-type.bmwconnecteddrive.total-driven-distance-channel.label = Total Electric Distance +channel-type.bmwconnecteddrive.trip-date-time-channel.label = Date and Time +channel-type.bmwconnecteddrive.trip-date-time-channel.state.pattern = %1$tA, %1$td.%1$tm. %1$tH:%1$tM +channel-type.bmwconnecteddrive.trip-duration-channel.label = Last Trip Duration +channel-type.bmwconnecteddrive.trunk-channel.label = Trunk +channel-type.bmwconnecteddrive.window-driver-front-channel.label = Driver Window +channel-type.bmwconnecteddrive.window-driver-rear-channel.label = Driver Rear Window +channel-type.bmwconnecteddrive.window-end-channel.label = Window End Time +channel-type.bmwconnecteddrive.window-end-channel.description = End time of charging window +channel-type.bmwconnecteddrive.window-end-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.window-passenger-front-channel.label = Passenger Window +channel-type.bmwconnecteddrive.window-passenger-rear-channel.label = Passenger Rear Window +channel-type.bmwconnecteddrive.window-rear-channel.label = Rear Window +channel-type.bmwconnecteddrive.window-start-channel.label = Window Start Time +channel-type.bmwconnecteddrive.window-start-channel.description = Start time of charging window +channel-type.bmwconnecteddrive.window-start-channel.state.pattern = %1$tH:%1$tM +channel-type.bmwconnecteddrive.windows-channel.label = Overall Window Status diff --git a/bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/i18n/boschindego.properties b/bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/i18n/boschindego.properties new file mode 100644 index 0000000000000..129903570a82f --- /dev/null +++ b/bundles/org.openhab.binding.boschindego/src/main/resources/OH-INF/i18n/boschindego.properties @@ -0,0 +1,58 @@ +# binding + +binding.boschindego.name = BoschIndego Binding +binding.boschindego.description = This is the binding for Bosch Indego Connect lawn mowers. + +# thing types + +thing-type.boschindego.indego.label = Bosch Indego +thing-type.boschindego.indego.description = Indego which supports the connect feature. + +# thing types config + +thing-type.config.boschindego.indego.password.label = Password +thing-type.config.boschindego.indego.password.description = Password for the Bosch Indego account. +thing-type.config.boschindego.indego.refresh.label = Refresh Interval +thing-type.config.boschindego.indego.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.boschindego.indego.username.label = Username +thing-type.config.boschindego.indego.username.description = Username for the Bosch Indego account. + +# channel types + +channel-type.boschindego.errorcode.label = Error Code +channel-type.boschindego.errorcode.description = 0 = no error +channel-type.boschindego.mowed.label = Cut Grass +channel-type.boschindego.ready.label = Ready +channel-type.boschindego.ready.description = Indicates if mower is ready to mow +channel-type.boschindego.ready.state.option.0 = not ready +channel-type.boschindego.ready.state.option.1 = ready +channel-type.boschindego.state.label = Numeric State +channel-type.boschindego.state.state.option.1 = Mow +channel-type.boschindego.state.state.option.2 = Charge/Dock +channel-type.boschindego.state.state.option.3 = Pause +channel-type.boschindego.statecode.label = State Code +channel-type.boschindego.statecode.description = API-code of the Indego state +channel-type.boschindego.statecode.state.option.0 = Reading status +channel-type.boschindego.statecode.state.option.257 = Charging +channel-type.boschindego.statecode.state.option.258 = Docked +channel-type.boschindego.statecode.state.option.259 = Docked - Software update +channel-type.boschindego.statecode.state.option.260 = Docked +channel-type.boschindego.statecode.state.option.261 = Docked +channel-type.boschindego.statecode.state.option.262 = Docked - Loading map +channel-type.boschindego.statecode.state.option.263 = Docked - Saving map +channel-type.boschindego.statecode.state.option.512 = Mowing +channel-type.boschindego.statecode.state.option.514 = Relocalising +channel-type.boschindego.statecode.state.option.515 = Loading map +channel-type.boschindego.statecode.state.option.516 = Learning lawn +channel-type.boschindego.statecode.state.option.517 = Paused +channel-type.boschindego.statecode.state.option.518 = Border cut +channel-type.boschindego.statecode.state.option.519 = Idle in lawn +channel-type.boschindego.statecode.state.option.769 = Returning to Dock +channel-type.boschindego.statecode.state.option.770 = Returning to Dock +channel-type.boschindego.statecode.state.option.771 = Returning to Dock - Battery low +channel-type.boschindego.statecode.state.option.772 = Returning to Dock - Calendar timeslot ended +channel-type.boschindego.statecode.state.option.773 = Returning to Dock - Battery temp range +channel-type.boschindego.statecode.state.option.774 = Returning to Dock +channel-type.boschindego.statecode.state.option.775 = Returning to Dock - Lawn complete +channel-type.boschindego.statecode.state.option.775 = Returning to Dock - Relocalising +channel-type.boschindego.textualstate.label = Textual State diff --git a/bundles/org.openhab.binding.bosesoundtouch/src/main/resources/OH-INF/i18n/bosesoundtouch.properties b/bundles/org.openhab.binding.bosesoundtouch/src/main/resources/OH-INF/i18n/bosesoundtouch.properties new file mode 100644 index 0000000000000..a2c0455b36c88 --- /dev/null +++ b/bundles/org.openhab.binding.bosesoundtouch/src/main/resources/OH-INF/i18n/bosesoundtouch.properties @@ -0,0 +1,183 @@ +# binding + +binding.bosesoundtouch.name = Bose SoundTouch Binding +binding.bosesoundtouch.description = This is the binding for Bose SoundTouch devices. + +# thing types + +thing-type.bosesoundtouch.10.label = Bose SoundTouch 10 +thing-type.bosesoundtouch.10.description = Bose SoundTouch 10 Speaker +thing-type.bosesoundtouch.20.label = Bose SoundTouch 20 +thing-type.bosesoundtouch.20.description = Bose SoundTouch 20 Speaker +thing-type.bosesoundtouch.30.label = Bose SoundTouch 30 +thing-type.bosesoundtouch.30.description = Bose SoundTouch 30 Speaker +thing-type.bosesoundtouch.300.label = Bose SoundTouch 300 +thing-type.bosesoundtouch.300.description = Bose SoundTouch 300 Speaker +thing-type.bosesoundtouch.device.label = Bose SoundTouch Device +thing-type.bosesoundtouch.device.description = Aan unknown Bose SoundTouch Device +thing-type.bosesoundtouch.sa5Amplifier.label = Bose SoundTouch SA-5 Amplifier +thing-type.bosesoundtouch.sa5Amplifier.description = A Bose SoundTouch SA-5 Amplifier +thing-type.bosesoundtouch.waveSoundTouchMusicSystemIV.label = Bose Wave SoundTouch Music System IV +thing-type.bosesoundtouch.waveSoundTouchMusicSystemIV.description = A Bose Wave SoundTouch Music System IV +thing-type.bosesoundtouch.wirelessLinkAdapter.label = Bose SoundTouch Wireless Link Adapter +thing-type.bosesoundtouch.wirelessLinkAdapter.description = Bose SoundTouch Wireless Link Adapter + +# thing types config + +thing-type.config.bosesoundtouch.config.appKey.label = Authorization Key +thing-type.config.bosesoundtouch.config.appKey.description = An authorization key used to identify the client application. Should be requested from the developer portal. +thing-type.config.bosesoundtouch.config.host.label = Host Address +thing-type.config.bosesoundtouch.config.host.description = The Host / IP Address used for communication to this device. +thing-type.config.bosesoundtouch.config.macAddress.label = MAC Address +thing-type.config.bosesoundtouch.config.macAddress.description = The MAC Address used for communication to this device. + +# channel types + +channel-type.bosesoundtouch.bass.label = Bass +channel-type.bosesoundtouch.bass.description = Bass (-9 minimum, 0 maximum) +channel-type.bosesoundtouch.keyCode.label = Remote Key Code +channel-type.bosesoundtouch.keyCode.description = Simulates pushing a remote control button +channel-type.bosesoundtouch.keyCode.state.option.PLAY = Play +channel-type.bosesoundtouch.keyCode.state.option.PAUSE = Pause +channel-type.bosesoundtouch.keyCode.state.option.STOP = Stop +channel-type.bosesoundtouch.keyCode.state.option.PREV_TRACK = Prev Track +channel-type.bosesoundtouch.keyCode.state.option.NEXT_TRACK = Next Track +channel-type.bosesoundtouch.keyCode.state.option.THUMBS_UP = Thumbs Up +channel-type.bosesoundtouch.keyCode.state.option.THUMBS_DOWN = Thumbs Down +channel-type.bosesoundtouch.keyCode.state.option.BOOKMARK = Bookmark +channel-type.bosesoundtouch.keyCode.state.option.POWER = Power +channel-type.bosesoundtouch.keyCode.state.option.MUTE = Mute +channel-type.bosesoundtouch.keyCode.state.option.VOLUME_UP = Volume Up +channel-type.bosesoundtouch.keyCode.state.option.VOLUME_DOWN = Volume Down +channel-type.bosesoundtouch.keyCode.state.option.PRESET_1 = Preset 1 +channel-type.bosesoundtouch.keyCode.state.option.PRESET_2 = Preset 2 +channel-type.bosesoundtouch.keyCode.state.option.PRESET_3 = Preset 3 +channel-type.bosesoundtouch.keyCode.state.option.PRESET_4 = Preset 4 +channel-type.bosesoundtouch.keyCode.state.option.PRESET_5 = Preset 5 +channel-type.bosesoundtouch.keyCode.state.option.PRESET_6 = Preset 6 +channel-type.bosesoundtouch.keyCode.state.option.AUX_INPUT = AUX Input +channel-type.bosesoundtouch.keyCode.state.option.SHUFFLE_OFF = Shuffle Off +channel-type.bosesoundtouch.keyCode.state.option.SHUFFLE_ON = Shuffle On +channel-type.bosesoundtouch.keyCode.state.option.REPEAT_OFF = Repeat Off +channel-type.bosesoundtouch.keyCode.state.option.REPEAT_ONE = Repeat One +channel-type.bosesoundtouch.keyCode.state.option.REPEAT_ALL = Repeat All +channel-type.bosesoundtouch.keyCode.state.option.PLAY_PAUSE = Play/Pause +channel-type.bosesoundtouch.keyCode.state.option.ADD_FAVORITE = Add Favorite +channel-type.bosesoundtouch.keyCode.state.option.REMOVE_FAVORITE = Remove Favorite +channel-type.bosesoundtouch.mute.label = Mute +channel-type.bosesoundtouch.mute.description = Mutes the sound +channel-type.bosesoundtouch.notificationsound.label = Notification Sound +channel-type.bosesoundtouch.notificationsound.description = Play a notification sound by a given URI +channel-type.bosesoundtouch.nowPlayingAlbum.label = Album +channel-type.bosesoundtouch.nowPlayingAlbum.description = Current playing album name +channel-type.bosesoundtouch.nowPlayingArtist.label = Artist +channel-type.bosesoundtouch.nowPlayingArtist.description = Current playing artist name +channel-type.bosesoundtouch.nowPlayingArtwork.label = Artwork +channel-type.bosesoundtouch.nowPlayingArtwork.description = Artwork for the current playing song +channel-type.bosesoundtouch.nowPlayingDescription.label = Description +channel-type.bosesoundtouch.nowPlayingDescription.description = Description to current playing song +channel-type.bosesoundtouch.nowPlayingGenre.label = Genre +channel-type.bosesoundtouch.nowPlayingGenre.description = Genre of current playing song +channel-type.bosesoundtouch.nowPlayingItemName.label = Now Playing +channel-type.bosesoundtouch.nowPlayingItemName.description = Visible description shown in display +channel-type.bosesoundtouch.nowPlayingStationLocation.label = Station Location +channel-type.bosesoundtouch.nowPlayingStationLocation.description = Location of current playing radio station +channel-type.bosesoundtouch.nowPlayingStationName.label = Station Name +channel-type.bosesoundtouch.nowPlayingStationName.description = Name of current playing radio station +channel-type.bosesoundtouch.nowPlayingTrack.label = Track +channel-type.bosesoundtouch.nowPlayingTrack.description = Track currently playing +channel-type.bosesoundtouch.operationMode_BST_10_20_30.label = Operation Mode +channel-type.bosesoundtouch.operationMode_BST_10_20_30.description = Current Operation Mode +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.STANDBY = Standby +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.INTERNET_RADIO = Internet Radio +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.BLUETOOTH = Bluetooth +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.STORED_MUSIC = Stored Music +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.AUX = AUX +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.SPOTIFY = Spotify +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.PANDORA = Pandora +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.DEEZER = Deezer +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.SIRIUSXM = SiriusXM +channel-type.bosesoundtouch.operationMode_BST_10_20_30.state.option.AMAZON = Amazon +channel-type.bosesoundtouch.operationMode_BST_300.label = Operation Mode +channel-type.bosesoundtouch.operationMode_BST_300.description = Current Operation Mode +channel-type.bosesoundtouch.operationMode_BST_300.state.option.STANDBY = Standby +channel-type.bosesoundtouch.operationMode_BST_300.state.option.INTERNET_RADIO = Internet Radio +channel-type.bosesoundtouch.operationMode_BST_300.state.option.BLUETOOTH = Bluetooth +channel-type.bosesoundtouch.operationMode_BST_300.state.option.STORED_MUSIC = Stored Music +channel-type.bosesoundtouch.operationMode_BST_300.state.option.TV = TV +channel-type.bosesoundtouch.operationMode_BST_300.state.option.HDMI = HDMI +channel-type.bosesoundtouch.operationMode_BST_300.state.option.SPOTIFY = Spotify +channel-type.bosesoundtouch.operationMode_BST_300.state.option.PANDORA = Pandora +channel-type.bosesoundtouch.operationMode_BST_300.state.option.DEEZER = Deezer +channel-type.bosesoundtouch.operationMode_BST_300.state.option.SIRIUSXM = SiriusXM +channel-type.bosesoundtouch.operationMode_BST_300.state.option.AMAZON = Amazon +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.label = Operation Mode +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.description = Bose SoundTouch current Operation Mode +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.STANDBY = Standby +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.INTERNET_RADIO = Internet Radio +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.BLUETOOTH = Bluetooth +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.STORED_MUSIC = Stored Music +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.AUX1 = AUX1 +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.AUX2 = AUX2 +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.AUX3 = AUX3 +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.SPOTIFY = Spotify +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.PANDORA = Pandora +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.DEEZER = Deezer +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.SIRIUSXM = SiriusXM +channel-type.bosesoundtouch.operationMode_BST_SA5_Amplifier.state.option.AMAZON = Amazon +channel-type.bosesoundtouch.operationMode_BST_WLA.label = Operation Mode +channel-type.bosesoundtouch.operationMode_BST_WLA.description = Current Operation Mode +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.STANDBY = Standby +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.INTERNET_RADIO = Internet Radio +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.BLUETOOTH = Bluetooth +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.STORED_MUSIC = Stored Music +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.AUX = AUX +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.SPOTIFY = Spotify +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.PANDORA = Pandora +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.DEEZER = Deezer +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.SIRIUSXM = SiriusXM +channel-type.bosesoundtouch.operationMode_BST_WLA.state.option.AMAZON = Amazon +channel-type.bosesoundtouch.operationMode_default.label = Operation Mode +channel-type.bosesoundtouch.operationMode_default.description = Current Operation Mode +channel-type.bosesoundtouch.operationMode_default.state.option.STANDBY = Standby +channel-type.bosesoundtouch.operationMode_default.state.option.INTERNET_RADIO = Internet Radio +channel-type.bosesoundtouch.operationMode_default.state.option.BLUETOOTH = Bluetooth +channel-type.bosesoundtouch.operationMode_default.state.option.STORED_MUSIC = Stored Music +channel-type.bosesoundtouch.operationMode_default.state.option.AUX = AUX +channel-type.bosesoundtouch.operationMode_default.state.option.AUX1 = AUX1 +channel-type.bosesoundtouch.operationMode_default.state.option.AUX2 = AUX2 +channel-type.bosesoundtouch.operationMode_default.state.option.AUX3 = AUX3 +channel-type.bosesoundtouch.operationMode_default.state.option.TV = TV +channel-type.bosesoundtouch.operationMode_default.state.option.HDMI = HDMI +channel-type.bosesoundtouch.operationMode_default.state.option.SPOTIFY = Spotify +channel-type.bosesoundtouch.operationMode_default.state.option.PANDORA = Pandora +channel-type.bosesoundtouch.operationMode_default.state.option.DEEZER = Deezer +channel-type.bosesoundtouch.operationMode_default.state.option.SIRIUSXM = SiriusXM +channel-type.bosesoundtouch.operationMode_default.state.option.AMAZON = Amazon +channel-type.bosesoundtouch.playerControl.label = Player Control +channel-type.bosesoundtouch.playerControl.description = Control the Player +channel-type.bosesoundtouch.power.label = Power +channel-type.bosesoundtouch.power.description = SoundTouch power state +channel-type.bosesoundtouch.preset.label = Preset +channel-type.bosesoundtouch.preset.description = 1-6 Preset of Soundtouch, >7 Binding Presets +channel-type.bosesoundtouch.rateEnabled.label = Rating Enabled +channel-type.bosesoundtouch.rateEnabled.description = Current source allows rating +channel-type.bosesoundtouch.saveAsPreset.label = Save as Preset +channel-type.bosesoundtouch.saveAsPreset.description = A selected presetable Contentitem is save as Preset with number >6 +channel-type.bosesoundtouch.skipEnabled.label = Skip Enabled +channel-type.bosesoundtouch.skipEnabled.description = Current source allows skipping to next track +channel-type.bosesoundtouch.skipPreviousEnabled.label = Skip/Previous Enabled +channel-type.bosesoundtouch.skipPreviousEnabled.description = Current source allows scrolling through tracks +channel-type.bosesoundtouch.volume.label = Volume +channel-type.bosesoundtouch.volume.description = Set or get the volume + +# channel types config + +channel-type.config.bosesoundtouch.notificationSound.notificationMessage.label = Notification Message +channel-type.config.bosesoundtouch.notificationSound.notificationMessage.description = This indicates further details about the notification. This text will appear on the device display (when available) and the SoundTouch application screen. If a message string is not provided, the field with be blank. +channel-type.config.bosesoundtouch.notificationSound.notificationReason.label = Notification Reason +channel-type.config.bosesoundtouch.notificationSound.notificationReason.description = This indicates the reason for the notification. This text will appear on the device display (when available) and the SoundTouch application screen. If a reason string is not provided, the field with be blank. +channel-type.config.bosesoundtouch.notificationSound.notificationService.label = Notification Service +channel-type.config.bosesoundtouch.notificationSound.notificationService.description = This indicates the service providing the notification. This text will appear on the device display (when available) and the SoundTouch application screen. +channel-type.config.bosesoundtouch.notificationSound.notificationVolume.label = Notification Sound Volume +channel-type.config.bosesoundtouch.notificationSound.notificationVolume.description = This indicates the desired volume level while playing the notification. The value represents a percentage (0 to 100) of the full audible range of the speaker device. A value less than 10 or greater than 70 will result in an error and not play the notification. Upon completion of the notification, the speaker volume will return to its original value. If not present, the notification will play at the existing volume level. diff --git a/bundles/org.openhab.binding.broadlinkthermostat/src/main/resources/OH-INF/i18n/broadlinkthermostat.properties b/bundles/org.openhab.binding.broadlinkthermostat/src/main/resources/OH-INF/i18n/broadlinkthermostat.properties new file mode 100644 index 0000000000000..8521440114e06 --- /dev/null +++ b/bundles/org.openhab.binding.broadlinkthermostat/src/main/resources/OH-INF/i18n/broadlinkthermostat.properties @@ -0,0 +1,48 @@ +# binding + +binding.broadlinkthermostat.name = Broadlinkthermostat Binding +binding.broadlinkthermostat.description = This is the binding for Broadlinkthermostat devices. + +# thing types + +thing-type.broadlinkthermostat.floureonthermostat.label = Floureon Thermostat +thing-type.broadlinkthermostat.floureonthermostat.description = A heating device thermostat +thing-type.broadlinkthermostat.hysenthermostat.label = Hysen Thermostat +thing-type.broadlinkthermostat.hysenthermostat.description = A heating device thermostat + +# thing types config + +thing-type.config.broadlinkthermostat.floureonandhysenthermostat.host.label = Hostname +thing-type.config.broadlinkthermostat.floureonandhysenthermostat.host.description = The hostname/IP address the device is bound to, e.g. 192.168.0.2 +thing-type.config.broadlinkthermostat.floureonandhysenthermostat.macAddress.label = MAC Address +thing-type.config.broadlinkthermostat.floureonandhysenthermostat.macAddress.description = The unique MAC address of the device, e.g. 00:10:FA:6E:38:4A + +# channel types + +channel-type.broadlinkthermostat.active.label = Active +channel-type.broadlinkthermostat.active.description = Shows if thermostat is currently actively heating +channel-type.broadlinkthermostat.mode.label = Mode +channel-type.broadlinkthermostat.mode.description = Current mode of the thermostat +channel-type.broadlinkthermostat.mode.state.option.auto = auto +channel-type.broadlinkthermostat.mode.state.option.manual = manual +channel-type.broadlinkthermostat.power.label = Power +channel-type.broadlinkthermostat.power.description = Switch display on/off and enable/disables heating +channel-type.broadlinkthermostat.remotelock.label = Remote Lock +channel-type.broadlinkthermostat.remotelock.description = Locks the device to only allow remote actions +channel-type.broadlinkthermostat.roomtemperature.label = Temperature +channel-type.broadlinkthermostat.roomtemperature.description = Room temperature, measured directly at the device +channel-type.broadlinkthermostat.roomtemperatureexternalsensor.label = Temperature Ext. Sensor +channel-type.broadlinkthermostat.roomtemperatureexternalsensor.description = Room temperature, measured by the external sensor +channel-type.broadlinkthermostat.sensor.label = Sensor +channel-type.broadlinkthermostat.sensor.description = The sensor (internal/external) used for triggering the thermostat +channel-type.broadlinkthermostat.sensor.state.option.internal = internal +channel-type.broadlinkthermostat.sensor.state.option.external = external +channel-type.broadlinkthermostat.sensor.state.option.internal_temp_external_limit = internal control temperature; external limit temperature +channel-type.broadlinkthermostat.setpoint.label = Setpoint +channel-type.broadlinkthermostat.setpoint.description = Temperature setpoint that open/close valve +channel-type.broadlinkthermostat.temperature.label = Temperature +channel-type.broadlinkthermostat.temperature.description = Temperature +channel-type.broadlinkthermostat.temperatureoffset.label = Temperature Offset +channel-type.broadlinkthermostat.temperatureoffset.description = Manual temperature adjustment +channel-type.broadlinkthermostat.time.label = Time +channel-type.broadlinkthermostat.time.description = The time and day of week diff --git a/bundles/org.openhab.binding.bsblan/src/main/resources/OH-INF/i18n/bsblan.properties b/bundles/org.openhab.binding.bsblan/src/main/resources/OH-INF/i18n/bsblan.properties new file mode 100644 index 0000000000000..4528e6b0e42c7 --- /dev/null +++ b/bundles/org.openhab.binding.bsblan/src/main/resources/OH-INF/i18n/bsblan.properties @@ -0,0 +1,53 @@ +# binding + +binding.bsblan.name = BSB-LAN Binding +binding.bsblan.description = Binding for BSB-LAN Gateway. + +# thing types + +thing-type.bsblan.bridge.label = BSB-LAN Bridge +thing-type.bsblan.bridge.description = A bridge to connect a BSB-LAN device +thing-type.bsblan.parameter.label = Parameter +thing-type.bsblan.parameter.description = Represents a single parameter available at the BSB-LAN device and identified by a numeric id. + +# thing types config + +thing-type.config.bsblan.bridge.group.network.label = Network Settings +thing-type.config.bsblan.bridge.host.label = Host +thing-type.config.bsblan.bridge.host.description = The hostname or IP address of the BSB-LAN device. +thing-type.config.bsblan.bridge.passkey.label = Passkey +thing-type.config.bsblan.bridge.passkey.description = The passkey required to access the BSB-LAN device. +thing-type.config.bsblan.bridge.password.label = Password +thing-type.config.bsblan.bridge.password.description = The password required to access the BSB-LAN device (when using HTTP Basic Authentication). +thing-type.config.bsblan.bridge.port.label = Port +thing-type.config.bsblan.bridge.port.description = The port BSB-LAN device. +thing-type.config.bsblan.bridge.refreshInterval.label = Refresh Interval +thing-type.config.bsblan.bridge.refreshInterval.description = Specifies the refresh interval in seconds. +thing-type.config.bsblan.bridge.username.label = Username +thing-type.config.bsblan.bridge.username.description = The username required to access the BSB-LAN device (when using HTTP Basic Authentication). +thing-type.config.bsblan.parameter.group.change-requests.label = Change Requests +thing-type.config.bsblan.parameter.id.label = Parameter ID +thing-type.config.bsblan.parameter.id.description = Specific parameter identifier +thing-type.config.bsblan.parameter.setId.label = Parameter Set-ID +thing-type.config.bsblan.parameter.setId.description = Parameter identifier used for change requests. Defaults to the value of Parameter ID +thing-type.config.bsblan.parameter.setType.label = Message Type +thing-type.config.bsblan.parameter.setType.description = Message type used for change requests. Defaults to SET. +thing-type.config.bsblan.parameter.setType.option.INF = INF +thing-type.config.bsblan.parameter.setType.option.SET = SET + +# channel types + +channel-type.bsblan.parameter_datatype.label = Data Type +channel-type.bsblan.parameter_datatype.description = Data type of the parameter +channel-type.bsblan.parameter_description.label = Description +channel-type.bsblan.parameter_description.description = Description of the parameter +channel-type.bsblan.parameter_name.label = Name +channel-type.bsblan.parameter_name.description = Name of the parameter +channel-type.bsblan.parameter_number_value.label = Value +channel-type.bsblan.parameter_number_value.description = Value of the parameter +channel-type.bsblan.parameter_string_value.label = Value +channel-type.bsblan.parameter_string_value.description = Value of the parameter +channel-type.bsblan.parameter_switch_value.label = Value +channel-type.bsblan.parameter_switch_value.description = Value of the parameter +channel-type.bsblan.parameter_unit.label = Unit +channel-type.bsblan.parameter_unit.description = Unit of the parameter diff --git a/bundles/org.openhab.binding.bticinosmarther/src/main/resources/OH-INF/i18n/bticinosmarther.properties b/bundles/org.openhab.binding.bticinosmarther/src/main/resources/OH-INF/i18n/bticinosmarther.properties new file mode 100644 index 0000000000000..d2886b83cad3c --- /dev/null +++ b/bundles/org.openhab.binding.bticinosmarther/src/main/resources/OH-INF/i18n/bticinosmarther.properties @@ -0,0 +1,116 @@ +# binding + +binding.bticinosmarther.name = BTicino Smarther Binding +binding.bticinosmarther.description = This is the binding for BTicino Smarther chronothermostat units + +# thing types + +thing-type.bticinosmarther.bridge.label = BTicino Smarther Bridge +thing-type.bticinosmarther.bridge.description = This bridge represents the gateway to Smarther API in the context of one specific BTicino/Legrand developer account.
If you want to control your devices in the context of different accounts you have to register a bridge for each account.

How-To configure the bridge:
  • Sign up for a new developer account on Works with Legrand website
  • Subscribe to "Starter Kit for Legrand APIs" from API > Subscriptions menu
    • This will generate your primary and secondary "Subscription Key"
  • Register a new application from User > My Applications menu
    • In "First Reply Url" field insert the public callback URL "https://<your openHAB host>:<your openHAB port>/smarther/connectsmarther"
    • Tick the checkbox near "comfort.read" and "comfort.write" scopes
    You should receive an email from Legrand, usually within 1-2 days max, containing your application's "Client ID" and "Client Secret".
How-To authorize the bridge:
  • Create and configure a bridge Thing first, using above Subscription Key + Client ID + Client Secret, then
  • Open in your browser the public URL "https://<your openHAB host>:<your openHAB port>/smarther/connectsmarther", and
  • Follow the steps reported therein to authorize the bridge
+thing-type.bticinosmarther.module.label = BTicino Smarther Chronothermostat +thing-type.bticinosmarther.module.description = This thing represents a BTicino Smarther chronothermostat module. + +# thing types config + +bridge-type.config.smarther.bridge.clientId.label = Client ID +bridge-type.config.smarther.bridge.clientId.description = This is the Client ID provided by BTicino/Legrand when you add a new Application to your developer account. Go to https://developer.legrand.com/tutorials/create-an-application/ +bridge-type.config.smarther.bridge.clientSecret.label = Client Secret +bridge-type.config.smarther.bridge.clientSecret.description = This is the Client Secret provided by BTicino/Legrand when you add a new Application to your developer account. +bridge-type.config.smarther.bridge.group.advancedset.label = Advanced Settings +bridge-type.config.smarther.bridge.group.advancedset.description = Advanced settings of this bridge. +bridge-type.config.smarther.bridge.group.application.label = Application Details +bridge-type.config.smarther.bridge.group.application.description = Details of the Smarther application registered on the BTicino/Legrand development portal. +bridge-type.config.smarther.bridge.group.subscription.label = Product Subscription +bridge-type.config.smarther.bridge.group.subscription.description = Details of the Smarther product subscription connected to the BTicino/Legrand development account. +bridge-type.config.smarther.bridge.statusRefreshPeriod.label = Bridge Status Refresh Period (minutes) +bridge-type.config.smarther.bridge.statusRefreshPeriod.description = This is the frequency the Smarther API gateway is called to update bridge status. There are limits to the number of requests that can be sent to the Smarther API gateway. The more often you poll, the faster locations are updated - at the risk of running out of your request quota. +bridge-type.config.smarther.bridge.subscriptionKey.label = Subscription Key +bridge-type.config.smarther.bridge.subscriptionKey.description = This is the Subscription Key provided by BTicino/Legrand when you subscribe to Smarther - v2.0 product. Go to https://developer.legrand.com/tutorials/getting-started/ +bridge-type.config.smarther.bridge.useNotifications.label = Use Notifications +bridge-type.config.smarther.bridge.useNotifications.description = ON = the bridge subscribes each of its locations to receive C2C notifications upon changes on each of its modules' status or sensors data - temperature, humidity (requires a public https endpoint has been set as "First Reply Url" when registering the Application on Legrand's development portal); OFF = for each module connected to this bridge, status+sensors data are requested to Smarther API gateway on a periodical basis and whenever new settings are applied (period can be changed via module's "Status Refresh Period" parameter). +thing-type.config.smarther.module.group.advancedset.label = Advanced Settings +thing-type.config.smarther.module.group.advancedset.description = Advanced settings of this module. +thing-type.config.smarther.module.group.topology.label = Module Topology +thing-type.config.smarther.module.group.topology.description = Reference to uniquely identify the module towards the BTicino/Legrand API gateway. +thing-type.config.smarther.module.moduleId.label = Chronothermostat Module Id +thing-type.config.smarther.module.moduleId.description = This is the Module Id of the Chronothermostat module, provided by Smarther API. +thing-type.config.smarther.module.numberOfEndDays.label = Number Of Days For End Date +thing-type.config.smarther.module.numberOfEndDays.description = This is the number of days to be displayed in module settings, as options list for "End Date" field in "manual" mode (e.g. 1 = only "Today" is displayed, 5 = "Today" + "Tomorrow" + following 3 days are displayed). +thing-type.config.smarther.module.plantId.label = Location Plant Id +thing-type.config.smarther.module.plantId.description = This is the Plant Id of the location the Chronothermostat module is installed in, provided by Smarther API. +thing-type.config.smarther.module.programsRefreshPeriod.label = Programs Refresh Period (hours) +thing-type.config.smarther.module.programsRefreshPeriod.description = This is the frequency the Smarther API gateway is called to refresh Programs list used in "automatic" mode. There are limits to the number of requests that can be sent to the Smarther API gateway. The more often you poll, the faster locations are updated - at the risk of running out of your request quota. +thing-type.config.smarther.module.settingsAutoupdate.label = Module Settings Auto-Update +thing-type.config.smarther.module.settingsAutoupdate.description = ON = the module settings are automatically updated according to the module status whenever it changes (e.g. polling, notification, etc.). OFF = the module settings are aligned to the module status only upon module initialization. +thing-type.config.smarther.module.statusRefreshPeriod.label = Module Status Refresh Period (minutes) +thing-type.config.smarther.module.statusRefreshPeriod.description = This is the frequency the Smarther API gateway is called to update module status and sensors data. There are limits to the number of requests that can be sent to the Smarther API gateway. The more often you poll, the faster locations are updated - at the risk of running out of your request quota. + +# channel group types + +channel-group-type.bticinosmarther.bridge-config.label = Configuration +channel-group-type.bticinosmarther.bridge-config.description = Convenience configuration channels for the bridge +channel-group-type.bticinosmarther.bridge-status.label = Status +channel-group-type.bticinosmarther.bridge-status.description = Current operational status of the bridge +channel-group-type.bticinosmarther.module-config.label = Configuration +channel-group-type.bticinosmarther.module-config.description = Convenience configuration channels for the module +channel-group-type.bticinosmarther.module-measures.label = Measures +channel-group-type.bticinosmarther.module-measures.description = Measures taken from the module on-board sensors +channel-group-type.bticinosmarther.module-settings.label = Settings +channel-group-type.bticinosmarther.module-settings.description = New operational settings to be applied to the module +channel-group-type.bticinosmarther.module-status.label = Status +channel-group-type.bticinosmarther.module-status.description = Current operational status of the module + +# channel types + +channel-type.bticinosmarther.config-fetchlocations.label = Fetch Locations List +channel-type.bticinosmarther.config-fetchlocations.description = This is a convenience switch to trigger a call to the Smarther API gateway, to manually fetch the updated client locations list. +channel-type.bticinosmarther.config-fetchprograms.label = Fetch Programs List +channel-type.bticinosmarther.config-fetchprograms.description = This is a convenience switch to trigger a call to the Smarther API gateway, to manually fetch the updated module programs list. +channel-type.bticinosmarther.measures-humidity.label = Humidity +channel-type.bticinosmarther.measures-humidity.description = Indoor humidity as measured by the sensor +channel-type.bticinosmarther.measures-temperature.label = Temperature +channel-type.bticinosmarther.measures-temperature.description = Indoor temperature as measured by the sensor +channel-type.bticinosmarther.settings-boosttime.label = Boost Time +channel-type.bticinosmarther.settings-boosttime.description = New operational boost time to be set on the module (valid only for Mode = "Boost") +channel-type.bticinosmarther.settings-boosttime.state.option.30 = 30 min +channel-type.bticinosmarther.settings-boosttime.state.option.60 = 60 min +channel-type.bticinosmarther.settings-boosttime.state.option.90 = 90 min +channel-type.bticinosmarther.settings-enddate.label = End Date +channel-type.bticinosmarther.settings-enddate.description = New operational end date to be set on the module (valid only for Mode = "Manual") +channel-type.bticinosmarther.settings-endhour.label = End Hour +channel-type.bticinosmarther.settings-endhour.description = New operational end hour to be set on the module (valid only for Mode = "Manual") +channel-type.bticinosmarther.settings-endminute.label = End Minute +channel-type.bticinosmarther.settings-endminute.description = New operational end minute to be set on the module (valid only for Mode = "Manual") +channel-type.bticinosmarther.settings-mode.label = Mode +channel-type.bticinosmarther.settings-mode.description = New operational mode to be set on the module +channel-type.bticinosmarther.settings-mode.state.option.AUTOMATIC = Automatic +channel-type.bticinosmarther.settings-mode.state.option.MANUAL = Manual +channel-type.bticinosmarther.settings-mode.state.option.BOOST = Boost +channel-type.bticinosmarther.settings-mode.state.option.OFF = Off +channel-type.bticinosmarther.settings-mode.state.option.PROTECTION = Protection +channel-type.bticinosmarther.settings-power.label = Power +channel-type.bticinosmarther.settings-power.description = Power on, send new operational settings to the module +channel-type.bticinosmarther.settings-program.label = Program +channel-type.bticinosmarther.settings-program.description = New operational program to be set on the module (valid only for Mode = "Automatic") +channel-type.bticinosmarther.settings-temperature.label = Temperature +channel-type.bticinosmarther.settings-temperature.description = New operational set-point temperature to be set on the module (valid only for Mode = "Manual") +channel-type.bticinosmarther.status-apicallshandled.label = API Calls Handled +channel-type.bticinosmarther.status-apicallshandled.description = Total number of API calls handled by the bridge +channel-type.bticinosmarther.status-endtime.label = End Time +channel-type.bticinosmarther.status-endtime.description = Current operational end time set on the module +channel-type.bticinosmarther.status-function.label = Function +channel-type.bticinosmarther.status-function.description = Current operational function set on the module +channel-type.bticinosmarther.status-mode.label = Mode +channel-type.bticinosmarther.status-mode.description = Current operational mode set on the module +channel-type.bticinosmarther.status-notifsreceived.label = Notifications Received +channel-type.bticinosmarther.status-notifsreceived.description = Total number of C2C notifications received by the bridge +channel-type.bticinosmarther.status-notifsrejected.label = Notifications Rejected +channel-type.bticinosmarther.status-notifsrejected.description = Total number of C2C notifications rejected by the bridge +channel-type.bticinosmarther.status-program.label = Program +channel-type.bticinosmarther.status-program.description = Current operational program set on the module +channel-type.bticinosmarther.status-state.label = State +channel-type.bticinosmarther.status-state.description = Current operational state of the module +channel-type.bticinosmarther.status-temperature.label = Temperature +channel-type.bticinosmarther.status-temperature.description = Current operational target temperature set on the module +channel-type.bticinosmarther.status-temperatureformat.label = Temperature Format +channel-type.bticinosmarther.status-temperatureformat.description = Current operational temperature format of the module diff --git a/bundles/org.openhab.binding.buienradar/src/main/resources/OH-INF/i18n/buienradar.properties b/bundles/org.openhab.binding.buienradar/src/main/resources/OH-INF/i18n/buienradar.properties new file mode 100644 index 0000000000000..6d9a2a8929ecb --- /dev/null +++ b/bundles/org.openhab.binding.buienradar/src/main/resources/OH-INF/i18n/buienradar.properties @@ -0,0 +1,73 @@ +# binding + +binding.buienradar.name = Buienradar Binding +binding.buienradar.description = The Buienradar Binding periodically (5 minutes) retrieves results from the Buienradar API. For personal use only. + +# thing types + +thing-type.buienradar.rain_forecast.label = Rain Forecast +thing-type.buienradar.rain_forecast.description = Does a simple rain forecast at the specified longitude/latitude of two hours, in 5 minute increments using the buienradar.nl webservice. + +# thing types config + +thing-type.config.buienradar.rain_forecast.exponentialBackoffRetryBaseInSeconds.label = Doubling Backoff Base for Retries +thing-type.config.buienradar.rain_forecast.exponentialBackoffRetryBaseInSeconds.description = Doubling back-off base value for retries in seconds. For example, when this is 30 seconds, will retry at 30, 60, 120, 240 seconds. +thing-type.config.buienradar.rain_forecast.location.label = Location of Weather +thing-type.config.buienradar.rain_forecast.location.description = Location of weather in geographical coordinates (latitude/longitude/altitude). +thing-type.config.buienradar.rain_forecast.refreshIntervalMinutes.label = Refresh Interval +thing-type.config.buienradar.rain_forecast.refreshIntervalMinutes.description = Refresh interval in minutes +thing-type.config.buienradar.rain_forecast.retries.label = Retries +thing-type.config.buienradar.rain_forecast.retries.description = Number of retries to try to retrieve buienradar results + +# channel types + +channel-type.buienradar.actual_datetime.label = Actual Date/Time +channel-type.buienradar.actual_datetime.description = The actual date and time when the prediction was made." +channel-type.buienradar.forecast_0.label = Current Rainfall +channel-type.buienradar.forecast_0.description = Current rainfall +channel-type.buienradar.forecast_10.label = Rainfall in 10 min +channel-type.buienradar.forecast_10.description = Rainfall in 10 minutes +channel-type.buienradar.forecast_100.label = Rainfall in 100 min +channel-type.buienradar.forecast_100.description = Rainfall in 100 minutes +channel-type.buienradar.forecast_105.label = Rainfall in 105 min +channel-type.buienradar.forecast_105.description = Rainfall in 105 minutes +channel-type.buienradar.forecast_110.label = Rainfall in 110 min +channel-type.buienradar.forecast_110.description = Rainfall in 110 minutes +channel-type.buienradar.forecast_115.label = Rainfall in 115 min +channel-type.buienradar.forecast_115.description = Rainfall in 115 minutes +channel-type.buienradar.forecast_15.label = Rainfall in 15 min +channel-type.buienradar.forecast_15.description = Rainfall in 15 minutes +channel-type.buienradar.forecast_20.label = Rainfall in 20 min +channel-type.buienradar.forecast_20.description = Rainfall in 20 minutes +channel-type.buienradar.forecast_25.label = Rainfall in 25 min +channel-type.buienradar.forecast_25.description = Rainfall in 25 minutes +channel-type.buienradar.forecast_30.label = Rainfall in 30 min +channel-type.buienradar.forecast_30.description = Rainfall in 30 minutes +channel-type.buienradar.forecast_35.label = Rainfall in 35 min +channel-type.buienradar.forecast_35.description = Rainfall in 35 minutes +channel-type.buienradar.forecast_40.label = Rainfall in 40 min +channel-type.buienradar.forecast_40.description = Rainfall in 40 minutes +channel-type.buienradar.forecast_45.label = Rainfall in 45 min +channel-type.buienradar.forecast_45.description = Rainfall in 45 minutes +channel-type.buienradar.forecast_5.label = Rainfall in 5 min +channel-type.buienradar.forecast_5.description = Rainfall in 5 minutes +channel-type.buienradar.forecast_50.label = Rainfall in 50 min +channel-type.buienradar.forecast_50.description = Rainfall in 50 minutes +channel-type.buienradar.forecast_55.label = Rainfall in 55 min +channel-type.buienradar.forecast_55.description = Rainfall in 55 minutes +channel-type.buienradar.forecast_60.label = Rainfall in 60 min +channel-type.buienradar.forecast_60.description = Rainfall in 60 minutes +channel-type.buienradar.forecast_65.label = Rainfall in 65 min +channel-type.buienradar.forecast_65.description = Rainfall in 65 minutes +channel-type.buienradar.forecast_70.label = Rainfall in 70 min +channel-type.buienradar.forecast_70.description = Rainfall in 70 minutes +channel-type.buienradar.forecast_75.label = Rainfall in 75 min +channel-type.buienradar.forecast_75.description = Rainfall in 75 minutes +channel-type.buienradar.forecast_80.label = Rainfall in 80 min +channel-type.buienradar.forecast_80.description = Rainfall in 80 minutes +channel-type.buienradar.forecast_85.label = Rainfall in 85 min +channel-type.buienradar.forecast_85.description = Rainfall in 85 minutes +channel-type.buienradar.forecast_90.label = Rainfall in 90 min +channel-type.buienradar.forecast_90.description = Rainfall in 90 minutes +channel-type.buienradar.forecast_95.label = Rainfall in 95 min +channel-type.buienradar.forecast_95.description = Rainfall in 95 minutes diff --git a/bundles/org.openhab.binding.caddx/src/main/resources/OH-INF/i18n/caddx.properties b/bundles/org.openhab.binding.caddx/src/main/resources/OH-INF/i18n/caddx.properties new file mode 100644 index 0000000000000..4c23f62ec96c2 --- /dev/null +++ b/bundles/org.openhab.binding.caddx/src/main/resources/OH-INF/i18n/caddx.properties @@ -0,0 +1,372 @@ +# binding + +binding.caddx.name = Caddx Security Binding +binding.caddx.description = Binding for Caddx security system with RS232 serial interface. + +# thing types + +thing-type.caddx.bridge.label = Caddx +thing-type.caddx.bridge.description = This bridge represents the Caddx Serial interface. +thing-type.caddx.bridge.channel.send_command.label = Send Command +thing-type.caddx.bridge.channel.send_command.description = Sends an Alarm Panel Command +thing-type.caddx.keypad.label = Caddx Alarm Keypad +thing-type.caddx.keypad.description = Represents any of the keypads of the Caddx Alarm System. +thing-type.caddx.keypad.channel.keypad_key_pressed.label = Key +thing-type.caddx.keypad.channel.keypad_key_pressed.description = Key pressed +thing-type.caddx.panel.label = Caddx Alarm Panel +thing-type.caddx.panel.description = The basic representation of the Caddx Alarm System. +thing-type.caddx.panel.channel.panel_ac_fail.label = AC fail +thing-type.caddx.panel.channel.panel_ac_fail.description = AC fail +thing-type.caddx.panel.channel.panel_ac_power_on.label = AC Power On +thing-type.caddx.panel.channel.panel_ac_power_on.description = AC Power On +thing-type.caddx.panel.channel.panel_firmware_version.label = Firmware Version +thing-type.caddx.panel.channel.panel_firmware_version.description = Firmware version +thing-type.caddx.panel.channel.panel_interface_configuration_message.label = Interface Configuration Message +thing-type.caddx.panel.channel.panel_interface_configuration_message.description = Interface Configuration Message +thing-type.caddx.panel.channel.panel_interface_configuration_request.label = Interface Configuration Request +thing-type.caddx.panel.channel.panel_interface_configuration_request.description = Interface Configuration Request +thing-type.caddx.panel.channel.panel_keypad_message_received.label = Keypad Message Received +thing-type.caddx.panel.channel.panel_keypad_message_received.description = Keypad Message Received +thing-type.caddx.panel.channel.panel_keypad_terminal_mode_request.label = Keypad Terminal Mode Request +thing-type.caddx.panel.channel.panel_keypad_terminal_mode_request.description = Keypad Terminal Mode Request +thing-type.caddx.panel.channel.panel_log_event_message.label = Log Event Message +thing-type.caddx.panel.channel.panel_log_event_message.description = Log Event Message +thing-type.caddx.panel.channel.panel_log_event_request.label = Log Event Request +thing-type.caddx.panel.channel.panel_log_event_request.description = Log Event Request +thing-type.caddx.panel.channel.panel_log_message_n_0.label = Log Message 10 +thing-type.caddx.panel.channel.panel_log_message_n_0.description = Log message 10 +thing-type.caddx.panel.channel.panel_log_message_n_1.label = Log Message 9 +thing-type.caddx.panel.channel.panel_log_message_n_1.description = Log message 9 +thing-type.caddx.panel.channel.panel_log_message_n_2.label = Log Message 8 +thing-type.caddx.panel.channel.panel_log_message_n_2.description = Log message 8 +thing-type.caddx.panel.channel.panel_log_message_n_3.label = Log Message 7 +thing-type.caddx.panel.channel.panel_log_message_n_3.description = Log message 7 +thing-type.caddx.panel.channel.panel_log_message_n_4.label = Log Message 6 +thing-type.caddx.panel.channel.panel_log_message_n_4.description = Log message 6 +thing-type.caddx.panel.channel.panel_log_message_n_5.label = Log Message 5 +thing-type.caddx.panel.channel.panel_log_message_n_5.description = Log message 5 +thing-type.caddx.panel.channel.panel_log_message_n_6.label = Log Message 4 +thing-type.caddx.panel.channel.panel_log_message_n_6.description = Log message 4 +thing-type.caddx.panel.channel.panel_log_message_n_7.label = Log Message 3 +thing-type.caddx.panel.channel.panel_log_message_n_7.description = Log message 3 +thing-type.caddx.panel.channel.panel_log_message_n_8.label = Log Message 2 +thing-type.caddx.panel.channel.panel_log_message_n_8.description = Log message 2 +thing-type.caddx.panel.channel.panel_log_message_n_9.label = Log Message 1 +thing-type.caddx.panel.channel.panel_log_message_n_9.description = Log message 1 +thing-type.caddx.panel.channel.panel_low_battery_memory.label = Low Battery Memory +thing-type.caddx.panel.channel.panel_low_battery_memory.description = Low Battery Memory +thing-type.caddx.panel.channel.panel_partition_status_message.label = Partition Status Message +thing-type.caddx.panel.channel.panel_partition_status_message.description = Partition Status Message +thing-type.caddx.panel.channel.panel_partition_status_request.label = Partition Status Request +thing-type.caddx.panel.channel.panel_partition_status_request.description = Partition Status Request +thing-type.caddx.panel.channel.panel_partitions_snapshot_message.label = Partitions Snapshot Message +thing-type.caddx.panel.channel.panel_partitions_snapshot_message.description = Partitions Snapshot Message +thing-type.caddx.panel.channel.panel_partitions_snapshot_request.label = Partitions Snapshot Request +thing-type.caddx.panel.channel.panel_partitions_snapshot_request.description = Partitions Snapshot Request +thing-type.caddx.panel.channel.panel_primary_keypad_function_with_pin.label = Primary Keypad Function with PIN +thing-type.caddx.panel.channel.panel_primary_keypad_function_with_pin.description = Primary Keypad Function with PIN +thing-type.caddx.panel.channel.panel_primary_keypad_function_without_pin.label = Primary Keypad Function without PIN +thing-type.caddx.panel.channel.panel_primary_keypad_function_without_pin.description = Primary Keypad Function without PIN +thing-type.caddx.panel.channel.panel_program_data_command.label = Program Data Command +thing-type.caddx.panel.channel.panel_program_data_command.description = Program Data Command +thing-type.caddx.panel.channel.panel_program_data_request.label = Program Data Request +thing-type.caddx.panel.channel.panel_program_data_request.description = Program Data Request +thing-type.caddx.panel.channel.panel_secondary_keypad_function.label = Secondary Keypad Function +thing-type.caddx.panel.channel.panel_secondary_keypad_function.description = Secondary Keypad Function +thing-type.caddx.panel.channel.panel_send_keypad_text_message.label = Send Keypad Text Message +thing-type.caddx.panel.channel.panel_send_keypad_text_message.description = Send Keypad Text Message +thing-type.caddx.panel.channel.panel_send_x10_message.label = Send X-10 Message +thing-type.caddx.panel.channel.panel_send_x10_message.description = Send X-10 Message +thing-type.caddx.panel.channel.panel_set_clock_calendar_command.label = Set Clock / Calendar Command +thing-type.caddx.panel.channel.panel_set_clock_calendar_command.description = Set Clock / Calendar Command +thing-type.caddx.panel.channel.panel_set_user_authorization_command_with_pin.label = Set User Authorization Command with PIN +thing-type.caddx.panel.channel.panel_set_user_authorization_command_with_pin.description = Set User Authorization Command with PIN +thing-type.caddx.panel.channel.panel_set_user_authorization_command_without_pin.label = Set User Authorization Command without PIN +thing-type.caddx.panel.channel.panel_set_user_authorization_command_without_pin.description = Set User Authorization Command without PIN +thing-type.caddx.panel.channel.panel_set_user_code_command_with_pin.label = Set User Code Command with PIN +thing-type.caddx.panel.channel.panel_set_user_code_command_with_pin.description = Set User Code Command with PIN +thing-type.caddx.panel.channel.panel_set_user_code_command_without_pin.label = Set User Code Command without PIN +thing-type.caddx.panel.channel.panel_set_user_code_command_without_pin.description = Set User Code Command without PIN +thing-type.caddx.panel.channel.panel_store_communication_event_command.label = Store Communication Event Command +thing-type.caddx.panel.channel.panel_store_communication_event_command.description = Store Communication Event Command +thing-type.caddx.panel.channel.panel_system_status_message.label = System Status Message +thing-type.caddx.panel.channel.panel_system_status_message.description = System Status Message +thing-type.caddx.panel.channel.panel_system_status_request.label = System Status Request +thing-type.caddx.panel.channel.panel_system_status_request.description = System Status Request +thing-type.caddx.panel.channel.panel_user_information_request_with_pin.label = User Information Request with PIN +thing-type.caddx.panel.channel.panel_user_information_request_with_pin.description = User Information Request with PIN +thing-type.caddx.panel.channel.panel_user_information_request_without_pin.label = User Information Request without PIN +thing-type.caddx.panel.channel.panel_user_information_request_without_pin.description = User Information Request without PIN +thing-type.caddx.panel.channel.panel_x10_message_received.label = X-10 Message Received +thing-type.caddx.panel.channel.panel_x10_message_received.description = X-10 Message Received +thing-type.caddx.panel.channel.panel_zone_bypass_toggle.label = Zone Bypass Toggle +thing-type.caddx.panel.channel.panel_zone_bypass_toggle.description = Zone Bypass Toggle +thing-type.caddx.panel.channel.panel_zone_name_request.label = Zone Name Request +thing-type.caddx.panel.channel.panel_zone_name_request.description = Zone Name Request +thing-type.caddx.panel.channel.panel_zone_status_message.label = Zone Status Message +thing-type.caddx.panel.channel.panel_zone_status_message.description = Zone Status Message +thing-type.caddx.panel.channel.panel_zone_status_request.label = Zone Status Request +thing-type.caddx.panel.channel.panel_zone_status_request.description = Zone Status Request +thing-type.caddx.panel.channel.panel_zones_snapshot_message.label = Zones Snapshot Message +thing-type.caddx.panel.channel.panel_zones_snapshot_message.description = Zones Snapshot Message +thing-type.caddx.panel.channel.panel_zones_snapshot_request.label = Zones Snapshot Request +thing-type.caddx.panel.channel.panel_zones_snapshot_request.description = Zones Snapshot Request +thing-type.caddx.partition.label = Caddx Alarm Partition +thing-type.caddx.partition.description = Represents a controllable area within a Caddx Alarm System. +thing-type.caddx.partition.channel.partition_alarm_memory.label = Alarm Memory +thing-type.caddx.partition.channel.partition_alarm_memory.description = Alarm memory +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_1.label = Alarm Sent Using Phone 1 +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_1.description = Alarm sent using phone number 1 +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_2.label = Alarm Sent Using Phone 2 +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_2.description = Alarm sent using phone number 2 +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_3.label = Alarm Sent Using Phone 3 +thing-type.caddx.partition.channel.partition_alarm_sent_using_phone_number_3.description = Alarm sent using phone number 3 +thing-type.caddx.partition.channel.partition_armed.label = Armed +thing-type.caddx.partition.channel.partition_armed.description = Armed +thing-type.caddx.partition.channel.partition_auto_home_inhibited.label = Auto Home Inhibited +thing-type.caddx.partition.channel.partition_auto_home_inhibited.description = Auto home inhibited +thing-type.caddx.partition.channel.partition_bypass_code_required.label = Bypass Code Required +thing-type.caddx.partition.channel.partition_bypass_code_required.description = Bypass code required +thing-type.caddx.partition.channel.partition_cancel_command_entered.label = Cancel Command Entered +thing-type.caddx.partition.channel.partition_cancel_command_entered.description = Cancel command entered +thing-type.caddx.partition.channel.partition_cancel_pending.label = Cancel Pending +thing-type.caddx.partition.channel.partition_cancel_pending.description = Cancel pending +thing-type.caddx.partition.channel.partition_cancel_report_is_in_the_stack.label = Cancel Report is in the Stack +thing-type.caddx.partition.channel.partition_cancel_report_is_in_the_stack.description = Cancel report is in the stack +thing-type.caddx.partition.channel.partition_chime_mode_on.label = Chime Mode On +thing-type.caddx.partition.channel.partition_chime_mode_on.description = Chime mode on +thing-type.caddx.partition.channel.partition_chime_on.label = Chime On (Sounding) +thing-type.caddx.partition.channel.partition_chime_on.description = Chime on (sounding) +thing-type.caddx.partition.channel.partition_code_entered.label = Code Entered +thing-type.caddx.partition.channel.partition_code_entered.description = Code entered +thing-type.caddx.partition.channel.partition_cross_timing.label = Cross Timing +thing-type.caddx.partition.channel.partition_cross_timing.description = Cross timing +thing-type.caddx.partition.channel.partition_delay_expiration_warning.label = Delay Expiration Warning +thing-type.caddx.partition.channel.partition_delay_expiration_warning.description = Delay expiration warning +thing-type.caddx.partition.channel.partition_delay_trip_in_progress.label = Delay Trip in Progress +thing-type.caddx.partition.channel.partition_delay_trip_in_progress.description = Delay Trip in progress (common zone) +thing-type.caddx.partition.channel.partition_entry.label = Entry +thing-type.caddx.partition.channel.partition_entry.description = Entry +thing-type.caddx.partition.channel.partition_entry1.label = Entry 1 +thing-type.caddx.partition.channel.partition_entry1.description = Entry 1 +thing-type.caddx.partition.channel.partition_entryguard.label = Entryguard (Stay Mode) +thing-type.caddx.partition.channel.partition_entryguard.description = Entryguard (stay mode) +thing-type.caddx.partition.channel.partition_error_beep.label = Error Beep (Triple Beep) +thing-type.caddx.partition.channel.partition_error_beep.description = Error beep (triple beep) +thing-type.caddx.partition.channel.partition_exit1.label = Exit1 +thing-type.caddx.partition.channel.partition_exit1.description = Exit1 +thing-type.caddx.partition.channel.partition_exit2.label = Exit2 +thing-type.caddx.partition.channel.partition_exit2.description = Exit2 +thing-type.caddx.partition.channel.partition_exit_error_triggered.label = Exit Error Triggered +thing-type.caddx.partition.channel.partition_exit_error_triggered.description = Exit error triggered +thing-type.caddx.partition.channel.partition_fire.label = Fire +thing-type.caddx.partition.channel.partition_fire.description = Fire +thing-type.caddx.partition.channel.partition_fire_trouble.label = Fire Trouble +thing-type.caddx.partition.channel.partition_fire_trouble.description = Fire trouble +thing-type.caddx.partition.channel.partition_force_arm_triggered_by_auto_arm.label = Force Arm triggered by Auto Arm +thing-type.caddx.partition.channel.partition_force_arm_triggered_by_auto_arm.description = Force arm triggered by auto arm +thing-type.caddx.partition.channel.partition_instant.label = Instant +thing-type.caddx.partition.channel.partition_instant.description = Instant +thing-type.caddx.partition.channel.partition_keyswitch_armed.label = Keyswitch Armed +thing-type.caddx.partition.channel.partition_keyswitch_armed.description = Keyswitch armed +thing-type.caddx.partition.channel.partition_led_extinguish.label = Led Extinguish +thing-type.caddx.partition.channel.partition_led_extinguish.description = Led extinguish +thing-type.caddx.partition.channel.partition_open_period.label = Open Period +thing-type.caddx.partition.channel.partition_open_period.description = Open period +thing-type.caddx.partition.channel.partition_previous_alarm.label = Previous Alarm +thing-type.caddx.partition.channel.partition_previous_alarm.description = Previous Alarm +thing-type.caddx.partition.channel.partition_pulsing_buzzer.label = Pulsing Buzzer +thing-type.caddx.partition.channel.partition_pulsing_buzzer.description = Pulsing Buzzer +thing-type.caddx.partition.channel.partition_ready_to_arm.label = Ready to Arm +thing-type.caddx.partition.channel.partition_ready_to_arm.description = Ready to arm +thing-type.caddx.partition.channel.partition_ready_to_force_arm.label = Ready to Force Arm +thing-type.caddx.partition.channel.partition_ready_to_force_arm.description = Ready to force arm +thing-type.caddx.partition.channel.partition_recent_closing_being_timed.label = Recent Closing Being Timed +thing-type.caddx.partition.channel.partition_recent_closing_being_timed.description = Recent closing being timed +thing-type.caddx.partition.channel.partition_secondary_command.label = Partition Secondary Command +thing-type.caddx.partition.channel.partition_secondary_command.description = Partition Secondary Command +thing-type.caddx.partition.channel.partition_sensor_lost_supervision.label = Sensor Lost Supervision +thing-type.caddx.partition.channel.partition_sensor_lost_supervision.description = Sensor lost supervision +thing-type.caddx.partition.channel.partition_sensor_low_battery.label = Sensor Low Battery +thing-type.caddx.partition.channel.partition_sensor_low_battery.description = Sensor low battery +thing-type.caddx.partition.channel.partition_silent_exit_enabled.label = Silent Exit Enabled +thing-type.caddx.partition.channel.partition_silent_exit_enabled.description = Silent exit enabled +thing-type.caddx.partition.channel.partition_siren_on.label = Siren On +thing-type.caddx.partition.channel.partition_siren_on.description = Siren on +thing-type.caddx.partition.channel.partition_steady_siren_on.label = Steady Siren On +thing-type.caddx.partition.channel.partition_steady_siren_on.description = Steady siren on +thing-type.caddx.partition.channel.partition_tamper.label = Tamper +thing-type.caddx.partition.channel.partition_tamper.description = Tamper +thing-type.caddx.partition.channel.partition_tlm_fault_memory.label = TLM Fault Memory +thing-type.caddx.partition.channel.partition_tlm_fault_memory.description = TLM fault memory +thing-type.caddx.partition.channel.partition_tone_on.label = Tone On (Activation Tone) +thing-type.caddx.partition.channel.partition_tone_on.description = Tone on (activation tone) +thing-type.caddx.partition.channel.partition_valid_pin_accepted.label = Valid PIN Accepted +thing-type.caddx.partition.channel.partition_valid_pin_accepted.description = Valid PIN accepted +thing-type.caddx.partition.channel.partition_zone_bypassed.label = Zone Bypassed +thing-type.caddx.partition.channel.partition_zone_bypassed.description = Zone bypassed +thing-type.caddx.zone.label = Caddx Alarm Zone +thing-type.caddx.zone.description = Represents a physical device such as a door, window, or motion sensor. +thing-type.caddx.zone.channel.zone_24hour.label = 24 Hour +thing-type.caddx.zone.channel.zone_24hour.description = 24 Hour +thing-type.caddx.zone.channel.zone_alarm_memory.label = Alarm Memory +thing-type.caddx.zone.channel.zone_alarm_memory.description = Alarm memory +thing-type.caddx.zone.channel.zone_bypass_memory.label = Bypass Memory +thing-type.caddx.zone.channel.zone_bypass_memory.description = Bypass memory +thing-type.caddx.zone.channel.zone_bypassable.label = Bypassable +thing-type.caddx.zone.channel.zone_bypassable.description = Bypassable +thing-type.caddx.zone.channel.zone_bypassed.label = Bypassed +thing-type.caddx.zone.channel.zone_bypassed.description = Bypassed +thing-type.caddx.zone.channel.zone_chime.label = Chime +thing-type.caddx.zone.channel.zone_chime.description = Chime +thing-type.caddx.zone.channel.zone_cross_zone.label = Cross Zone +thing-type.caddx.zone.channel.zone_cross_zone.description = Cross zone +thing-type.caddx.zone.channel.zone_dialer_delay.label = Dialer Delay +thing-type.caddx.zone.channel.zone_dialer_delay.description = Dialer delay +thing-type.caddx.zone.channel.zone_double_eol_tamper.label = Double EOL Tamper +thing-type.caddx.zone.channel.zone_double_eol_tamper.description = Double EOL tamper +thing-type.caddx.zone.channel.zone_entry_exit_delay_1.label = Entry / Exit Delay 1 +thing-type.caddx.zone.channel.zone_entry_exit_delay_1.description = Entry / exit delay 1 +thing-type.caddx.zone.channel.zone_entry_exit_delay_2.label = Entry / Exit Delay 2 +thing-type.caddx.zone.channel.zone_entry_exit_delay_2.description = Entry / exit delay 2 +thing-type.caddx.zone.channel.zone_entry_guard.label = Entry Guard +thing-type.caddx.zone.channel.zone_entry_guard.description = Entry guard +thing-type.caddx.zone.channel.zone_fast_loop_response.label = Fast Loop Response +thing-type.caddx.zone.channel.zone_fast_loop_response.description = Fast loop response +thing-type.caddx.zone.channel.zone_faulted.label = Faulted +thing-type.caddx.zone.channel.zone_faulted.description = Faulted (or delayed trip) +thing-type.caddx.zone.channel.zone_fire.label = Fire +thing-type.caddx.zone.channel.zone_fire.description = Fire +thing-type.caddx.zone.channel.zone_follower.label = Follower +thing-type.caddx.zone.channel.zone_follower.description = Follower +thing-type.caddx.zone.channel.zone_force_armable.label = Force Armable +thing-type.caddx.zone.channel.zone_force_armable.description = Force armable +thing-type.caddx.zone.channel.zone_group_bypassable.label = Group Bypassable +thing-type.caddx.zone.channel.zone_group_bypassable.description = Group bypassable +thing-type.caddx.zone.channel.zone_inhibited.label = Inhibited (Force Armed) +thing-type.caddx.zone.channel.zone_inhibited.description = Inhibited (force armed) +thing-type.caddx.zone.channel.zone_interior.label = Interior +thing-type.caddx.zone.channel.zone_interior.description = Interior +thing-type.caddx.zone.channel.zone_key_switch.label = Key-switch +thing-type.caddx.zone.channel.zone_key_switch.description = Key-switch +thing-type.caddx.zone.channel.zone_keypad_sounder.label = Keypad Sounder +thing-type.caddx.zone.channel.zone_keypad_sounder.description = Keypad Sounder +thing-type.caddx.zone.channel.zone_listen_in.label = Listen in +thing-type.caddx.zone.channel.zone_listen_in.description = Listen in +thing-type.caddx.zone.channel.zone_local_only.label = Local Only +thing-type.caddx.zone.channel.zone_local_only.description = Local only +thing-type.caddx.zone.channel.zone_loss_of_supervision.label = Loss of Supervision +thing-type.caddx.zone.channel.zone_loss_of_supervision.description = Loss of supervision +thing-type.caddx.zone.channel.zone_low_battery.label = Low Battery +thing-type.caddx.zone.channel.zone_low_battery.description = Low Battery +thing-type.caddx.zone.channel.zone_name.label = Name +thing-type.caddx.zone.channel.zone_name.description = Name +thing-type.caddx.zone.channel.zone_partition1.label = Partition 1 +thing-type.caddx.zone.channel.zone_partition1.description = Partition 1 +thing-type.caddx.zone.channel.zone_partition2.label = Partition 2 +thing-type.caddx.zone.channel.zone_partition2.description = Partition 2 +thing-type.caddx.zone.channel.zone_partition3.label = Partition 3 +thing-type.caddx.zone.channel.zone_partition3.description = Partition 3 +thing-type.caddx.zone.channel.zone_partition4.label = Partition 4 +thing-type.caddx.zone.channel.zone_partition4.description = Partition 4 +thing-type.caddx.zone.channel.zone_partition5.label = Partition 5 +thing-type.caddx.zone.channel.zone_partition5.description = Partition 5 +thing-type.caddx.zone.channel.zone_partition6.label = Partition 6 +thing-type.caddx.zone.channel.zone_partition6.description = Partition 6 +thing-type.caddx.zone.channel.zone_partition7.label = Partition 7 +thing-type.caddx.zone.channel.zone_partition7.description = Partition 7 +thing-type.caddx.zone.channel.zone_partition8.label = Partition 8 +thing-type.caddx.zone.channel.zone_partition8.description = Partition 8 +thing-type.caddx.zone.channel.zone_restorable.label = Restorable +thing-type.caddx.zone.channel.zone_restorable.description = Restorable +thing-type.caddx.zone.channel.zone_steady_siren.label = Steady Siren +thing-type.caddx.zone.channel.zone_steady_siren.description = Steady siren +thing-type.caddx.zone.channel.zone_swinger_shutdown.label = Swinger Shutdown +thing-type.caddx.zone.channel.zone_swinger_shutdown.description = Swinger shutdown +thing-type.caddx.zone.channel.zone_tampered.label = Tampered +thing-type.caddx.zone.channel.zone_tampered.description = Tampered +thing-type.caddx.zone.channel.zone_trouble.label = Trouble +thing-type.caddx.zone.channel.zone_trouble.description = Trouble +thing-type.caddx.zone.channel.zone_type_trouble.label = Trouble +thing-type.caddx.zone.channel.zone_type_trouble.description = Trouble +thing-type.caddx.zone.channel.zone_yelping_siren.label = Yelping Siren +thing-type.caddx.zone.channel.zone_yelping_siren.description = Yelping siren + +# thing types config + +thing-type.config.caddx.bridge.baudrate.label = Baud Rate +thing-type.config.caddx.bridge.baudrate.description = The baud rate of the serial port. Valid values for the NX-584E are 600, 1200, 2400, 4800, 9600 (default), 19200, 38400, and 76800. Valid values for the NX-8E are 2400, 4800, 9600 (default), 19200 and 38400. +thing-type.config.caddx.bridge.baudrate.option.600 = 600 +thing-type.config.caddx.bridge.baudrate.option.1200 = 1200 +thing-type.config.caddx.bridge.baudrate.option.2400 = 2400 +thing-type.config.caddx.bridge.baudrate.option.4800 = 4800 +thing-type.config.caddx.bridge.baudrate.option.9600 = 9600 +thing-type.config.caddx.bridge.baudrate.option.19200 = 19200 +thing-type.config.caddx.bridge.baudrate.option.38400 = 38400 +thing-type.config.caddx.bridge.baudrate.option.76800 = 76800 +thing-type.config.caddx.bridge.ignoreZoneStatusTransitions.label = Ignore Zone Status Transitions +thing-type.config.caddx.bridge.ignoreZoneStatusTransitions.description = Flag specifying if the Zone Status Transitions should be ignored +thing-type.config.caddx.bridge.maxZoneNumber.label = Maximum Zone Number +thing-type.config.caddx.bridge.maxZoneNumber.description = The maximum zone number that should be auto-discovered +thing-type.config.caddx.bridge.protocol.label = Caddx Bridge Protocol +thing-type.config.caddx.bridge.protocol.description = The configured panel protocol. Valid values are Binary and Ascii. +thing-type.config.caddx.bridge.protocol.option.Ascii = Ascii +thing-type.config.caddx.bridge.protocol.option.Binary = Binary +thing-type.config.caddx.bridge.serialPort.label = Caddx Bridge Serial Port +thing-type.config.caddx.bridge.serialPort.description = The serial port name for the communication. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux. +thing-type.config.caddx.keypad.keypadAddress.label = Keypad Address +thing-type.config.caddx.keypad.keypadAddress.description = The Keypad Address. +thing-type.config.caddx.keypad.terminalModeSeconds.label = Terminal Mode Seconds +thing-type.config.caddx.keypad.terminalModeSeconds.description = The number of Seconds the keypad has to remain in Terminal Mode. +thing-type.config.caddx.partition.partitionNumber.label = Partition Number +thing-type.config.caddx.partition.partitionNumber.description = The Partition Number. +thing-type.config.caddx.partition.userNumber.label = User Number +thing-type.config.caddx.partition.userNumber.description = The User Number. +thing-type.config.caddx.zone.zoneNumber.label = Zone Number +thing-type.config.caddx.zone.zoneNumber.description = The Zone Number. + +# channel types + +channel-type.caddx.command.label = Send Command +channel-type.caddx.command.description = Sends a Command +channel-type.caddx.keypad_button_press.label = Key +channel-type.caddx.keypad_button_press.description = Key text +channel-type.caddx.panel_flag.label = Panel Flag +channel-type.caddx.panel_flag.description = Panel flag +channel-type.caddx.panel_text.label = Panel Text +channel-type.caddx.panel_text.description = Panel text +channel-type.caddx.partition_condition.label = Partition Condition +channel-type.caddx.partition_condition.description = Partition Condition +channel-type.caddx.partition_secondary.label = Partition Secondary Command +channel-type.caddx.partition_secondary.description = Partition secondary command +channel-type.caddx.partition_secondary.state.option.-1 = None +channel-type.caddx.partition_secondary.state.option.0 = Stay (1 button arm / toggle interiors) +channel-type.caddx.partition_secondary.state.option.1 = Chime (toggle chime mode) +channel-type.caddx.partition_secondary.state.option.2 = Exit (1 button arm / toggle instant) +channel-type.caddx.partition_secondary.state.option.3 = Bypass interiors +channel-type.caddx.partition_secondary.state.option.4 = Fire Panic +channel-type.caddx.partition_secondary.state.option.5 = Medical Panic +channel-type.caddx.partition_secondary.state.option.6 = Police Panic +channel-type.caddx.partition_secondary.state.option.7 = Smoke detector reset +channel-type.caddx.partition_secondary.state.option.8 = Auto callback download +channel-type.caddx.partition_secondary.state.option.9 = Manual pickup download +channel-type.caddx.partition_secondary.state.option.10 = Enable silent exit (for this arm cycle) +channel-type.caddx.partition_secondary.state.option.11 = Perform test +channel-type.caddx.partition_secondary.state.option.12 = Group Bypass +channel-type.caddx.partition_secondary.state.option.13 = Auxiliary function 1 +channel-type.caddx.partition_secondary.state.option.14 = Auxiliary function 2 +channel-type.caddx.partition_secondary.state.option.15 = Start keypad sounder +channel-type.caddx.reset.label = Reset +channel-type.caddx.reset.description = Reset Switch +channel-type.caddx.zone_bypass.label = Bypass Mode +channel-type.caddx.zone_bypass.description = Bypass Mode (OFF=Armed, ON=Bypassed) +channel-type.caddx.zone_condition.label = Zone Condition +channel-type.caddx.zone_condition.description = Zone Condition +channel-type.caddx.zone_partition.label = Zone Partition +channel-type.caddx.zone_partition.description = Zone Partition +channel-type.caddx.zone_status.label = Zone Status +channel-type.caddx.zone_status.description = Zone Status (Open/Closed) +channel-type.caddx.zone_text.label = Zone Text +channel-type.caddx.zone_text.description = Zone text +channel-type.caddx.zone_type.label = Zone Type +channel-type.caddx.zone_type.description = Zone Type diff --git a/bundles/org.openhab.binding.cbus/src/main/resources/OH-INF/i18n/cbus.properties b/bundles/org.openhab.binding.cbus/src/main/resources/OH-INF/i18n/cbus.properties new file mode 100644 index 0000000000000..5c88a4f711b35 --- /dev/null +++ b/bundles/org.openhab.binding.cbus/src/main/resources/OH-INF/i18n/cbus.properties @@ -0,0 +1,51 @@ +# binding + +binding.cbus.name = C-Bus Binding +binding.cbus.description = Clipsal C-Bus Binding + +# thing types + +thing-type.cbus.cgate.label = CGate Connection +thing-type.cbus.cgate.description = CGate Connection to connect to physical C-Bus Networks +thing-type.cbus.dali.label = DALI Group +thing-type.cbus.dali.description = DALI Group +thing-type.cbus.light.label = Lighting Group +thing-type.cbus.light.description = Lighting Group +thing-type.cbus.network.label = C-Bus Network +thing-type.cbus.network.description = C-Bus Network bridge +thing-type.cbus.temperature.label = Temperature Group +thing-type.cbus.temperature.description = Temperature Group +thing-type.cbus.trigger.label = Trigger Group +thing-type.cbus.trigger.description = Trigger Group + +# thing types config + +thing-type.config.cbus.cgate.ipAddress.label = CGate Server IP +thing-type.config.cbus.cgate.ipAddress.description = The IP address of the CGate Server. +thing-type.config.cbus.dali.group.label = CBus Group ID +thing-type.config.cbus.dali.group.description = Group number of this Thing on the C-Bus Network. +thing-type.config.cbus.light.group.label = CBus Group ID +thing-type.config.cbus.light.group.description = Group number of this Thing on the C-Bus Network. +thing-type.config.cbus.network.id.label = C-Bus Network ID +thing-type.config.cbus.network.id.description = Network number of C-Bus Network. +thing-type.config.cbus.network.project.label = C-Bus Project Name +thing-type.config.cbus.network.project.description = Project name that contains the network. +thing-type.config.cbus.network.syncInterval.label = Network Sync Interval +thing-type.config.cbus.network.syncInterval.description = The interval in seconds between fetching current group states from the network. +thing-type.config.cbus.temperature.group.label = CBus Group ID +thing-type.config.cbus.temperature.group.description = Group number of this Thing on the C-Bus Network. +thing-type.config.cbus.trigger.group.label = CBus Group ID +thing-type.config.cbus.trigger.group.description = Group number of this Thing on the C-Bus Network. + +# channel types + +channel-type.cbus.dali-channel.label = DALI Channel +channel-type.cbus.dali-channel.description = Group channel for CBus DALI groups +channel-type.cbus.level-channel.label = Level Channel +channel-type.cbus.level-channel.description = Group channel for CBus variable value lighting groups +channel-type.cbus.light-channel.label = Light Channel +channel-type.cbus.light-channel.description = Group channel for CBus on/off lighting groups +channel-type.cbus.temp-channel.label = Temperature +channel-type.cbus.temp-channel.description = Group channel for CBus temperature groups +channel-type.cbus.trigger-channel.label = Trigger Channel +channel-type.cbus.trigger-channel.description = Group channel for CBus trigger groups diff --git a/bundles/org.openhab.binding.cm11a/src/main/resources/OH-INF/i18n/cm11a.properties b/bundles/org.openhab.binding.cm11a/src/main/resources/OH-INF/i18n/cm11a.properties new file mode 100644 index 0000000000000..a3f643197dae1 --- /dev/null +++ b/bundles/org.openhab.binding.cm11a/src/main/resources/OH-INF/i18n/cm11a.properties @@ -0,0 +1,31 @@ +# binding + +binding.cm11a.name = CM11A Binding +binding.cm11a.description = This is the binding for the X10 Cm11a interface + +# thing types + +thing-type.cm11a.cm11a.label = CM11a Controller for X10 Devices +thing-type.cm11a.cm11a.description = CM11 is a device that allows control of X10 devices for a computer. +thing-type.cm11a.dimmer.label = X10 Dimmer +thing-type.cm11a.dimmer.description = Controls dimmable loads +thing-type.cm11a.switch.label = X10 Switch +thing-type.cm11a.switch.description = On/off switch + +# thing types config + +thing-type.config.cm11a.cm11a.refresh.label = Refresh Interval +thing-type.config.cm11a.cm11a.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.cm11a.cm11a.serialPort.label = Serial Port +thing-type.config.cm11a.cm11a.serialPort.description = Serial port used to communicate with the CM11a +thing-type.config.cm11a.dimmer.houseUnitCode.label = X10 House and Unit Code +thing-type.config.cm11a.dimmer.houseUnitCode.description = Address of dimmer in the X10 system +thing-type.config.cm11a.switch.houseUnitCode.label = X10 House and Unit Code +thing-type.config.cm11a.switch.houseUnitCode.description = Address of switch in the X10 system + +# channel types + +channel-type.cm11a.lightDimmer.label = Light Level +channel-type.cm11a.lightDimmer.description = Increase/decrease the light level +channel-type.cm11a.switchState.label = Switch State +channel-type.cm11a.switchState.description = On/off status of the switch diff --git a/bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/i18n/comfoair.properties b/bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/i18n/comfoair.properties new file mode 100644 index 0000000000000..247c282a5d000 --- /dev/null +++ b/bundles/org.openhab.binding.comfoair/src/main/resources/OH-INF/i18n/comfoair.properties @@ -0,0 +1,312 @@ +# binding + +binding.comfoair.name = ComfoAir Binding +binding.comfoair.description = This is the binding for ComfoAir. + +# thing types + +thing-type.comfoair.WHR930.label = Zehnder WHR930 Ventilation System +thing-type.comfoair.WHR930.description = Provides a generic access to a Zehnder WHR930 ventilation device +thing-type.comfoair.comfoair.label = Generic ComfoAir Ventilation System +thing-type.comfoair.comfoair.description = Provides a generic access to a ComfoAir compatible ventilation system +thing-type.comfoair.comfoair.group.analog1.label = Analog Inputs 1 +thing-type.comfoair.comfoair.group.analog2.label = Analog Inputs 2 +thing-type.comfoair.comfoair.group.analog3.label = Analog Inputs 3 +thing-type.comfoair.comfoair.group.analog4.label = Analog Inputs 4 + +# thing types config + +thing-type.config.comfoair.serial.refreshInterval.label = Refresh Interval +thing-type.config.comfoair.serial.refreshInterval.description = Refresh interval in seconds +thing-type.config.comfoair.serial.serialPort.label = Serial Port +thing-type.config.comfoair.serial.serialPort.description = Serial port that the ComfoAir is connected to + +# channel group types + +channel-group-type.comfoair.analog.label = Analog Inputs +channel-group-type.comfoair.analogRF.label = RF Input +channel-group-type.comfoair.bindingControl.label = Binding Control +channel-group-type.comfoair.bypass.label = Bypass Values +channel-group-type.comfoair.cookerhood.label = Cookerhood Values +channel-group-type.comfoair.enthalpy.label = Enthalpy Values +channel-group-type.comfoair.errors.label = Error States +channel-group-type.comfoair.ghx.label = Geothermal Heat Exchanger Values +channel-group-type.comfoair.heater.label = Heater Values +channel-group-type.comfoair.inputs.label = Inputs +channel-group-type.comfoair.menuP1.label = Menu P1: Control States +channel-group-type.comfoair.menuP1_WHR930.label = Menu P1: Control States +channel-group-type.comfoair.menuP2.label = Menu P2: Delay Settings +channel-group-type.comfoair.menuP2_WHR930.label = Menu P2: Delay Settings +channel-group-type.comfoair.menuP9.label = Menu P9: Option Control States +channel-group-type.comfoair.menuP9_WHR930.label = Menu P9: Option Control States +channel-group-type.comfoair.options.label = Option Settings +channel-group-type.comfoair.options_WHR930.label = Option Settings +channel-group-type.comfoair.preheater.label = Preheater Values +channel-group-type.comfoair.resets.label = Reset +channel-group-type.comfoair.temperatures.label = Temperature Values +channel-group-type.comfoair.temperatures_WHR930.label = Temperature Values +channel-group-type.comfoair.times.label = Uptimes +channel-group-type.comfoair.times_WHR930.label = Uptimes +channel-group-type.comfoair.ventilation.label = Ventilation Values +channel-group-type.comfoair.ventilation_WHR930.label = Ventilation Values + +# channel types + +channel-type.comfoair.L1_end_delay.label = L1 Switch End Delay (P23) +channel-type.comfoair.L1_end_delay.description = End delay for L1 switch (min) +channel-type.comfoair.RF_long_delay.label = RF Long Delay (P26) +channel-type.comfoair.RF_long_delay.description = End delay (RF long actuation) for ventilation level 3 (min) +channel-type.comfoair.RF_max.label = RF Input Max +channel-type.comfoair.RF_max.description = Maximum setting for RF input +channel-type.comfoair.RF_min.label = RF Input Min +channel-type.comfoair.RF_min.description = Minimum setting for RF input +channel-type.comfoair.RF_mode.label = RF Input State +channel-type.comfoair.RF_mode.description = State of RF input +channel-type.comfoair.RF_negative.label = RF Input Postive/Negative +channel-type.comfoair.RF_negative.description = Postive/Negative state of RF input +channel-type.comfoair.RF_short_delay.label = RF Short Delay (P25) +channel-type.comfoair.RF_short_delay.description = End delay (RF short actuation) for ventilation level 3 (min) +channel-type.comfoair.RF_value.label = RF Input Target +channel-type.comfoair.RF_value.description = Target setting for RF input +channel-type.comfoair.activate.label = Activate Binding Control +channel-type.comfoair.activate.description = Activate (control through openHAB) or deactivate (return control to CCEase) binding control +channel-type.comfoair.analog_max.label = Analog Input Max +channel-type.comfoair.analog_max.description = Maximum setting for analog input +channel-type.comfoair.analog_min.label = Analog Input Min +channel-type.comfoair.analog_min.description = Minimum setting for analog input +channel-type.comfoair.analog_mode.label = Analog Input State +channel-type.comfoair.analog_mode.description = State of analog input +channel-type.comfoair.analog_negative.label = Analog Input Postive/Negative +channel-type.comfoair.analog_negative.description = Postive/Negative state of analog input +channel-type.comfoair.analog_priority.label = Analog Priority +channel-type.comfoair.analog_priority.description = Priority of analog inputs for highest fan level +channel-type.comfoair.analog_priority.state.option.0 = Analog inputs +channel-type.comfoair.analog_priority.state.option.1 = Schedule +channel-type.comfoair.analog_value.label = Analog Input Target +channel-type.comfoair.analog_value.description = Target setting for analog input +channel-type.comfoair.analog_volt.label = Analog Input Voltage Level +channel-type.comfoair.analog_volt.description = Voltage level of analog input +channel-type.comfoair.bathroom_end_delay.label = Bathroom Switch End Delay (P22) +channel-type.comfoair.bathroom_end_delay.description = End delay for bathroom switch (min) +channel-type.comfoair.bathroom_start_delay.label = Bathroom Switch Start Delay (P21) +channel-type.comfoair.bathroom_start_delay.description = Start delay for bathroom switch (min) +channel-type.comfoair.bypass_correction.label = Bypass Correction +channel-type.comfoair.bypass_correction.description = Bypass correction state +channel-type.comfoair.bypass_factor.label = Bypass Factor +channel-type.comfoair.bypass_factor.description = Bypass factor value +channel-type.comfoair.bypass_level.label = Bypass Level +channel-type.comfoair.bypass_level.description = Bypass level state +channel-type.comfoair.bypass_state.label = Bypass State +channel-type.comfoair.bypass_state.description = State of the bypass (ON = open / OFF = closed) +channel-type.comfoair.bypass_summer.label = Bypass Summer Mode +channel-type.comfoair.bypass_summer.description = Bypass summer mode +channel-type.comfoair.bypass_time.label = Bypass Duration +channel-type.comfoair.bypass_time.description = Hours of bypass open +channel-type.comfoair.chimney_state.label = Chimney Control State +channel-type.comfoair.chimney_state.description = State of the chimney control +channel-type.comfoair.cookerhood_delay.label = Cookerhood Delay (P20) +channel-type.comfoair.cookerhood_delay.description = End delay for cooker hood control (min) +channel-type.comfoair.cookerhood_speed.label = Cookerhood Speed Up (%) +channel-type.comfoair.cookerhood_speed.description = Speed up of the cookerhood +channel-type.comfoair.cookerhood_state.label = Cookerhood State +channel-type.comfoair.cookerhood_state.description = State of the cookerhood control +channel-type.comfoair.cookerhood_temperature.label = Cookerhood Temperature +channel-type.comfoair.cookerhood_temperature.description = Temperature of cookerhood sensor +channel-type.comfoair.enthalpy_humidity.label = Enthalpy Sensor Humidity +channel-type.comfoair.enthalpy_humidity.description = Humidity of the enthalpy sensor +channel-type.comfoair.enthalpy_level.label = Enthalpy Sensor Level +channel-type.comfoair.enthalpy_level.description = Level of the enthalpy sensor +channel-type.comfoair.enthalpy_state.label = Enthalpy State +channel-type.comfoair.enthalpy_state.description = State of the enthalpy module +channel-type.comfoair.enthalpy_temperature.label = Enthalpy Sensor Temperature +channel-type.comfoair.enthalpy_temperature.description = Temperature of the enthalpy sensor +channel-type.comfoair.enthalpy_time.label = Enthalpy Sensor Timer +channel-type.comfoair.enthalpy_time.description = Timer state of the enthalpy sensor +channel-type.comfoair.error_reset.label = Error Reset +channel-type.comfoair.error_reset.description = Reset errors +channel-type.comfoair.error_reset.command.option.1 = Reset +channel-type.comfoair.errors_current.label = Error Current +channel-type.comfoair.errors_current.description = Current errors +channel-type.comfoair.errors_last.label = Errors Last +channel-type.comfoair.errors_last.description = Last errors +channel-type.comfoair.errors_pre_prelast.label = Errors Pre-Prelast +channel-type.comfoair.errors_pre_prelast.description = Pre-Prelast errors +channel-type.comfoair.errors_prelast.label = Errors Prelast +channel-type.comfoair.errors_prelast.description = Prelast errors +channel-type.comfoair.fan_evel.label = Fan Level +channel-type.comfoair.fan_evel.description = Fan level +channel-type.comfoair.fan_evel.state.option.1 = Away +channel-type.comfoair.fan_evel.state.option.2 = Level 1 +channel-type.comfoair.fan_evel.state.option.3 = Level 2 +channel-type.comfoair.fan_evel.state.option.4 = Level 3 +channel-type.comfoair.fan_in_0.label = Fan In Level 0 (away) +channel-type.comfoair.fan_in_0.description = Fan level 0 performance (%) of incoming fan +channel-type.comfoair.fan_in_1.label = Fan In Level 1 +channel-type.comfoair.fan_in_1.description = Fan level 1 performance (%) of incoming fan +channel-type.comfoair.fan_in_2.label = Fan In Level 2 +channel-type.comfoair.fan_in_2.description = Fan level 2 performance (%) of incoming fan +channel-type.comfoair.fan_in_3.label = Fan In Level 3 +channel-type.comfoair.fan_in_3.description = Fan level 3 performance (%) of incoming fan +channel-type.comfoair.fan_in_RPM.label = Fan In (rpm) +channel-type.comfoair.fan_in_RPM.description = Current absolute speed (rpm) of incoming fan +channel-type.comfoair.fan_in_percent.label = Fan In (%) +channel-type.comfoair.fan_in_percent.description = Current relative speed (%) of incoming fan +channel-type.comfoair.fan_out_0.label = Fan Out Level 0 (away) +channel-type.comfoair.fan_out_0.description = Fan level 0 performance (%) of outgoing fan +channel-type.comfoair.fan_out_1.label = Fan Out Level 1 +channel-type.comfoair.fan_out_1.description = Fan level 1 performance (%) of outgoing fan +channel-type.comfoair.fan_out_2.label = Fan Out Level 2 +channel-type.comfoair.fan_out_2.description = Fan level 2 performance (%) of outgoing fan +channel-type.comfoair.fan_out_3.label = Fan Out Level 3 +channel-type.comfoair.fan_out_3.description = Fan level 3 performance (%) of outgoing fan +channel-type.comfoair.fan_out_RPM.label = Fan Out (rpm) +channel-type.comfoair.fan_out_RPM.description = Current absolute speed (rpm) of outgoing fan +channel-type.comfoair.fan_out_percent.label = Fan Out (%) +channel-type.comfoair.fan_out_percent.description = Current relative speed (%) of outgoing fan +channel-type.comfoair.filter_error.label = Filter Error +channel-type.comfoair.filter_error.description = Filter full +channel-type.comfoair.filter_hours.label = Filter Duration +channel-type.comfoair.filter_hours.description = Uptime of the filter +channel-type.comfoair.filter_reset.label = Filter Reset +channel-type.comfoair.filter_reset.description = Reset filter uptime +channel-type.comfoair.filter_reset.command.option.1 = Reset +channel-type.comfoair.filter_weeks.label = Filter Period (P24) +channel-type.comfoair.filter_weeks.description = Usage period until filter pollution message (weeks) +channel-type.comfoair.freeze_time.label = Antifrost Duration +channel-type.comfoair.freeze_time.description = Uptime of antifrost +channel-type.comfoair.frost_state.label = Antifrost State +channel-type.comfoair.frost_state.description = State of the antifrost control +channel-type.comfoair.ghx_speed.label = GHX Speed Up (%) +channel-type.comfoair.ghx_speed.description = Speed up of the geothermal heat exchanger +channel-type.comfoair.ghx_state.label = Geothermal Heat exchanger State +channel-type.comfoair.ghx_state.description = State of the geothermal heat exchanger valve (ON = open / OFF = closed) +channel-type.comfoair.ghx_temperature.label = GHX Temperature +channel-type.comfoair.ghx_temperature.description = Temperature of geothermal heat exchanger sensor +channel-type.comfoair.ghx_temperature_high.label = GHX Temperature (high) +channel-type.comfoair.ghx_temperature_high.description = Upper temperature of the geothermal heat exchanger +channel-type.comfoair.ghx_temperature_low.label = GHX Temperature (low) +channel-type.comfoair.ghx_temperature_low.description = Lower temperature of the geothermal heat exchanger +channel-type.comfoair.heater_power.label = Heater Power +channel-type.comfoair.heater_power.description = Heater power value +channel-type.comfoair.heater_power_I.label = Heater Power I-Parameter +channel-type.comfoair.heater_power_I.description = Heater power I-parameter value +channel-type.comfoair.heater_state.label = Heater State +channel-type.comfoair.heater_state.description = State of the heater +channel-type.comfoair.heater_target_temperature.label = Heater Target Temperature +channel-type.comfoair.heater_target_temperature.description = Target temperature of the heater +channel-type.comfoair.heater_temperature.label = Heater Temperature +channel-type.comfoair.heater_temperature.description = Temperature of heater sensor +channel-type.comfoair.indoor_temperature_in.label = Indoor Temperature Incoming +channel-type.comfoair.indoor_temperature_in.description = Inlet air temperature (inside) +channel-type.comfoair.indoor_temperature_out.label = Indoor Temperature Outgoing +channel-type.comfoair.indoor_temperature_out.description = Uptake air temperature (inside) +channel-type.comfoair.is_L1_switch.label = L1 Switch +channel-type.comfoair.is_L1_switch.description = Availability of L1 step switch +channel-type.comfoair.is_L2_switch.label = L2 Switch +channel-type.comfoair.is_L2_switch.description = Availability of L2 step switch +channel-type.comfoair.is_RF.label = RF Input Availability +channel-type.comfoair.is_RF.description = Availability of RF input +channel-type.comfoair.is_T1_sensor.label = Sensor T1 Available +channel-type.comfoair.is_T1_sensor.description = Availability of temperature sensor T1 (outdoor in) +channel-type.comfoair.is_T2_sensor.label = Sensor T2 Available +channel-type.comfoair.is_T2_sensor.description = Availability of temperature sensor T2 (indoor in) +channel-type.comfoair.is_T3_sensor.label = Sensor T3 Available +channel-type.comfoair.is_T3_sensor.description = Availability of temperature sensor T3 (indoor out) +channel-type.comfoair.is_T4_sensor.label = Sensor T4 Available +channel-type.comfoair.is_T4_sensor.description = Availability of temperature sensor T4 (outdoor out) +channel-type.comfoair.is_analog.label = Analog Input Availability +channel-type.comfoair.is_analog.description = Availability of analog input +channel-type.comfoair.is_bathroom2_switch.label = Bathroom Switch 2 +channel-type.comfoair.is_bathroom2_switch.description = Availability of bathroom switch 2 (luxe) +channel-type.comfoair.is_bathroom_switch.label = Bathroom Switch +channel-type.comfoair.is_bathroom_switch.description = Availability of bathroom switch +channel-type.comfoair.is_bypass.label = Bypass +channel-type.comfoair.is_bypass.description = Bypass option installed +channel-type.comfoair.is_chimney.label = Chimney +channel-type.comfoair.is_chimney.description = Chimney option installed +channel-type.comfoair.is_cookerhood.label = Cookerhood +channel-type.comfoair.is_cookerhood.description = Cookerhood option installed +channel-type.comfoair.is_cookerhood_sensor.label = Cookerhood Sensor Available +channel-type.comfoair.is_cookerhood_sensor.description = Availability of cookerhood temperature sensor +channel-type.comfoair.is_cookerhood_switch.label = Cookerhood Switch +channel-type.comfoair.is_cookerhood_switch.description = Availability of cookerhood switch +channel-type.comfoair.is_enthalpy.label = Enthalpy +channel-type.comfoair.is_enthalpy.description = Enthalpy option installed +channel-type.comfoair.is_enthalpy.state.option.0 = Not installed +channel-type.comfoair.is_enthalpy.state.option.1 = With sensor +channel-type.comfoair.is_enthalpy.state.option.2 = Without sensor +channel-type.comfoair.is_external_filter.label = External Filter +channel-type.comfoair.is_external_filter.description = Availability of external filter +channel-type.comfoair.is_ghx.label = Geothermal Heat Exchanger +channel-type.comfoair.is_ghx.description = Geothermal heat exchanger option installed +channel-type.comfoair.is_ghx.state.option.0 = Not installed +channel-type.comfoair.is_ghx.state.option.1 = Regulated +channel-type.comfoair.is_ghx.state.option.2 = Not regulated +channel-type.comfoair.is_ghx_sensor.label = GHX Sensor Available +channel-type.comfoair.is_ghx_sensor.description = Availability of geothermal heat exchanger temperature sensor +channel-type.comfoair.is_heater.label = Heater +channel-type.comfoair.is_heater.description = Heater option installed +channel-type.comfoair.is_heater_sensor.label = Heater Sensor Available +channel-type.comfoair.is_heater_sensor.description = Availability of heater temperature sensor +channel-type.comfoair.is_preheater.label = Preheater +channel-type.comfoair.is_preheater.description = Preheater option installed +channel-type.comfoair.is_wtw.label = Heat Recovery +channel-type.comfoair.is_wtw.description = Availability of heat recovery (WTW) +channel-type.comfoair.level0_time.label = Level 0 Duration +channel-type.comfoair.level0_time.description = Uptime at level 0 (away) +channel-type.comfoair.level1_time.label = Level 1 Duration +channel-type.comfoair.level1_time.description = Uptime at level 1 +channel-type.comfoair.level2_time.label = Level 2 Duration +channel-type.comfoair.level2_time.description = Uptime at level 2 +channel-type.comfoair.level3_time.label = Level 3 Duration +channel-type.comfoair.level3_time.description = Uptime at level 3 +channel-type.comfoair.menu20_mode.label = Menu 20 Mode (P10) +channel-type.comfoair.menu20_mode.description = State of menu 20 mode (P10) +channel-type.comfoair.menu21_mode.label = Menu 21 Mode (P11) +channel-type.comfoair.menu21_mode.description = State of menu 21 mode (P11) +channel-type.comfoair.menu22_mode.label = Menu 22 Mode (P12) +channel-type.comfoair.menu22_mode.description = State of menu 22 mode (P12) +channel-type.comfoair.menu23_mode.label = Menu 23 Mode (P13) +channel-type.comfoair.menu23_mode.description = State of menu 23 mode (P13) +channel-type.comfoair.menu24_mode.label = Menu 24 Mode (P14) +channel-type.comfoair.menu24_mode.description = State of menu 24 mode (P14) +channel-type.comfoair.menu25_mode.label = Menu 25 Mode (P15) +channel-type.comfoair.menu25_mode.description = State of menu 25 mode (P15) +channel-type.comfoair.menu26_mode.label = Menu 26 Mode (P16) +channel-type.comfoair.menu26_mode.description = State of menu 26 mode (P16) +channel-type.comfoair.menu27_mode.label = Menu 27 Mode (P17) +channel-type.comfoair.menu27_mode.description = State of menu 27 mode (P17) +channel-type.comfoair.menu28_mode.label = Menu 28 Mode (P18) +channel-type.comfoair.menu28_mode.description = State of menu 28 mode (P18) +channel-type.comfoair.menu29_mode.label = Menu 29 Mode (P19) +channel-type.comfoair.menu29_mode.description = State of menu 29 mode (P19) +channel-type.comfoair.outdoor_temperature_in.label = Outdoor Temperature Incoming +channel-type.comfoair.outdoor_temperature_in.description = Intake air temperature (outside) +channel-type.comfoair.outdoor_temperature_out.label = Outdoor Temperature Outgoing +channel-type.comfoair.outdoor_temperature_out.description = Outlet air temperature (outside) +channel-type.comfoair.preheater_frost_protect.label = Frost Protection +channel-type.comfoair.preheater_frost_protect.description = State of the frost protection +channel-type.comfoair.preheater_frost_time.label = Preheater Frost Time +channel-type.comfoair.preheater_frost_time.description = Frost minutes +channel-type.comfoair.preheater_heating.label = Preheater +channel-type.comfoair.preheater_heating.description = State of the preheater +channel-type.comfoair.preheater_safety.label = Preheater Frost Safety +channel-type.comfoair.preheater_safety.description = Frost safety setting +channel-type.comfoair.preheater_time.label = Preheater Duration +channel-type.comfoair.preheater_time.description = Uptime of preheater +channel-type.comfoair.preheater_valve.label = Preheater Valve +channel-type.comfoair.preheater_valve.description = State of the preheater valve +channel-type.comfoair.pulse_ventilation.label = Pulse Ventilation Period (P27) +channel-type.comfoair.pulse_ventilation.description = Period for pulse ventilation (min) +channel-type.comfoair.recu_size.label = Comfoair Size +channel-type.comfoair.recu_size.description = Size of the ComfoAir (1 = big / 2 = small) +channel-type.comfoair.recu_size.state.option.1 = Big +channel-type.comfoair.recu_size.state.option.2 = Small +channel-type.comfoair.recu_type.label = Comfoair Type +channel-type.comfoair.recu_type.description = Type of the ComfoAir (1 = left / 2 = right) +channel-type.comfoair.recu_type.state.option.1 = Left +channel-type.comfoair.recu_type.state.option.2 = Right +channel-type.comfoair.target_temperature.label = Target Temperature +channel-type.comfoair.target_temperature.description = Target (comfort) temperature +channel-type.comfoair.v_control_state.label = 0-10V Control State +channel-type.comfoair.v_control_state.description = State of the 0-10V control diff --git a/bundles/org.openhab.binding.coolmasternet/src/main/resources/OH-INF/i18n/coolmasternet.properties b/bundles/org.openhab.binding.coolmasternet/src/main/resources/OH-INF/i18n/coolmasternet.properties new file mode 100644 index 0000000000000..2a41ad6782fdf --- /dev/null +++ b/bundles/org.openhab.binding.coolmasternet/src/main/resources/OH-INF/i18n/coolmasternet.properties @@ -0,0 +1,52 @@ +# binding + +binding.coolmasternet.name = CoolMasterNet Binding +binding.coolmasternet.description = Binding for Cool Automation CoolMasterNet HVAC controllers. + +# thing types + +thing-type.coolmasternet.controller.label = CoolMasterNet Controller +thing-type.coolmasternet.controller.description = A CoolMasterNet Controller (connected to one or more HVAC systems) +thing-type.coolmasternet.hvac.label = HVAC System +thing-type.coolmasternet.hvac.description = HVAC System connected to a controller (unique UID) + +# thing types config + +thing-type.config.coolmasternet.controller.host.label = Hostname +thing-type.config.coolmasternet.controller.host.description = The IP address / FQDN of the CoolMasterNet unit +thing-type.config.coolmasternet.controller.port.label = Port +thing-type.config.coolmasternet.controller.port.description = Port of ASCII interface of CoolMasterNet unit. +thing-type.config.coolmasternet.controller.refresh.label = Refresh Frequency +thing-type.config.coolmasternet.controller.refresh.description = Frequency to poll the controller for updates, in seconds. Defaults to every 5 seconds. +thing-type.config.coolmasternet.hvac.uid.label = HVAC Unit ID +thing-type.config.coolmasternet.hvac.uid.description = Unit ID of the HVAC Unit to control. Example: L1.100. + +# channel types + +channel-type.coolmasternet.fan_speed.label = Fan Speed +channel-type.coolmasternet.fan_speed.state.option.l = Low +channel-type.coolmasternet.fan_speed.state.option.m = Medium +channel-type.coolmasternet.fan_speed.state.option.h = High +channel-type.coolmasternet.fan_speed.state.option.t = Top +channel-type.coolmasternet.fan_speed.state.option.a = Auto +channel-type.coolmasternet.hvac_mode.label = Mode +channel-type.coolmasternet.hvac_mode.description = HVAC unit operation mode +channel-type.coolmasternet.hvac_mode.state.option.cool = Cool +channel-type.coolmasternet.hvac_mode.state.option.heat = Heat +channel-type.coolmasternet.hvac_mode.state.option.auto = Auto +channel-type.coolmasternet.hvac_mode.state.option.dry = Dry +channel-type.coolmasternet.hvac_mode.state.option.fan = Fan Only +channel-type.coolmasternet.louvre_angle.label = Louvre Position +channel-type.coolmasternet.louvre_angle.state.option.0 = No Control +channel-type.coolmasternet.louvre_angle.state.option.a = Auto Swing +channel-type.coolmasternet.louvre_angle.state.option.h = Horizontal +channel-type.coolmasternet.louvre_angle.state.option.3 = 30 degrees +channel-type.coolmasternet.louvre_angle.state.option.4 = 45 degrees +channel-type.coolmasternet.louvre_angle.state.option.6 = 60 degrees +channel-type.coolmasternet.louvre_angle.state.option.v = Vertical +channel-type.coolmasternet.power.label = Power +channel-type.coolmasternet.power.description = Is the HVAC unit powered on? +channel-type.coolmasternet.temperature_readback.label = Current Temperature +channel-type.coolmasternet.temperature_readback.description = Current system ambient temperature +channel-type.coolmasternet.temperature_setpoint.label = Set Temperature +channel-type.coolmasternet.temperature_setpoint.description = Temperature thermostat setpoint diff --git a/bundles/org.openhab.binding.coronastats/src/main/resources/OH-INF/i18n/coronastats.properties b/bundles/org.openhab.binding.coronastats/src/main/resources/OH-INF/i18n/coronastats.properties new file mode 100644 index 0000000000000..30d7bfedac9d3 --- /dev/null +++ b/bundles/org.openhab.binding.coronastats/src/main/resources/OH-INF/i18n/coronastats.properties @@ -0,0 +1,30 @@ +# binding + +binding.coronastats.name = CoronaStats Binding +binding.coronastats.description = This is a binding for accessing data from https://corona-stats.online/ website. + +# thing types + +thing-type.coronastats.country.label = Corona Statistics (Country) +thing-type.coronastats.country.description = Corona statistics for a specific country +thing-type.coronastats.world.label = Corona Statistics (World) +thing-type.coronastats.world.description = Bridge for accessing data from https://corona-stats.online/ website and representing world statistics. + +# thing types config + +thing-type.config.coronastats.country.countryCode.label = Country Code +thing-type.config.coronastats.country.countryCode.description = 2-letter Country Code +thing-type.config.coronastats.world.refresh.label = Refresh Interval +thing-type.config.coronastats.world.refresh.description = Time between two API requests in minutes. Minimum 15 minutes. + +# channel types + +channel-type.coronastats.active.label = Active +channel-type.coronastats.cases.label = Total Cases +channel-type.coronastats.critical.label = Critical +channel-type.coronastats.deaths.label = Total Deaths +channel-type.coronastats.recovered.label = Recovered +channel-type.coronastats.tests.label = Tests +channel-type.coronastats.today_cases.label = New Cases +channel-type.coronastats.today_deaths.label = New Deaths +channel-type.coronastats.updated.label = Updated diff --git a/bundles/org.openhab.binding.daikin/src/main/resources/OH-INF/i18n/daikin.properties b/bundles/org.openhab.binding.daikin/src/main/resources/OH-INF/i18n/daikin.properties new file mode 100644 index 0000000000000..e7b19d70231d3 --- /dev/null +++ b/bundles/org.openhab.binding.daikin/src/main/resources/OH-INF/i18n/daikin.properties @@ -0,0 +1,149 @@ +# binding + +binding.daikin.name = Daikin Binding +binding.daikin.description = This is the binding for Daikin A/C units. + +# thing types + +thing-type.daikin.ac_unit.label = Daikin AC Unit +thing-type.daikin.ac_unit.description = Daikin AC Unit +thing-type.daikin.airbase_ac_unit.label = Daikin Airbase AC Unit +thing-type.daikin.airbase_ac_unit.description = Daikin Airbase AC Unit + +# thing types config + +thing-type.config.daikin.config.host.label = Host +thing-type.config.daikin.config.host.description = The Host address of the Daikin AC unit. +thing-type.config.daikin.config.key.label = Key +thing-type.config.daikin.config.key.description = The key obtained from the Daikin adapter. +thing-type.config.daikin.config.refresh.label = Refresh Interval +thing-type.config.daikin.config.refresh.description = Time between fetches of the AC unit state. +thing-type.config.daikin.config.secure.label = Secure/HTTPS +thing-type.config.daikin.config.secure.description = Whether to access using https (default:false). +thing-type.config.daikin.config.uuid.label = UUID +thing-type.config.daikin.config.uuid.description = A unique UUID for authentication if required. + +# channel types + +channel-type.daikin.acunit-cmpfrequency.label = Compressor Frequency +channel-type.daikin.acunit-cmpfrequency.description = Current compressor frequency +channel-type.daikin.acunit-energycoolingcurrentyear-1.label = Energy Cooling Current Year January +channel-type.daikin.acunit-energycoolingcurrentyear-1.description = The energy usage for cooling this year January +channel-type.daikin.acunit-energycoolingcurrentyear-2.label = Energy Cooling Current Year February +channel-type.daikin.acunit-energycoolingcurrentyear-2.description = The energy usage for cooling this year February +channel-type.daikin.acunit-energycoolingcurrentyear-3.label = Energy Cooling Current Year March +channel-type.daikin.acunit-energycoolingcurrentyear-3.description = The energy usage for cooling this year March +channel-type.daikin.acunit-energycoolingcurrentyear-4.label = Energy Cooling Current Year April +channel-type.daikin.acunit-energycoolingcurrentyear-4.description = The energy usage for cooling this year April +channel-type.daikin.acunit-energycoolingcurrentyear-5.label = Energy Cooling Current Year May +channel-type.daikin.acunit-energycoolingcurrentyear-5.description = The energy usage for cooling this year May +channel-type.daikin.acunit-energycoolingcurrentyear-6.label = Energy Cooling Current Year June +channel-type.daikin.acunit-energycoolingcurrentyear-6.description = The energy usage for cooling this year June +channel-type.daikin.acunit-energycoolingcurrentyear-7.label = Energy Cooling Current Year July +channel-type.daikin.acunit-energycoolingcurrentyear-7.description = The energy usage for cooling this year July +channel-type.daikin.acunit-energycoolingcurrentyear-8.label = Energy Cooling Current Year August +channel-type.daikin.acunit-energycoolingcurrentyear-8.description = The energy usage for cooling this year August +channel-type.daikin.acunit-energycoolingcurrentyear-9.label = Energy Cooling Current Year September +channel-type.daikin.acunit-energycoolingcurrentyear-9.description = The energy usage for cooling this year September +channel-type.daikin.acunit-energycoolingcurrentyear-10.label = Energy Cooling Current Year October +channel-type.daikin.acunit-energycoolingcurrentyear-10.description = The energy usage for cooling this year October +channel-type.daikin.acunit-energycoolingcurrentyear-11.label = Energy Cooling Current Year November +channel-type.daikin.acunit-energycoolingcurrentyear-11.description = The energy usage for cooling this year November +channel-type.daikin.acunit-energycoolingcurrentyear-12.label = Energy Cooling Current Year December +channel-type.daikin.acunit-energycoolingcurrentyear-12.description = The energy usage for cooling this year December +channel-type.daikin.acunit-energycoolinglastweek.label = Energy Cooling Last Week +channel-type.daikin.acunit-energycoolinglastweek.description = The energy usage for cooling last week +channel-type.daikin.acunit-energycoolingthisweek.label = Energy Cooling This Week +channel-type.daikin.acunit-energycoolingthisweek.description = The energy usage for cooling this week +channel-type.daikin.acunit-energycoolingtoday.label = Energy Cooling Today +channel-type.daikin.acunit-energycoolingtoday.description = The energy usage for cooling today +channel-type.daikin.acunit-energyheatingcurrentyear-1.label = Energy Heating Current Year January +channel-type.daikin.acunit-energyheatingcurrentyear-1.description = The energy usage for heating this year January +channel-type.daikin.acunit-energyheatingcurrentyear-2.label = Energy Heating Current Year February +channel-type.daikin.acunit-energyheatingcurrentyear-2.description = The energy usage for heating this year February +channel-type.daikin.acunit-energyheatingcurrentyear-3.label = Energy Heating Current Year March +channel-type.daikin.acunit-energyheatingcurrentyear-3.description = The energy usage for heating this year March +channel-type.daikin.acunit-energyheatingcurrentyear-4.label = Energy Heating Current Year April +channel-type.daikin.acunit-energyheatingcurrentyear-4.description = The energy usage for heating this year April +channel-type.daikin.acunit-energyheatingcurrentyear-5.label = Energy Heating Current Year May +channel-type.daikin.acunit-energyheatingcurrentyear-5.description = The energy usage for heating this year May +channel-type.daikin.acunit-energyheatingcurrentyear-6.label = Energy Heating Current Year June +channel-type.daikin.acunit-energyheatingcurrentyear-6.description = The energy usage for heating this year June +channel-type.daikin.acunit-energyheatingcurrentyear-7.label = Energy Heating Current Year July +channel-type.daikin.acunit-energyheatingcurrentyear-7.description = The energy usage for heating this year July +channel-type.daikin.acunit-energyheatingcurrentyear-8.label = Energy Heating Current Year August +channel-type.daikin.acunit-energyheatingcurrentyear-8.description = The energy usage for heating this year August +channel-type.daikin.acunit-energyheatingcurrentyear-9.label = Energy Heating Current Year September +channel-type.daikin.acunit-energyheatingcurrentyear-9.description = The energy usage for heating this year September +channel-type.daikin.acunit-energyheatingcurrentyear-10.label = Energy Heating Current Year October +channel-type.daikin.acunit-energyheatingcurrentyear-10.description = The energy usage for heating this year October +channel-type.daikin.acunit-energyheatingcurrentyear-11.label = Energy Heating Current Year November +channel-type.daikin.acunit-energyheatingcurrentyear-11.description = The energy usage for heating this year November +channel-type.daikin.acunit-energyheatingcurrentyear-12.label = Energy Heating Current Year December +channel-type.daikin.acunit-energyheatingcurrentyear-12.description = The energy usage for heating this year December +channel-type.daikin.acunit-energyheatinglastweek.label = Energy Heating Last Week +channel-type.daikin.acunit-energyheatinglastweek.description = The energy usage for heating last week +channel-type.daikin.acunit-energyheatingthisweek.label = Energy Heating This Week +channel-type.daikin.acunit-energyheatingthisweek.description = The energy usage for heating this week +channel-type.daikin.acunit-energyheatingtoday.label = Energy Heating Today +channel-type.daikin.acunit-energyheatingtoday.description = The energy usage for heating today +channel-type.daikin.acunit-fan.label = Fan +channel-type.daikin.acunit-fan.description = Current fan speed setting of the AC unit +channel-type.daikin.acunit-fan.state.option.AUTO = auto +channel-type.daikin.acunit-fan.state.option.SILENCE = silence +channel-type.daikin.acunit-fan.state.option.LEVEL_1 = level 1 +channel-type.daikin.acunit-fan.state.option.LEVEL_2 = level 2 +channel-type.daikin.acunit-fan.state.option.LEVEL_3 = level 3 +channel-type.daikin.acunit-fan.state.option.LEVEL_4 = level 4 +channel-type.daikin.acunit-fan.state.option.LEVEL_5 = level 5 +channel-type.daikin.acunit-fandir.label = Fan Swing +channel-type.daikin.acunit-fandir.description = Current fan swing setting of the AC unit +channel-type.daikin.acunit-fandir.state.option.STOPPED = stopped +channel-type.daikin.acunit-fandir.state.option.VERTICAL = vertical +channel-type.daikin.acunit-fandir.state.option.HORIZONTAL = horizontal +channel-type.daikin.acunit-fandir.state.option.VERTICAL_AND_HORIZONTAL = vertical and horizontal +channel-type.daikin.acunit-homekitmode.label = Homekit Mode +channel-type.daikin.acunit-homekitmode.description = Current Homekit mode of the AC unit +channel-type.daikin.acunit-homekitmode.state.option.auto = Auto +channel-type.daikin.acunit-homekitmode.state.option.heat = Heating On +channel-type.daikin.acunit-homekitmode.state.option.cool = Cooling On +channel-type.daikin.acunit-homekitmode.state.option.off = Off +channel-type.daikin.acunit-humidity.label = Indoor Humidity +channel-type.daikin.acunit-humidity.description = The indoor humidity as measured by the A/C unit +channel-type.daikin.acunit-indoortemp.label = Indoor Temperature +channel-type.daikin.acunit-indoortemp.description = The indoor temperature +channel-type.daikin.acunit-mode.label = Mode +channel-type.daikin.acunit-mode.description = Current mode of the AC unit +channel-type.daikin.acunit-mode.state.option.AUTO = auto +channel-type.daikin.acunit-mode.state.option.DEHUMIDIFIER = dehumidifier +channel-type.daikin.acunit-mode.state.option.COLD = cooling +channel-type.daikin.acunit-mode.state.option.HEAT = heating +channel-type.daikin.acunit-mode.state.option.FAN = fan +channel-type.daikin.acunit-outdoortemp.label = Outdoor Temperature +channel-type.daikin.acunit-outdoortemp.description = The outdoor temperature +channel-type.daikin.acunit-power.label = Power +channel-type.daikin.acunit-power.description = Power for the AC unit +channel-type.daikin.acunit-settemp.label = Set Point +channel-type.daikin.acunit-settemp.description = The set point temperature +channel-type.daikin.acunit-specialmode-powerful.label = Powerful Mode +channel-type.daikin.acunit-specialmode-powerful.description = Powerful mode switch +channel-type.daikin.acunit-specialmode.label = Special Mode +channel-type.daikin.acunit-specialmode.description = Current special mode +channel-type.daikin.airbase-acunit-fan.label = Fan +channel-type.daikin.airbase-acunit-fan.description = Current fan speed setting of the AC unit +channel-type.daikin.airbase-acunit-zone1.label = Zone 1 +channel-type.daikin.airbase-acunit-zone1.description = Zone 1 for the AC unit +channel-type.daikin.airbase-acunit-zone2.label = Zone 2 +channel-type.daikin.airbase-acunit-zone2.description = Zone 2 for the AC unit +channel-type.daikin.airbase-acunit-zone3.label = Zone 3 +channel-type.daikin.airbase-acunit-zone3.description = Zone 3 for the AC unit +channel-type.daikin.airbase-acunit-zone4.label = Zone 4 +channel-type.daikin.airbase-acunit-zone4.description = Zone 4 for the AC unit +channel-type.daikin.airbase-acunit-zone5.label = Zone 5 +channel-type.daikin.airbase-acunit-zone5.description = Zone 5 for the AC unit +channel-type.daikin.airbase-acunit-zone6.label = Zone 6 +channel-type.daikin.airbase-acunit-zone6.description = Zone 6 for the AC unit +channel-type.daikin.airbase-acunit-zone7.label = Zone 7 +channel-type.daikin.airbase-acunit-zone7.description = Zone 7 for the AC unit +channel-type.daikin.airbase-acunit-zone8.label = Zone 8 +channel-type.daikin.airbase-acunit-zone8.description = Zone 8 for the AC unit diff --git a/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties new file mode 100644 index 0000000000000..333b4dbd0bda4 --- /dev/null +++ b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties @@ -0,0 +1,32 @@ +# binding + +binding.dali.name = DALI Binding +binding.dali.description = This is the binding for controlling lights using the Digital Addressable Lighting Interface (DALI). + +# thing types + +thing-type.dali.daliserver.label = Daliserver +thing-type.dali.daliserver.description = A running daliserver. +thing-type.dali.device.label = DALI Device +thing-type.dali.device.description = Controls a single device/ballast +thing-type.dali.group.label = DALI Group +thing-type.dali.group.description = Controls a group of devices/ballasts +thing-type.dali.rgb.label = DALI RGB Device +thing-type.dali.rgb.description = Controls three DALI devices representing R,G,B lighting channels + +# thing types config + +thing-type.config.dali.daliserver.host.label = Host Address +thing-type.config.dali.daliserver.host.description = IP address or host name of daliserver. +thing-type.config.dali.daliserver.port.label = TCP Port +thing-type.config.dali.daliserver.port.description = Port of the daliserver TCP interface. +thing-type.config.dali.device.targetId.label = Device ID +thing-type.config.dali.device.targetId.description = Address of the device in the DALI bus +thing-type.config.dali.group.targetId.label = Group ID +thing-type.config.dali.group.targetId.description = Address of the group in the DALI bus +thing-type.config.dali.rgb.targetIdB.label = B Device ID +thing-type.config.dali.rgb.targetIdB.description = Address of the device in the DALI bus +thing-type.config.dali.rgb.targetIdG.label = G Device ID +thing-type.config.dali.rgb.targetIdG.description = Address of the device in the DALI bus +thing-type.config.dali.rgb.targetIdR.label = R Device ID +thing-type.config.dali.rgb.targetIdR.description = Address of the device in the DALI bus diff --git a/bundles/org.openhab.binding.dbquery/src/main/resources/OH-INF/i18n/dbquery.properties b/bundles/org.openhab.binding.dbquery/src/main/resources/OH-INF/i18n/dbquery.properties new file mode 100644 index 0000000000000..a41848af0f100 --- /dev/null +++ b/bundles/org.openhab.binding.dbquery/src/main/resources/OH-INF/i18n/dbquery.properties @@ -0,0 +1,56 @@ +# binding + +binding.dbquery.name = DBQuery Binding +binding.dbquery.description = This is the binding for DBQuery that allows to execute native database queries and bind their results to items. + +# thing types + +thing-type.dbquery.influxdb2.label = InfluxDB2 Bridge +thing-type.dbquery.influxdb2.description = The InfluxDB 2.0 represents a connection to a InfluxDB 2.0 server +thing-type.dbquery.query.label = Query Thing +thing-type.dbquery.query.description = Thing that represents a native query + +# thing types config + +thing-type.config.dbquery.influxdb2.bucket.label = Bucket +thing-type.config.dbquery.influxdb2.bucket.description = Name of the database bucket +thing-type.config.dbquery.influxdb2.organization.label = Organization +thing-type.config.dbquery.influxdb2.organization.description = Name of the database organization +thing-type.config.dbquery.influxdb2.token.label = Token +thing-type.config.dbquery.influxdb2.token.description = Token to authenticate to the database +thing-type.config.dbquery.influxdb2.url.label = Url +thing-type.config.dbquery.influxdb2.url.description = Database url +thing-type.config.dbquery.influxdb2.user.label = Username +thing-type.config.dbquery.influxdb2.user.description = Name of the database user +thing-type.config.dbquery.query.hasParameters.label = Query has Parameters +thing-type.config.dbquery.query.hasParameters.description = True if the query has parameters, otherwise false +thing-type.config.dbquery.query.interval.label = Interval +thing-type.config.dbquery.query.interval.description = An interval, in seconds, the query will be repeatedly executed. Default values is 0, which means that query is never executed automatically. You need to send the ON command each time you wish to execute. +thing-type.config.dbquery.query.query.label = Query Definition +thing-type.config.dbquery.query.query.description = Query definition using native query language +thing-type.config.dbquery.query.scalarColumn.label = Scalar Column Name +thing-type.config.dbquery.query.scalarColumn.description = The column's name that is used to extract scalarResult. If only one column is returned this parameter can be blank +thing-type.config.dbquery.query.scalarResult.label = Scalar Result +thing-type.config.dbquery.query.scalarResult.description = True if the query always return only one single scalar value (only one row and one value-column in this row), otherwise false +thing-type.config.dbquery.query.timeout.label = Timeout Query +thing-type.config.dbquery.query.timeout.description = A time-out in seconds to wait for the query result, if it's exceeded result will be discarded. Use 0 for no timeout + +# channel types + +channel-type.dbquery.calculate-parameters-channel.label = Calculate Parameters +channel-type.dbquery.calculate-parameters-channel.description = Event to calculate query parameters +channel-type.dbquery.correct-channel.label = Last Query Worked +channel-type.dbquery.correct-channel.description = True if last query executed correctly +channel-type.dbquery.execute-channel.label = Execute Query +channel-type.dbquery.execute-channel.description = Send ON to execute the query, the current state tells if the query is running +channel-type.dbquery.parameters-channel.label = JSON Result +channel-type.dbquery.result-channel-contact.label = Contact Result +channel-type.dbquery.result-channel-contact.description = Execute query and binds result value to channel as a Contact +channel-type.dbquery.result-channel-datetime.label = DateTime Result +channel-type.dbquery.result-channel-datetime.description = Execute query and binds result value to channel as a DateTime +channel-type.dbquery.result-channel-number.label = Number Result +channel-type.dbquery.result-channel-number.description = Execute query and binds result value to channel as a Number +channel-type.dbquery.result-channel-string.label = String Result +channel-type.dbquery.result-channel-string.description = Execute query and binds result value to channel as a String +channel-type.dbquery.result-channel-switch.label = Switch Result +channel-type.dbquery.result-channel-switch.description = Execute query and binds result value to channel as a Switch diff --git a/bundles/org.openhab.binding.denonmarantz/src/main/resources/OH-INF/i18n/denonmarantz.properties b/bundles/org.openhab.binding.denonmarantz/src/main/resources/OH-INF/i18n/denonmarantz.properties new file mode 100644 index 0000000000000..39a3a664203b5 --- /dev/null +++ b/bundles/org.openhab.binding.denonmarantz/src/main/resources/OH-INF/i18n/denonmarantz.properties @@ -0,0 +1,110 @@ +# binding + +binding.denonmarantz.name = DenonMarantz Binding +binding.denonmarantz.description = Binding for controlling network enabled Denon and Marantz receivers. + +# thing types + +thing-type.denonmarantz.avr.label = Denon/Marantz AVR +thing-type.denonmarantz.avr.description = Control a Denon/Marantz AVR. +thing-type.denonmarantz.avr.group.mainZone.label = Main Zone Control +thing-type.denonmarantz.avr.group.mainZone.description = Channels for the main zone of this AVR. +thing-type.denonmarantz.avr.group.zone2.label = Zone 2 Control +thing-type.denonmarantz.avr.group.zone2.description = Channels for zone2 of this AVR. +thing-type.denonmarantz.avr.group.zone3.label = Zone 3 Control +thing-type.denonmarantz.avr.group.zone3.description = Channels for zone3 of this AVR. +thing-type.denonmarantz.avr.group.zone4.label = Zone 4 Control +thing-type.denonmarantz.avr.group.zone4.description = Channels for zone4 of this AVR. + +# thing types config + +thing-type.config.denonmarantz.avr.group.connectionSettings.label = General Connection Settings +thing-type.config.denonmarantz.avr.group.httpSettings.label = HTTP Settings +thing-type.config.denonmarantz.avr.group.httpSettings.description = Settings for the HTTP port of the AVR +thing-type.config.denonmarantz.avr.group.receiverProperties.label = Receiver Properties +thing-type.config.denonmarantz.avr.group.telnetSettings.label = Telnet Settings +thing-type.config.denonmarantz.avr.group.telnetSettings.description = Settings for the Telnet port of the AVR +thing-type.config.denonmarantz.avr.host.label = AVR Host or IP Address +thing-type.config.denonmarantz.avr.host.description = Hostname or IP address of the AVR to control. +thing-type.config.denonmarantz.avr.httpPollingInterval.label = Polling Interval +thing-type.config.denonmarantz.avr.httpPollingInterval.description = Refresh interval of the HTTP API in seconds (minimal 5) +thing-type.config.denonmarantz.avr.httpPort.label = HTTP Port +thing-type.config.denonmarantz.avr.httpPort.description = HTTP Port used for AVR communication. Normally shouldn't be changed. +thing-type.config.denonmarantz.avr.telnetEnabled.label = Use Telnet Port +thing-type.config.denonmarantz.avr.telnetEnabled.description = By using telnet the AVR updates are received immediately. Also, some devices only support telnet. However, the AVR only allows 1 simultaneous connection. Uncheck if you are using dedicated apps to control the AVR. Then HTTP polling is used instead. +thing-type.config.denonmarantz.avr.telnetPort.label = Telnet Port +thing-type.config.denonmarantz.avr.telnetPort.description = Telnet port used for AVR communication. Normally shouldn't be changed. +thing-type.config.denonmarantz.avr.zoneCount.label = Zone Count of the Receiver +thing-type.config.denonmarantz.avr.zoneCount.description = Number of zones (including main zone), values 1-4 are supported. + +# channel group types + +channel-group-type.denonmarantz.general.label = General Control +channel-group-type.denonmarantz.general.description = General channels for this AVR. +channel-group-type.denonmarantz.zone.label = Zone Control +channel-group-type.denonmarantz.zone.description = Channels for a zone of this AVR. + +# channel types + +channel-type.denonmarantz.album.label = Now Playing (album) +channel-type.denonmarantz.album.description = Displays the album of the now playing song. +channel-type.denonmarantz.artist.label = Now Playing (artist) +channel-type.denonmarantz.artist.description = Displays the artist of the now playing song. +channel-type.denonmarantz.command.label = Send a Custom Command +channel-type.denonmarantz.command.description = Use this channel to send any custom command, e.g. SITV or MSSTANDARD (check the protocol documentation) +channel-type.denonmarantz.input.label = Input Source +channel-type.denonmarantz.input.description = Select the input source for this zone of the AVR +channel-type.denonmarantz.input.state.option.DVD = DVD +channel-type.denonmarantz.input.state.option.BD = BD +channel-type.denonmarantz.input.state.option.TV = TV +channel-type.denonmarantz.input.state.option.SAT/CBL = SAT/CBL +channel-type.denonmarantz.input.state.option.SAT = SAT +channel-type.denonmarantz.input.state.option.MPLAY = MPLAY +channel-type.denonmarantz.input.state.option.VCR = VCR +channel-type.denonmarantz.input.state.option.GAME = GAME +channel-type.denonmarantz.input.state.option.V.AUX = V.AUX +channel-type.denonmarantz.input.state.option.TUNER = TUNER +channel-type.denonmarantz.input.state.option.HDRADIO = HDRADIO +channel-type.denonmarantz.input.state.option.SIRIUS = SIRIUS +channel-type.denonmarantz.input.state.option.SPOTIFY = SPOTIFY +channel-type.denonmarantz.input.state.option.SIRIUSXM = SIRIUSXM +channel-type.denonmarantz.input.state.option.RHAPSODY = RHAPSODY +channel-type.denonmarantz.input.state.option.PANDORA = PANDORA +channel-type.denonmarantz.input.state.option.NAPSTER = NAPSTER +channel-type.denonmarantz.input.state.option.LASTFM = LASTFM +channel-type.denonmarantz.input.state.option.FLICKR = FLICKR +channel-type.denonmarantz.input.state.option.IRADIO = IRADIO +channel-type.denonmarantz.input.state.option.SERVER = SERVER +channel-type.denonmarantz.input.state.option.FAVORITES = FAVORITES +channel-type.denonmarantz.input.state.option.CDR = CDR +channel-type.denonmarantz.input.state.option.AUX1 = AUX1 +channel-type.denonmarantz.input.state.option.AUX2 = AUX2 +channel-type.denonmarantz.input.state.option.AUX3 = AUX3 +channel-type.denonmarantz.input.state.option.AUX4 = AUX4 +channel-type.denonmarantz.input.state.option.AUX5 = AUX5 +channel-type.denonmarantz.input.state.option.AUX6 = AUX6 +channel-type.denonmarantz.input.state.option.AUX7 = AUX7 +channel-type.denonmarantz.input.state.option.NET = NET +channel-type.denonmarantz.input.state.option.NET/USB = NET/USB +channel-type.denonmarantz.input.state.option.BT = BT +channel-type.denonmarantz.input.state.option.M-XPORT = M-XPORT +channel-type.denonmarantz.input.state.option.USB/IPOD = USB/IPOD +channel-type.denonmarantz.input.state.option.USB = USB +channel-type.denonmarantz.input.state.option.IPD = IPD +channel-type.denonmarantz.input.state.option.IRP = IRP +channel-type.denonmarantz.input.state.option.FVP = FVP +channel-type.denonmarantz.input.state.option.OTP = OTP +channel-type.denonmarantz.mainPower.label = Power +channel-type.denonmarantz.mainPower.description = Power ON/OFF the AVR +channel-type.denonmarantz.mute.label = Mute +channel-type.denonmarantz.mute.description = Enable/Disable Mute on this zone of the AVR +channel-type.denonmarantz.surroundProgram.label = Surround Program +channel-type.denonmarantz.surroundProgram.description = Select the surround program of the AVR +channel-type.denonmarantz.track.label = Now Playing (track) +channel-type.denonmarantz.track.description = Displays the title of the now playing track. +channel-type.denonmarantz.volume.label = Volume +channel-type.denonmarantz.volume.description = Set the volume level of this zone +channel-type.denonmarantz.volumeDB.label = Volume (dB) +channel-type.denonmarantz.volumeDB.description = Set the volume level (dB). Same as [mainVolume - 80]. +channel-type.denonmarantz.zonePower.label = Power (zone) +channel-type.denonmarantz.zonePower.description = Power ON/OFF this zone of the AVR diff --git a/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn.properties b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn.properties new file mode 100644 index 0000000000000..93aa011039db5 --- /dev/null +++ b/bundles/org.openhab.binding.deutschebahn/src/main/resources/OH-INF/i18n/deutschebahn.properties @@ -0,0 +1,102 @@ +# binding + +binding.deutschebahn.name = Deutsche Bahn Binding +binding.deutschebahn.description = This binding provides timetable information for train stations of Deutsche Bahn. + +# thing types + +thing-type.deutschebahn.timetable.label = Deutsche Bahn Timetable +thing-type.deutschebahn.timetable.description = Connection to the timetable API of Deutsche Bahn. Provides timetable data that can be displayed using the train things. +thing-type.deutschebahn.train.label = Train +thing-type.deutschebahn.train.description = Displays informations about an train within the given timetable at one station. +thing-type.deutschebahn.train.group.arrival.label = Arrival +thing-type.deutschebahn.train.group.arrival.description = Contains all informations about the arrival of the train at the station. Channels may be empty, if the trains starts at this station. +thing-type.deutschebahn.train.group.departure.label = Departure +thing-type.deutschebahn.train.group.departure.description = Contains all informations about the departure of the train at the station. Channels may be empty, if the trains ends at this station. +thing-type.deutschebahn.train.group.trip.label = Trip +thing-type.deutschebahn.train.group.trip.description = Contains all informations about the trip of the train. + +# thing types config + +thing-type.config.deutschebahn.timetable.accessToken.label = Access Token +thing-type.config.deutschebahn.timetable.accessToken.description = Access Token from Deutsche Bahn developer portal for accessing the webservice api. +thing-type.config.deutschebahn.timetable.evaNo.label = EvaNo of Station +thing-type.config.deutschebahn.timetable.evaNo.description = evaNo of the station, for which the timetable should be requested. see https://data.deutschebahn.com/dataset.tags.EVA-Nr..html +thing-type.config.deutschebahn.timetable.trainFilter.label = Train Filter +thing-type.config.deutschebahn.timetable.trainFilter.description = Selects the trains that will be be displayed in this timetable. If not set only departures will be provided. +thing-type.config.deutschebahn.timetable.trainFilter.option.all = All +thing-type.config.deutschebahn.timetable.trainFilter.option.arrivals = Arrivals +thing-type.config.deutschebahn.timetable.trainFilter.option.departures = Departures +thing-type.config.deutschebahn.train.position.label = Position +thing-type.config.deutschebahn.train.position.description = Selects the position of the train in the timetable. + +# channel group types + +channel-group-type.deutschebahn.eventAttributes.label = Event Attributes +channel-group-type.deutschebahn.eventAttributes.description = Contains all attributes for an event (arrival / departure) of an train at the station. +channel-group-type.deutschebahn.tripAttributes.label = Trip Attributes +channel-group-type.deutschebahn.tripAttributes.description = Contains all informations about the trip of the train. + +# channel types + +channel-type.deutschebahn.cancellation-time.label = Cancellation Time +channel-type.deutschebahn.cancellation-time.description = Time when the cancellation of this stop was created. +channel-type.deutschebahn.cancellation-time.state.pattern = %1$tH:%1$tM +channel-type.deutschebahn.category.label = Category +channel-type.deutschebahn.category.description = Provides the category of the trip, e.g. "ICE" or "RE". +channel-type.deutschebahn.changed-distant-endpoint.label = Changed Distant Endpoint +channel-type.deutschebahn.changed-distant-endpoint.description = Changed distant endpoint. +channel-type.deutschebahn.changed-final-station.label = Changed Final Station +channel-type.deutschebahn.changed-final-station.description = Changed final station of the train. For arrivals the starting station is returned, for departures the target station is returned. +channel-type.deutschebahn.changed-intermediate-stations.label = Changed Intermediate Stations +channel-type.deutschebahn.changed-intermediate-stations.description = Returns the changed stations this train came from (for arrivals) or the stations this train will go to (for departures). Stations will be separated by single dash. +channel-type.deutschebahn.changed-path.label = Changed Path +channel-type.deutschebahn.changed-path.description = Provides the planned path of a train. For arrival, the path indicates the stations that come before the current station. The first element then is the trip’s start station. For departure, the path indicates the stations that come after the current station. The last ele-ment in the path then is the trip’s destination station. Note that the current station is never included in the path (neither for arrival nor for departure). +channel-type.deutschebahn.changed-platform.label = Changed Platform +channel-type.deutschebahn.changed-platform.description = Provides the changed platform of a train. +channel-type.deutschebahn.changed-status.label = Changed Status +channel-type.deutschebahn.changed-status.description = Provides the changed status of a train. +channel-type.deutschebahn.changed-status.state.option.p = Planned +channel-type.deutschebahn.changed-status.state.option.a = Added +channel-type.deutschebahn.changed-status.state.option.c = Cancelled +channel-type.deutschebahn.changed-time.label = Changed Time +channel-type.deutschebahn.changed-time.description = Provides the changed time of a train. +channel-type.deutschebahn.changed-time.state.pattern = %1$tH:%1$tM +channel-type.deutschebahn.distant-change.label = Distant Change +channel-type.deutschebahn.distant-change.description = distant change +channel-type.deutschebahn.filter-flags.label = Filter Flags +channel-type.deutschebahn.filter-flags.description = Provides the filter flags. +channel-type.deutschebahn.hidden.label = Hidden +channel-type.deutschebahn.hidden.description = On if the event should not be shown, because travellers are not supposed to enter or exit the train at this stop. +channel-type.deutschebahn.line.label = Line +channel-type.deutschebahn.line.description = The line indicator. +channel-type.deutschebahn.messages.label = Messages +channel-type.deutschebahn.messages.description = Messages for this train. Contains all translated codes from the messages of the selected train stop. Multiple messages will be separated with an single dash. +channel-type.deutschebahn.number.label = Number +channel-type.deutschebahn.number.description = Provides the trip/train number, e.g. "4523". +channel-type.deutschebahn.owner.label = Owner +channel-type.deutschebahn.owner.description = Provides the owner of the train. A unique short-form and only intended to map a trip to specific evu (EisenbahnVerkehrsUnternehmen). +channel-type.deutschebahn.planned-distant-endpoint.label = Planned Distant Endpoint +channel-type.deutschebahn.planned-distant-endpoint.description = Planned distant endpoint. +channel-type.deutschebahn.planned-final-station.label = Planned Final Station +channel-type.deutschebahn.planned-final-station.description = Planned final station of the train. For arrivals the starting station is returned, for departures the target station is returned. +channel-type.deutschebahn.planned-intermediate-stations.label = Planned Intermediate Stations +channel-type.deutschebahn.planned-intermediate-stations.description = Returns the planned stations this train came from (for arrivals) or the stations this train will go to (for departures). Stations will be separated by single dash. +channel-type.deutschebahn.planned-path.label = Planned Path +channel-type.deutschebahn.planned-path.description = Provides the planned path of a train. For arrival, the path indicates the stations that come before the current station. The first element then is the trip’s start station. For departure, the path indicates the stations that come after the current station. The last ele-ment in the path then is the trip’s destination station. Note that the current station is never included in the path (neither for arrival nor for departure). +channel-type.deutschebahn.planned-platform.label = Planned Platform +channel-type.deutschebahn.planned-platform.description = Provides the planned platform of a train. +channel-type.deutschebahn.planned-status.label = Planned Status +channel-type.deutschebahn.planned-status.description = Provides the planned status of a train. +channel-type.deutschebahn.planned-status.state.option.p = Planned +channel-type.deutschebahn.planned-status.state.option.a = Added +channel-type.deutschebahn.planned-status.state.option.c = Cancelled +channel-type.deutschebahn.planned-time.label = Planned Time +channel-type.deutschebahn.planned-time.description = Provides the planned time of a train. +channel-type.deutschebahn.planned-time.state.pattern = %1$tH:%1$tM +channel-type.deutschebahn.transition.label = Transition +channel-type.deutschebahn.transition.description = Trip id of the next or previous train of a shared train. At the start stop this references the previous trip, at the last stop it references the next trip. +channel-type.deutschebahn.trip-type.label = Trip Type +channel-type.deutschebahn.trip-type.description = Provides the type of the trip. +channel-type.deutschebahn.wings.label = Wings +channel-type.deutschebahn.wings.description = A sequence of trip id separated by the pipe symbols (“|”). diff --git a/bundles/org.openhab.binding.digiplex/src/main/resources/OH-INF/i18n/digiplex.properties b/bundles/org.openhab.binding.digiplex/src/main/resources/OH-INF/i18n/digiplex.properties new file mode 100644 index 0000000000000..ae9ea114ea9a1 --- /dev/null +++ b/bundles/org.openhab.binding.digiplex/src/main/resources/OH-INF/i18n/digiplex.properties @@ -0,0 +1,139 @@ +# binding + +binding.digiplex.name = Digiplex/EVO Binding +binding.digiplex.description = Binding for Digiplex/EVO alarm systems (utilizing PRT3 module) + +# thing types + +thing-type.digiplex.area.label = Area +thing-type.digiplex.area.description = Area +thing-type.digiplex.bridge.label = Digiplex PRT3 Module +thing-type.digiplex.bridge.description = Digiplex PRT3 module with Serial Interface +thing-type.digiplex.zone.label = Zone +thing-type.digiplex.zone.description = Zone + +# thing types config + +thing-type.config.digiplex.area.refreshPeriod.label = Refresh Time of Area Status +thing-type.config.digiplex.area.refreshPeriod.description = Controls how often area status will be refreshed from the PRT3 module +thing-type.config.digiplex.bridge.baudrate.label = Baud Rate +thing-type.config.digiplex.bridge.baudrate.description = Set the serial port baud rate +thing-type.config.digiplex.bridge.baudrate.option.2400 = 2400 +thing-type.config.digiplex.bridge.baudrate.option.9600 = 9600 +thing-type.config.digiplex.bridge.baudrate.option.19200 = 19200 +thing-type.config.digiplex.bridge.baudrate.option.57600 = 57600 +thing-type.config.digiplex.bridge.group.port.label = Port Configuration +thing-type.config.digiplex.bridge.port.label = Serial Port +thing-type.config.digiplex.bridge.port.description = Set the serial port used to access PRT3 device + +# channel group types + +channel-group-type.digiplex.statistics.label = Statistics +channel-group-type.digiplex.statistics.description = Statistics of PRT3 communication +channel-group-type.digiplex.troubles.label = Troubles +channel-group-type.digiplex.troubles.description = Problems reported by the alarm system + +# channel types + +channel-type.digiplex.ac_failure.label = AC Line +channel-type.digiplex.ac_failure.description = Reports power line failure +channel-type.digiplex.ac_failure.state.option.ON = Failure +channel-type.digiplex.ac_failure.state.option.OFF = OK +channel-type.digiplex.alarm.label = Area in Alarm +channel-type.digiplex.alarm.description = Indicates if area is in alarm +channel-type.digiplex.alarm.state.option.CLOSED = Ok +channel-type.digiplex.alarm.state.option.OPEN = Alarm +channel-type.digiplex.alarm.label = Alarm Triggered +channel-type.digiplex.alarm.description = Indicates if zone is in alarm +channel-type.digiplex.alarm.state.option.CLOSED = No +channel-type.digiplex.alarm.state.option.OPEN = Yes +channel-type.digiplex.area_armed.label = Area Armed +channel-type.digiplex.area_armed.description = Indicates if area is armed +channel-type.digiplex.area_armed.state.option.CLOSED = Ok +channel-type.digiplex.area_armed.state.option.OPEN = Armed +channel-type.digiplex.area_status.label = Area Status +channel-type.digiplex.area_status.description = Area Status as received from 'Area Status Request' +channel-type.digiplex.area_status.state.option.DISARMED = Disarmed +channel-type.digiplex.area_status.state.option.ARMED = Armed +channel-type.digiplex.area_status.state.option.ARMED_FORCE = Force armed +channel-type.digiplex.area_status.state.option.ARMED_STAY = Stay armed +channel-type.digiplex.area_status.state.option.ARMED_INSTANT = Instant armed +channel-type.digiplex.aux_current_limit.label = AUX Current Limit +channel-type.digiplex.aux_current_limit.description = Auxiliary Outputs have exceeded their current limits +channel-type.digiplex.aux_current_limit.state.option.ON = Exceeded +channel-type.digiplex.aux_current_limit.state.option.OFF = OK +channel-type.digiplex.battery_failure.label = Battery +channel-type.digiplex.battery_failure.description = Reports battery failure +channel-type.digiplex.battery_failure.state.option.ON = Failure +channel-type.digiplex.battery_failure.state.option.OFF = OK +channel-type.digiplex.bell_absent.label = Bell Status +channel-type.digiplex.bell_absent.description = Reports if bell is absent +channel-type.digiplex.bell_absent.state.option.ON = Absent +channel-type.digiplex.bell_absent.state.option.OFF = OK +channel-type.digiplex.bell_current_limit.label = Bell Current Limit +channel-type.digiplex.bell_current_limit.description = Bell Output has exceeded its current limit +channel-type.digiplex.bell_current_limit.state.option.ON = Exceeded +channel-type.digiplex.bell_current_limit.state.option.OFF = OK +channel-type.digiplex.clock_trouble.label = Clock +channel-type.digiplex.clock_trouble.description = Reports if clock is not malfunctioning +channel-type.digiplex.clock_trouble.state.option.ON = Failure +channel-type.digiplex.clock_trouble.state.option.OFF = OK +channel-type.digiplex.control.label = Control Alarm System +channel-type.digiplex.control.description = Used to control area status. By reading its state one can check result of the last command sent to the alarm system. +channel-type.digiplex.control.state.option.OK = Ok +channel-type.digiplex.control.state.option.FAIL = Fail +channel-type.digiplex.events_received.label = Events Received +channel-type.digiplex.events_received.description = Counts events received from the alarm system +channel-type.digiplex.extended_status.label = Extended Zone Status +channel-type.digiplex.extended_status.description = Indicates actual zone state as a string +channel-type.digiplex.extended_status.state.option.CLOSED = Closed +channel-type.digiplex.extended_status.state.option.OPEN = Open +channel-type.digiplex.extended_status.state.option.TAMPERED = Tampered +channel-type.digiplex.extended_status.state.option.FIRE_LOOP_TROUBLE = Fire Loop Trouble +channel-type.digiplex.fire_alarm.label = Fire Alarm Triggered +channel-type.digiplex.fire_alarm.description = Indicates if zone is in fire alarm +channel-type.digiplex.fire_alarm.state.option.CLOSED = No +channel-type.digiplex.fire_alarm.state.option.OPEN = Yes +channel-type.digiplex.global_fire_loop.label = Global Fire Loop +channel-type.digiplex.global_fire_loop.description = Reports if fire loop has been triggered +channel-type.digiplex.global_fire_loop.state.option.ON = Fire! +channel-type.digiplex.global_fire_loop.state.option.OFF = OK +channel-type.digiplex.in_programming.label = Area in Programming Mode +channel-type.digiplex.in_programming.description = Indicates if area is in the programming mode +channel-type.digiplex.in_programming.state.option.CLOSED = Ok +channel-type.digiplex.in_programming.state.option.OPEN = In programming mode +channel-type.digiplex.last_triggered.label = Last Triggered Time +channel-type.digiplex.last_triggered.description = Indicates when the zone has been triggered for the last time +channel-type.digiplex.low_battery.label = Low Battery Warning +channel-type.digiplex.low_battery.description = Indicates if zone is low on battery +channel-type.digiplex.low_battery.state.option.CLOSED = No +channel-type.digiplex.low_battery.state.option.OPEN = Yes +channel-type.digiplex.messages_sent.label = Messages Sent +channel-type.digiplex.messages_sent.description = Counts messages sent to the alarm system +channel-type.digiplex.ready.label = Area Ready +channel-type.digiplex.ready.description = Indicates if area is ready (no open zones) +channel-type.digiplex.ready.state.option.CLOSED = Not ready +channel-type.digiplex.ready.state.option.OPEN = Ready +channel-type.digiplex.responses_received.label = Responses Received +channel-type.digiplex.responses_received.description = Counts responses received from the alarm system +channel-type.digiplex.status.label = Zone Status +channel-type.digiplex.status.description = Zone Status (Open/Closed) +channel-type.digiplex.status.state.option.CLOSED = Closed +channel-type.digiplex.status.state.option.OPEN = Open +channel-type.digiplex.strobe.label = Strobe +channel-type.digiplex.strobe.state.option.CLOSED = Ok +channel-type.digiplex.strobe.state.option.OPEN = Strobe +channel-type.digiplex.supervision_lost.label = Supervision Lost +channel-type.digiplex.supervision_lost.description = Indicates if zone has lost a supervision +channel-type.digiplex.supervision_lost.state.option.CLOSED = No +channel-type.digiplex.supervision_lost.state.option.OPEN = Yes +channel-type.digiplex.tlm_trouble.label = Telephone Line +channel-type.digiplex.tlm_trouble.description = Reports telephone line failure +channel-type.digiplex.tlm_trouble.state.option.ON = Failure +channel-type.digiplex.tlm_trouble.state.option.OFF = OK +channel-type.digiplex.trouble.label = Trouble +channel-type.digiplex.trouble.state.option.CLOSED = Ok +channel-type.digiplex.trouble.state.option.OPEN = Trouble +channel-type.digiplex.zone_in_memory.label = Zone in Memory +channel-type.digiplex.zone_in_memory.state.option.CLOSED = Ok +channel-type.digiplex.zone_in_memory.state.option.OPEN = Zone in memory diff --git a/bundles/org.openhab.binding.dlinksmarthome/src/main/resources/OH-INF/i18n/dlinksmarthome.properties b/bundles/org.openhab.binding.dlinksmarthome/src/main/resources/OH-INF/i18n/dlinksmarthome.properties new file mode 100644 index 0000000000000..73e26f6c28ab6 --- /dev/null +++ b/bundles/org.openhab.binding.dlinksmarthome/src/main/resources/OH-INF/i18n/dlinksmarthome.properties @@ -0,0 +1,18 @@ +# binding + +binding.dlinksmarthome.name = D-Link Smart Home Binding +binding.dlinksmarthome.description = This is the binding for D-Link Smart Home devices + +# thing types + +thing-type.dlinksmarthome.DCH-S150.label = Motion Sensor +thing-type.dlinksmarthome.DCH-S150.description = D-Link DCH-S150 WiFi motion sensor +thing-type.dlinksmarthome.DCH-S150.channel.motion.label = Motion Detected +thing-type.dlinksmarthome.DCH-S150.channel.motion.description = Triggered when the sensor detects motion + +# thing types config + +thing-type.config.dlinksmarthome.DCH-S150.ipAddress.label = Hostname or IP +thing-type.config.dlinksmarthome.DCH-S150.ipAddress.description = Hostname or IP of the device. +thing-type.config.dlinksmarthome.DCH-S150.pin.label = PIN Code +thing-type.config.dlinksmarthome.DCH-S150.pin.description = PIN code from the back of the device. diff --git a/bundles/org.openhab.binding.dmx/src/main/resources/OH-INF/i18n/dmx.properties b/bundles/org.openhab.binding.dmx/src/main/resources/OH-INF/i18n/dmx.properties new file mode 100644 index 0000000000000..5ac05cd550b58 --- /dev/null +++ b/bundles/org.openhab.binding.dmx/src/main/resources/OH-INF/i18n/dmx.properties @@ -0,0 +1,116 @@ +# binding + +binding.dmx.name = DMX Binding +binding.dmx.description = This is the binding for DMX. + +# thing types + +thing-type.dmx.artnet-bridge.label = ArtNet Bridge +thing-type.dmx.artnet-bridge.description = The ArtNet bridge represents a single DMX universe connected via ArtNet, only unicast +thing-type.dmx.chaser.label = DMX Chaser +thing-type.dmx.chaser.description = A single/multi-channel chaser +thing-type.dmx.color.label = DMX Color (RGB) Dimmer +thing-type.dmx.color.description = A RGB capable dimmer +thing-type.dmx.dimmer.label = DMX Dimmer +thing-type.dmx.dimmer.description = A single/multi-channel dimmer +thing-type.dmx.lib485-bridge.label = Lib485 Bridge +thing-type.dmx.lib485-bridge.description = The Lib485 bridge represents a single DMX universe connected via Lib485 +thing-type.dmx.sacn-bridge.label = sACN/E1.31 Bridge +thing-type.dmx.sacn-bridge.description = The sACN/E1.31 bridge represents a single DMX universe connected via sACN/E1.31 +thing-type.dmx.tunablewhite.label = DMX Tunable White Dimmer +thing-type.dmx.tunablewhite.description = A tunable white capable dimmer + +# thing types config + +thing-type.config.dmx.artnet-bridge.address.label = Receiver Address(es) +thing-type.config.dmx.artnet-bridge.address.description = Network addresses of ArtNet receivers, format: address[:port][, address[:port], ...]. Default port is 6454. +thing-type.config.dmx.artnet-bridge.applycurve.label = Apply Curve +thing-type.config.dmx.artnet-bridge.applycurve.description = List of channels that should use LED dim curve. Format is channel[,channel, ...] or channel[/width]. +thing-type.config.dmx.artnet-bridge.localaddress.label = Local Network Address +thing-type.config.dmx.artnet-bridge.localaddress.description = Network address of the sending host, format: address[:port]. Default port is 0 (random) +thing-type.config.dmx.artnet-bridge.refreshmode.label = Refresh Mode +thing-type.config.dmx.artnet-bridge.refreshmode.description = Suppress re-transmission and refresh every 800ms or send every packet. +thing-type.config.dmx.artnet-bridge.refreshmode.option.always = Always +thing-type.config.dmx.artnet-bridge.refreshmode.option.standard = Standard +thing-type.config.dmx.artnet-bridge.refreshrate.description = DMX refresh rate in Hz (0=disable output) +thing-type.config.dmx.artnet-bridge.universe.label = DMX Universe +thing-type.config.dmx.artnet-bridge.universe.description = ID of DMX universe (0-32767) +thing-type.config.dmx.chaser.dmxid.label = DMX Channel Configuration +thing-type.config.dmx.chaser.dmxid.description = Format is channel[,channel, ...] or channel[/width] +thing-type.config.dmx.chaser.resumeafter.label = Resume After Finish +thing-type.config.dmx.chaser.resumeafter.description = resume old actions after this completes +thing-type.config.dmx.chaser.steps.label = Step Configuration +thing-type.config.dmx.chaser.steps.description = fadeTime:value[, ...]:holdTime +thing-type.config.dmx.color.dimtime.label = Dim Time +thing-type.config.dmx.color.dimtime.description = Time in ms for dimming from 0-100% +thing-type.config.dmx.color.dmxid.label = DMX Channel Configuration +thing-type.config.dmx.color.dmxid.description = Format is channel[,channel, ...] or channel[/width], has to be multiple of three +thing-type.config.dmx.color.dynamicturnonvalue.label = Dynamic Turn-On Value +thing-type.config.dmx.color.dynamicturnonvalue.description = If enabled, values are stored on OFF command and restored on ON command +thing-type.config.dmx.color.fadetime.label = Fade Time +thing-type.config.dmx.color.fadetime.description = Fade time in ms for changing values +thing-type.config.dmx.color.turnoffvalue.label = Turn-Off Value(s) +thing-type.config.dmx.color.turnoffvalue.description = Format is "value[, value, ...]", has to be a multiple of three. If less values than channels are defined, they are reused from the beginning. +thing-type.config.dmx.color.turnonvalue.label = Turn-On Value(s) +thing-type.config.dmx.color.turnonvalue.description = Format is "value[, value, ...]", has to be a multiple of three. If less values than channels are defined, they are reused from the beginning. +thing-type.config.dmx.dimmer.dimtime.label = Dim Time +thing-type.config.dmx.dimmer.dimtime.description = Time in ms for dimming from 0-100% +thing-type.config.dmx.dimmer.dmxid.label = DMX Channel Configuration +thing-type.config.dmx.dimmer.dmxid.description = Format is channel[,channel, ...] or channel[/width] +thing-type.config.dmx.dimmer.dynamicturnonvalue.label = Dynamic Turn-On Value +thing-type.config.dmx.dimmer.dynamicturnonvalue.description = If enabled, values are stored on OFF command and restored on ON command +thing-type.config.dmx.dimmer.fadetime.label = Fade Time +thing-type.config.dmx.dimmer.fadetime.description = Fade time in ms for changing values +thing-type.config.dmx.dimmer.turnoffvalue.label = Turn-Off Value(s) +thing-type.config.dmx.dimmer.turnoffvalue.description = Format is "value[, value, ...]". If less values than channels are defined, they are reused from the beginning. +thing-type.config.dmx.dimmer.turnonvalue.label = Turn-On Value(s) +thing-type.config.dmx.dimmer.turnonvalue.description = Format is "value[, value, ...]". If less values than channels are defined, they are reused from the beginning. +thing-type.config.dmx.lib485-bridge.address.label = Network Address +thing-type.config.dmx.lib485-bridge.address.description = Network address of bridge, format: address[:port]. Default port is 9020. +thing-type.config.dmx.lib485-bridge.applycurve.label = Apply Curve +thing-type.config.dmx.lib485-bridge.applycurve.description = List of channels that should use LED dim curve. Format is channel[,channel, ...] or channel[/width]. +thing-type.config.dmx.lib485-bridge.refreshrate.description = DMX refresh rate in Hz (0=disable output) +thing-type.config.dmx.sacn-bridge.address.label = Receiver Address(es) +thing-type.config.dmx.sacn-bridge.address.description = Network addresses of sACN/E1.31 receivers, format: address[:port][, address[:port], ...]. Default port is 5568. +thing-type.config.dmx.sacn-bridge.applycurve.label = Apply Curve +thing-type.config.dmx.sacn-bridge.applycurve.description = List of channels that should use LED dim curve. Format is channel[,channel, ...] or channel[/width]. +thing-type.config.dmx.sacn-bridge.localaddress.label = Local Network Address +thing-type.config.dmx.sacn-bridge.localaddress.description = Network address of the sending host, format: address[:port]. Default port is 0 (random) +thing-type.config.dmx.sacn-bridge.mode.label = Transmission Mode +thing-type.config.dmx.sacn-bridge.mode.description = Set UDP mode to multicast (default)/unicast +thing-type.config.dmx.sacn-bridge.mode.option.unicast = Unicast +thing-type.config.dmx.sacn-bridge.mode.option.multicast = Multicast +thing-type.config.dmx.sacn-bridge.refreshmode.label = Refresh Mode +thing-type.config.dmx.sacn-bridge.refreshmode.description = Suppress re-transmission and refresh every 800ms or send every packet. +thing-type.config.dmx.sacn-bridge.refreshmode.option.always = Always +thing-type.config.dmx.sacn-bridge.refreshmode.option.standard = Standard +thing-type.config.dmx.sacn-bridge.refreshrate.description = DMX refresh rate in Hz +thing-type.config.dmx.sacn-bridge.universe.label = DMX Universe +thing-type.config.dmx.sacn-bridge.universe.description = ID of DMX universe (1-63999) +thing-type.config.dmx.tunablewhite.dimtime.label = Dim Time +thing-type.config.dmx.tunablewhite.dimtime.description = Time in ms for dimming from 0-100% +thing-type.config.dmx.tunablewhite.dmxid.label = DMX Channel Configuration +thing-type.config.dmx.tunablewhite.dmxid.description = Format is channel[,channel, ...] or channel[/width], has to be an even number +thing-type.config.dmx.tunablewhite.dynamicturnonvalue.label = Dynamic Turn-On Value +thing-type.config.dmx.tunablewhite.dynamicturnonvalue.description = If enabled, values are stored on OFF command and restored on ON command +thing-type.config.dmx.tunablewhite.fadetime.label = Fade Time +thing-type.config.dmx.tunablewhite.fadetime.description = Fade time in ms for changing values +thing-type.config.dmx.tunablewhite.turnoffvalue.label = Turn-Off Value(s) +thing-type.config.dmx.tunablewhite.turnoffvalue.description = Format is "value[, value, ...]", has to be a multiple of two. If less values than channels are defined, they are reused from the beginning. +thing-type.config.dmx.tunablewhite.turnonvalue.label = Turn-On Value(s) +thing-type.config.dmx.tunablewhite.turnonvalue.description = Format is "value[, value, ...]", has to be a multiple of two. If less values than channels are defined, they are reused from the beginning. + +# channel types + +channel-type.dmx.brightness.label = Brightness +channel-type.dmx.brightness.description = Allows to send a brightness value to the thing. If the thing is associated with more than one DMX channel, the values is used for ALL DMX channels. +channel-type.dmx.color.label = Color +channel-type.dmx.color.description = Allows to send a color value to the thing. If the thing is associated with more than one DMX channel, color will be re-use in 3-channel groups. +channel-type.dmx.color_temperature.label = Color Temperature +channel-type.dmx.color_temperature.description = Relative intensity of two adjacent DMX channels +channel-type.dmx.control.label = Control +channel-type.dmx.control.description = Change Fade Configuration +channel-type.dmx.mute.label = Mute +channel-type.dmx.mute.description = Mutes the DMX output of the Bridge +channel-type.dmx.switch.label = Switch +channel-type.dmx.switch.description = Allows to switch a thing ON or OFF. diff --git a/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss.properties b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss.properties new file mode 100644 index 0000000000000..88572ea3424e7 --- /dev/null +++ b/bundles/org.openhab.binding.dominoswiss/src/main/resources/OH-INF/i18n/dominoswiss.properties @@ -0,0 +1,41 @@ +# binding + +binding.dominoswiss.name = Dominoswiss Binding +binding.dominoswiss.description = The Dominoswiss Binding interacts with the Dominoswiss eGate G1 Gateway to control blinds + +# thing types + +thing-type.dominoswiss.blind.label = Blind +thing-type.dominoswiss.blind.description = Provides various control commands for Dominoswiss receivers +thing-type.dominoswiss.egate.label = Dominoswiss EGate Server +thing-type.dominoswiss.egate.description = This is a Dominoswiss EGate Server instance. + +# thing types config + +thing-type.config.dominoswiss.blind.id.label = ID Address +thing-type.config.dominoswiss.blind.id.description = Blinds are identified by their ID address +thing-type.config.dominoswiss.egate.ipAddress.label = IP or Host Name +thing-type.config.dominoswiss.egate.ipAddress.description = The IP or host name of the Dominoswiss EGate Server (192.168.1.100, localhost) +thing-type.config.dominoswiss.egate.port.label = Web Port +thing-type.config.dominoswiss.egate.port.description = Port interface of the Dominoswiss EGate Server, default 1318 + +# channel types + +channel-type.dominoswiss.continuousDown.label = Continuous Down +channel-type.dominoswiss.continuousDown.description = Send continuous down command to blind +channel-type.dominoswiss.continuousUp.label = Continuous Up +channel-type.dominoswiss.continuousUp.description = Send continuous up command to blind +channel-type.dominoswiss.pulseDown.label = Pulse Down +channel-type.dominoswiss.pulseDown.description = Send one pulse down +channel-type.dominoswiss.pulseUp.label = Pulse Up +channel-type.dominoswiss.pulseUp.description = Send one pulse up +channel-type.dominoswiss.shutter.label = Shutter +channel-type.dominoswiss.shutter.description = Handle the commands up/down/stop +channel-type.dominoswiss.shutterTilt.label = Shutter Tilt Up Down +channel-type.dominoswiss.shutterTilt.description = Handle the commands tiltUp/tiltDown/stop +channel-type.dominoswiss.stop.label = Stop +channel-type.dominoswiss.stop.description = Send stop impulse to stop the blinds +channel-type.dominoswiss.tiltDown.label = Tilt Down +channel-type.dominoswiss.tiltDown.description = Handle the command for 3 tilts down +channel-type.dominoswiss.tiltUp.label = Tilt Up +channel-type.dominoswiss.tiltUp.description = Handle the command for 3 tilts up diff --git a/bundles/org.openhab.binding.doorbird/src/main/resources/OH-INF/i18n/doorbird.properties b/bundles/org.openhab.binding.doorbird/src/main/resources/OH-INF/i18n/doorbird.properties new file mode 100644 index 0000000000000..9645be95d324f --- /dev/null +++ b/bundles/org.openhab.binding.doorbird/src/main/resources/OH-INF/i18n/doorbird.properties @@ -0,0 +1,81 @@ +# binding + +binding.doorbird.name = Doorbird Binding +binding.doorbird.description = This is the binding for Doorbird video doorbells. + +# thing types + +thing-type.doorbird.a1081.label = Doorbird A1081 Controller +thing-type.doorbird.a1081.description = Doorbird model A1081 Controller +thing-type.doorbird.d101.label = Doorbird Doorbell D101/D201/D205/D1101V +thing-type.doorbird.d101.description = Doorbird doorbell model D101/D201/D205/D1101V +thing-type.doorbird.d101.channel.doorbell.label = Doorbell +thing-type.doorbird.d101.channel.doorbell.description = Trigger for doorbell press +thing-type.doorbird.d210x.label = Doorbird D210x Doorbell +thing-type.doorbird.d210x.description = Doorbird doorbell model D210x +thing-type.doorbird.d210x.channel.doorbell.label = Doorbell +thing-type.doorbird.d210x.channel.doorbell.description = Trigger for doorbell press + +# thing types config + +thing-type.config.controller.config.doorbirdHost.label = Host +thing-type.config.controller.config.doorbirdHost.description = Hostname or IP address of Doorbird +thing-type.config.controller.config.userId.label = User ID +thing-type.config.controller.config.userId.description = Doorbird user ID with API permissions enabled +thing-type.config.controller.config.userPassword.label = Password +thing-type.config.controller.config.userPassword.description = Doorbird user password +thing-type.config.doorbird.config.doorbellOffDelay.label = Doorbell Released Delay +thing-type.config.doorbird.config.doorbellOffDelay.description = Delay in seconds after a doorbell event to send RELEASED event (blank to disable) +thing-type.config.doorbird.config.doorbirdHost.label = Host +thing-type.config.doorbird.config.doorbirdHost.description = Hostname or IP address of Doorbird +thing-type.config.doorbird.config.imageRefreshRate.label = Image Refresh Rate +thing-type.config.doorbird.config.imageRefreshRate.description = Image refresh rate in seconds (blank to disable) +thing-type.config.doorbird.config.montageNumImages.label = Montage Number of Images +thing-type.config.doorbird.config.montageNumImages.description = Number of images to include in history montage +thing-type.config.doorbird.config.montageScaleFactor.label = Montage Scale Factor +thing-type.config.doorbird.config.montageScaleFactor.description = Scaling factor percentage to apply to history montage (e.g use 25 for 25%) +thing-type.config.doorbird.config.motionOffDelay.label = Motion Off Delay +thing-type.config.doorbird.config.motionOffDelay.description = Delay in seconds to set motion channel OFF after motion event (blank to disable) +thing-type.config.doorbird.config.userId.label = User ID +thing-type.config.doorbird.config.userId.description = Doorbird user ID with API permissions enabled +thing-type.config.doorbird.config.userPassword.label = Password +thing-type.config.doorbird.config.userPassword.description = Doorbird user password + +# channel types + +channel-type.doorbird.doorbellHistoryImage.label = Doorbell History Image +channel-type.doorbird.doorbellHistoryImage.description = Historical image for doorbell press +channel-type.doorbird.doorbellHistoryIndex.label = Doorbell History Index +channel-type.doorbird.doorbellHistoryIndex.description = Index of historical image for doorbell press +channel-type.doorbird.doorbellHistoryTimestamp.label = Doorbell History Timestamp +channel-type.doorbird.doorbellHistoryTimestamp.description = Time when doorbell was pressed for history image +channel-type.doorbird.doorbellImage.label = Doorbell Pressed Image +channel-type.doorbird.doorbellImage.description = Image when doorbell was last pressed +channel-type.doorbird.doorbellMontage.label = Doorbell Montage Image +channel-type.doorbird.doorbellMontage.description = Montage of multiple doorbell history images +channel-type.doorbird.doorbellTimestamp.label = Doorbell Timestamp +channel-type.doorbird.doorbellTimestamp.description = Time when doorbell was last pressed +channel-type.doorbird.image.label = Image +channel-type.doorbird.image.description = Image from device +channel-type.doorbird.imageTimestamp.label = Image Timestamp +channel-type.doorbird.imageTimestamp.description = Time when image was captured from device +channel-type.doorbird.light.label = Light +channel-type.doorbird.light.description = Energize the light relay +channel-type.doorbird.motionHistoryImage.label = Motion History Image +channel-type.doorbird.motionHistoryImage.description = Historical image for motion sensor +channel-type.doorbird.motionHistoryIndex.label = Motion History Index +channel-type.doorbird.motionHistoryIndex.description = Index of Historical image for motion +channel-type.doorbird.motionHistoryTimestamp.label = Motion History Timestamp +channel-type.doorbird.motionHistoryTimestamp.description = Time when motion was detected for history image +channel-type.doorbird.motionImage.label = Motion Detected Image +channel-type.doorbird.motionImage.description = Image when motion was last detected +channel-type.doorbird.motionMontage.label = Motion Montage Image +channel-type.doorbird.motionMontage.description = Montage of multiple motion history images +channel-type.doorbird.motionTimestamp.label = Motion Timestamp +channel-type.doorbird.motionTimestamp.description = Time when motion was last detected +channel-type.doorbird.openDoor1.label = Open Door 1 +channel-type.doorbird.openDoor1.description = Energize opendoor / alarm output relay 1 +channel-type.doorbird.openDoor2.label = Open Door 2 +channel-type.doorbird.openDoor2.description = Energize opendoor / alarm output relay 2 +channel-type.doorbird.openDoor3.label = Open Door 3 +channel-type.doorbird.openDoor3.description = Energize opendoor / alarm output relay 3 diff --git a/bundles/org.openhab.binding.draytonwiser/src/main/resources/OH-INF/i18n/draytonwiser.properties b/bundles/org.openhab.binding.draytonwiser/src/main/resources/OH-INF/i18n/draytonwiser.properties new file mode 100644 index 0000000000000..bcb9bdd506838 --- /dev/null +++ b/bundles/org.openhab.binding.draytonwiser/src/main/resources/OH-INF/i18n/draytonwiser.properties @@ -0,0 +1,115 @@ +# binding + +binding.draytonwiser.name = DraytonWiser Binding +binding.draytonwiser.description = This is the binding for Drayton Wiser smart heating system. + +# thing types + +thing-type.draytonwiser.boiler-controller.label = Boiler Controller +thing-type.draytonwiser.boiler-controller.description = The controller attached to the boiler +thing-type.draytonwiser.boiler-controller.channel.heatChannel1Demand.label = Channel 1 Heat Demand +thing-type.draytonwiser.boiler-controller.channel.heatChannel1DemandState.label = Channel 1 Requesting Heat +thing-type.draytonwiser.boiler-controller.channel.heatChannel2Demand.label = Channel 2 Heat Demand +thing-type.draytonwiser.boiler-controller.channel.heatChannel2DemandState.label = Channel 2 Requesting Heat +thing-type.draytonwiser.heathub.label = HeatHub +thing-type.draytonwiser.heathub.description = A Drayton Wiser HeatHub acting as a bridge to Thermostats and TRVs +thing-type.draytonwiser.hotwater.label = Hot Water +thing-type.draytonwiser.hotwater.description = The hot water heating system +thing-type.draytonwiser.hotwater.channel.hotWaterBoostDuration.description = Duration to boost hot water for +thing-type.draytonwiser.hotwater.channel.hotWaterBoosted.description = Is the hot water currently being boosted +thing-type.draytonwiser.hotwater.channel.hotWaterDemandState.label = Hot Water Requesting Heat +thing-type.draytonwiser.hotwater.channel.hotWaterDemandState.description = Hot Water is requesting heat +thing-type.draytonwiser.itrv.label = iTRV +thing-type.draytonwiser.itrv.description = Thermostatic Radiator Valve +thing-type.draytonwiser.room.label = Room +thing-type.draytonwiser.room.description = A Room that contains a thermostat and/or TRV +thing-type.draytonwiser.room.channel.roomBoostDuration.description = Duration to boost the temperature for +thing-type.draytonwiser.room.channel.roomBoosted.description = Is the room temperature currently being boosted +thing-type.draytonwiser.roomstat.label = Thermostat +thing-type.draytonwiser.roomstat.description = Wireless Thermostat device +thing-type.draytonwiser.smart-plug.label = Smart Plug +thing-type.draytonwiser.smart-plug.description = Remote controlled Plug Socket + +# thing types config + +thing-type.config.draytonwiser.heathub.awaySetPoint.label = Away Mode Set Point +thing-type.config.draytonwiser.heathub.awaySetPoint.description = Set point temperature for away mode in degrees celsius +thing-type.config.draytonwiser.heathub.networkAddress.label = Network Address +thing-type.config.draytonwiser.heathub.networkAddress.description = Network address of the HeatHub +thing-type.config.draytonwiser.heathub.refresh.label = Refresh Interval +thing-type.config.draytonwiser.heathub.refresh.description = Interval in seconds between automatic refreshes +thing-type.config.draytonwiser.heathub.secret.label = Authorisation Token +thing-type.config.draytonwiser.heathub.secret.description = Auth token required to access the API +thing-type.config.draytonwiser.itrv.serialNumber.label = Serial Number +thing-type.config.draytonwiser.itrv.serialNumber.description = Device Serial Number +thing-type.config.draytonwiser.room.name.label = Room Name +thing-type.config.draytonwiser.room.name.description = The room name as it appears in the Wiser app +thing-type.config.draytonwiser.roomstat.serialNumber.label = Serial Number +thing-type.config.draytonwiser.roomstat.serialNumber.description = Device Serial Number +thing-type.config.draytonwiser.smart-plug.serialNumber.label = Serial Number +thing-type.config.draytonwiser.smart-plug.serialNumber.description = Device Serial Number + +# channel types + +channel-type.draytonwiser.atmospheric-humidity-channel.label = Humidity +channel-type.draytonwiser.atmospheric-humidity-channel.description = Current relative humidity +channel-type.draytonwiser.awayModeSetPoint-channel.label = Away Mode Set Point +channel-type.draytonwiser.awayModeSetPoint-channel.description = Away Mode Set Point +channel-type.draytonwiser.awayModeState-channel.label = Away Mode Active +channel-type.draytonwiser.awayModeState-channel.description = Away mode has been activated +channel-type.draytonwiser.batteryVoltage-channel.label = Battery Voltage +channel-type.draytonwiser.batteryVoltage-channel.description = Current Battery Voltage for the device +channel-type.draytonwiser.boostDuration-channel.label = Boost Duration +channel-type.draytonwiser.boostDuration-channel.description = Duration in hours to boost hot water for +channel-type.draytonwiser.boostRemaining-channel.label = Boost Remaining +channel-type.draytonwiser.boostRemaining-channel.description = How long until the boost deactivates +channel-type.draytonwiser.boosted-channel.label = Is Boosted +channel-type.draytonwiser.boosted-channel.description = Is the hot water currently being boosted +channel-type.draytonwiser.comfortModeState-channel.label = Comfort Mode Active +channel-type.draytonwiser.comfortModeState-channel.description = Should the room pre-heat to achieve the desired temperature +channel-type.draytonwiser.currentSetPoint-channel.label = Set Point +channel-type.draytonwiser.currentSetPoint-channel.description = Current set point +channel-type.draytonwiser.currentTemperature-channel.label = Temperature +channel-type.draytonwiser.currentTemperature-channel.description = Current temperature +channel-type.draytonwiser.demandPercent-channel.label = Current Heat Demand +channel-type.draytonwiser.demandPercent-channel.description = Current heat demand in % +channel-type.draytonwiser.demandState-channel.label = Requesting Heat +channel-type.draytonwiser.demandState-channel.description = Current channel is requesting heat +channel-type.draytonwiser.deviceLocked-channel.label = Device Locked +channel-type.draytonwiser.deviceLocked-channel.description = Has the device been locked to prevent local changes +channel-type.draytonwiser.ecoModeState-channel.label = Eco Mode Enabled +channel-type.draytonwiser.ecoModeState-channel.description = Eco Mode activation state (EcoIQ) +channel-type.draytonwiser.heatChannelDemand-channel.label = Heat Demand +channel-type.draytonwiser.heatChannelDemand-channel.description = Current heat demand in % +channel-type.draytonwiser.heatRequest-channel.label = Currently Requesting Heat +channel-type.draytonwiser.heatRequest-channel.description = Is this room requesting heat +channel-type.draytonwiser.heatingOverride-channel.label = Heating Override +channel-type.draytonwiser.heatingOverride-channel.description = The heating override button has been pressed +channel-type.draytonwiser.hotWaterOverride-channel.label = Hot Water Override +channel-type.draytonwiser.hotWaterOverride-channel.description = The hot water override button has been pressed +channel-type.draytonwiser.hotWaterSetPoint-channel.label = Set Point +channel-type.draytonwiser.hotWaterSetPoint-channel.description = Hot water heating set point switch +channel-type.draytonwiser.manualModeState-channel.label = Manual Mode Enabled +channel-type.draytonwiser.manualModeState-channel.description = Manual Mode activation state +channel-type.draytonwiser.plugAwayAction-channel.label = Plug Off in Away Mode +channel-type.draytonwiser.plugAwayAction-channel.description = Should the smart plug switch off when in away mode +channel-type.draytonwiser.plugEnergyDelivered-channel.label = Plug Energy Delivered +channel-type.draytonwiser.plugEnergyDelivered-channel.description = Cumulative energy drawn through the plug +channel-type.draytonwiser.plugInstantaneousPower-channel.label = Plug Instantaneous Power +channel-type.draytonwiser.plugInstantaneousPower-channel.description = Current Power being drawn through the plug +channel-type.draytonwiser.plugOutputState-channel.label = Plug State +channel-type.draytonwiser.plugOutputState-channel.description = Is the smart plug switched on or off +channel-type.draytonwiser.signalLQI-channel.label = Signal LQI +channel-type.draytonwiser.signalLQI-channel.description = The reported network signal LQI +channel-type.draytonwiser.signalRSSI-channel.label = Signal RSSI +channel-type.draytonwiser.signalRSSI-channel.description = The reported network signal RSSI +channel-type.draytonwiser.windowState-channel.label = Window State +channel-type.draytonwiser.windowState-channel.description = Is the window open or closed +channel-type.draytonwiser.windowStateDetection-channel.label = Open Window Detection +channel-type.draytonwiser.windowStateDetection-channel.description = Is window detection turned on +channel-type.draytonwiser.wiserBatteryLevel-channel.label = Battery Level (Wiser) +channel-type.draytonwiser.wiserBatteryLevel-channel.description = Current Battery Level for the device +channel-type.draytonwiser.wiserSignalStrength-channel.label = Signal Strength (Wiser) +channel-type.draytonwiser.wiserSignalStrength-channel.description = The reported network signal strength +channel-type.draytonwiser.zigbeeConnected-channel.label = Device Connected +channel-type.draytonwiser.zigbeeConnected-channel.description = Is the device still connected to the ZigBee network diff --git a/bundles/org.openhab.binding.dscalarm/src/main/resources/OH-INF/i18n/dscalarm.properties b/bundles/org.openhab.binding.dscalarm/src/main/resources/OH-INF/i18n/dscalarm.properties new file mode 100644 index 0000000000000..f86f69f754598 --- /dev/null +++ b/bundles/org.openhab.binding.dscalarm/src/main/resources/OH-INF/i18n/dscalarm.properties @@ -0,0 +1,203 @@ +# binding + +binding.dscalarm.name = DSCAlarm Binding +binding.dscalarm.description = The DSCAlarm binding interfaces with a DSC PowerSeries Alarm System through the EyezOn Envisalink 3/2DS interface or the DSC IT-100 RS-232 interface. + +# thing types + +thing-type.dscalarm.envisalink.label = EyezOn Envisalink +thing-type.dscalarm.envisalink.description = This bridge represents the EyezOn Envlisalink 3/2D Ethernet interface. +thing-type.dscalarm.envisalink.channel.bridge_reset.label = Reset Envisalink +thing-type.dscalarm.envisalink.channel.bridge_reset.description = Resets the Envisalink +thing-type.dscalarm.envisalink.channel.send_command.label = Send Command +thing-type.dscalarm.envisalink.channel.send_command.description = Sends a DSC Alarm Command +thing-type.dscalarm.it100.label = DSC IT-100 +thing-type.dscalarm.it100.description = This bridge represents the DSC IT-100 Serial interface. +thing-type.dscalarm.it100.channel.bridge_reset.label = Reset IT100 +thing-type.dscalarm.it100.channel.bridge_reset.description = Resets the IT100 +thing-type.dscalarm.it100.channel.send_command.label = Send Command +thing-type.dscalarm.it100.channel.send_command.description = Sends a DSC Alarm Command +thing-type.dscalarm.keypad.label = DSC Alarm Keypad +thing-type.dscalarm.keypad.description = Represents the central administrative unit of the DSC Alarm System. +thing-type.dscalarm.keypad.channel.keypad_ac_led.label = Keypad AC LED +thing-type.dscalarm.keypad.channel.keypad_ac_led.description = Keypad AC LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_armed_led.label = Keypad Armed LED +thing-type.dscalarm.keypad.channel.keypad_armed_led.description = Keypad Armed LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_backlight_led.label = Keypad Backlight LED +thing-type.dscalarm.keypad.channel.keypad_backlight_led.description = Keypad Backlight LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_bypass_led.label = Keypad Bypass LED +thing-type.dscalarm.keypad.channel.keypad_bypass_led.description = Keypad Bypass LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_fire_led.label = Keypad Fire LED +thing-type.dscalarm.keypad.channel.keypad_fire_led.description = Keypad Fire LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_lcd_cursor.label = Keypad LCD Cursor +thing-type.dscalarm.keypad.channel.keypad_lcd_cursor.description = Keypad LCD Cursor Position Changes +thing-type.dscalarm.keypad.channel.keypad_lcd_update.label = Keypad LCD Update +thing-type.dscalarm.keypad.channel.keypad_lcd_update.description = Keypad LCD Menu Changes +thing-type.dscalarm.keypad.channel.keypad_memory_led.label = Keypad Memory LED +thing-type.dscalarm.keypad.channel.keypad_memory_led.description = Keypad Memory LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_program_led.label = Keypad Program LED +thing-type.dscalarm.keypad.channel.keypad_program_led.description = Keypad Program LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_ready_led.label = Keypad Ready LED +thing-type.dscalarm.keypad.channel.keypad_ready_led.description = Keypad Ready LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.keypad.channel.keypad_trouble_led.label = Keypad Trouble LED +thing-type.dscalarm.keypad.channel.keypad_trouble_led.description = Keypad Trouble LED (0=Off, 1=On, 2=Flashing) +thing-type.dscalarm.panel.label = DSC Alarm Panel +thing-type.dscalarm.panel.description = The basic representation of the DSC Alarm System. +thing-type.dscalarm.panel.channel.panel_ac_trouble.label = Panel AC Trouble +thing-type.dscalarm.panel.channel.panel_ac_trouble.description = Service AC Trouble Condition +thing-type.dscalarm.panel.channel.panel_aux_input_alarm.label = Panel Auxiliary Input Alarm +thing-type.dscalarm.panel.channel.panel_aux_input_alarm.description = Panel Auxiliary Input Alarm +thing-type.dscalarm.panel.channel.panel_aux_key_alarm.label = Panel Auxiliary Key Alarm +thing-type.dscalarm.panel.channel.panel_aux_key_alarm.description = Panel Auxiliary Key Alarm +thing-type.dscalarm.panel.channel.panel_command.label = Panel Command +thing-type.dscalarm.panel.channel.panel_command.description = Send Selected Command +thing-type.dscalarm.panel.channel.panel_fire_key_alarm.label = Panel Fire Key Alarm +thing-type.dscalarm.panel.channel.panel_fire_key_alarm.description = Panel Fire Key Alarm +thing-type.dscalarm.panel.channel.panel_ftc_trouble.label = Panel FTC Trouble +thing-type.dscalarm.panel.channel.panel_ftc_trouble.description = Service Fail to Communicate Trouble Condition +thing-type.dscalarm.panel.channel.panel_message.label = Panel Message +thing-type.dscalarm.panel.channel.panel_message.description = Message Received +thing-type.dscalarm.panel.channel.panel_panic_key_alarm.label = Panel Panic Key Alarm +thing-type.dscalarm.panel.channel.panel_panic_key_alarm.description = Panel Panic Key Alarm +thing-type.dscalarm.panel.channel.panel_service_required.label = Panel Service Required +thing-type.dscalarm.panel.channel.panel_service_required.description = Service Required Trouble Condition +thing-type.dscalarm.panel.channel.panel_system_error.label = Panel System Error +thing-type.dscalarm.panel.channel.panel_system_error.description = System Error +thing-type.dscalarm.panel.channel.panel_telephone_trouble.label = Panel Telephone Line Trouble +thing-type.dscalarm.panel.channel.panel_telephone_trouble.description = Service Telephone Line Trouble Condition +thing-type.dscalarm.panel.channel.panel_time.label = Panel Time +thing-type.dscalarm.panel.channel.panel_time.description = Panel Time +thing-type.dscalarm.panel.channel.panel_time_broadcast.label = Panel Time Broadcast +thing-type.dscalarm.panel.channel.panel_time_broadcast.description = Panel Time Broadcast +thing-type.dscalarm.panel.channel.panel_time_loss.label = Panel Time Loss +thing-type.dscalarm.panel.channel.panel_time_loss.description = Service Time Loss Trouble Condition +thing-type.dscalarm.panel.channel.panel_time_stamp.label = Panel Time Stamp +thing-type.dscalarm.panel.channel.panel_time_stamp.description = Panel Time Stamp +thing-type.dscalarm.panel.channel.panel_trouble_led.label = Panel Trouble LED +thing-type.dscalarm.panel.channel.panel_trouble_led.description = Trouble LED State +thing-type.dscalarm.panel.channel.panel_trouble_message.label = Panel Trouble Message +thing-type.dscalarm.panel.channel.panel_trouble_message.description = Trouble Message +thing-type.dscalarm.panel.channel.panel_zone_fault.label = Panel Zone Fault +thing-type.dscalarm.panel.channel.panel_zone_fault.description = Service Zone Fault Trouble Condition +thing-type.dscalarm.panel.channel.panel_zone_low_battery.label = Panel Zone Low Battery +thing-type.dscalarm.panel.channel.panel_zone_low_battery.description = Service Zone Low Battery Trouble Condition +thing-type.dscalarm.panel.channel.panel_zone_tamper.label = Panel Zone Tamper +thing-type.dscalarm.panel.channel.panel_zone_tamper.description = Service Zone Tamper Trouble Condition +thing-type.dscalarm.partition.label = DSC Alarm Partition +thing-type.dscalarm.partition.description = Represents a controllable area within a DSC Alarm System. +thing-type.dscalarm.partition.channel.partition_arm_mode.label = Partition Arm Mode +thing-type.dscalarm.partition.channel.partition_arm_mode.description = Partition Arm Mode +thing-type.dscalarm.partition.channel.partition_armed.label = Partition Armed Status +thing-type.dscalarm.partition.channel.partition_armed.description = Partition Armed Status (ON=Armed, OFF=Disarmed) +thing-type.dscalarm.partition.channel.partition_entry_delay.label = Partition Entry Delay +thing-type.dscalarm.partition.channel.partition_entry_delay.description = Partition In Entry Delay Mode +thing-type.dscalarm.partition.channel.partition_exit_delay.label = Partition Exit Delay +thing-type.dscalarm.partition.channel.partition_exit_delay.description = Partition In Exit Delay Mode +thing-type.dscalarm.partition.channel.partition_in_alarm.label = Partition in Alarm +thing-type.dscalarm.partition.channel.partition_in_alarm.description = Partition In Alarm +thing-type.dscalarm.partition.channel.partition_opening_closing_mode.label = Partition Opening/Closing Mode +thing-type.dscalarm.partition.channel.partition_opening_closing_mode.description = Partition Opening/Closing Mode ("User Closing", "Special Closing", "Partial Closing", "User Opening", "Special Opening") +thing-type.dscalarm.partition.channel.partition_status.label = Partition Status +thing-type.dscalarm.partition.channel.partition_status.description = Partition Status +thing-type.dscalarm.tcpserver.label = TCP Server +thing-type.dscalarm.tcpserver.description = This bridge represents a TCP Server Ethernet interface. +thing-type.dscalarm.tcpserver.channel.bridge_reset.label = Reset TCP Server +thing-type.dscalarm.tcpserver.channel.bridge_reset.description = Resets the TCP Server +thing-type.dscalarm.tcpserver.channel.send_command.label = Send Command +thing-type.dscalarm.tcpserver.channel.send_command.description = Sends a DSC Alarm Command +thing-type.dscalarm.zone.label = DSC Alarm Zone +thing-type.dscalarm.zone.description = Represents a physical device such as a door, window, or motion sensor. +thing-type.dscalarm.zone.channel.zone_bypass_mode.label = Zone Bypass Mode +thing-type.dscalarm.zone.channel.zone_bypass_mode.description = Zone Bypass Mode (OFF=Armed, ON=Bypassed) +thing-type.dscalarm.zone.channel.zone_fault.label = Zone Fault +thing-type.dscalarm.zone.channel.zone_fault.description = Zone Fault +thing-type.dscalarm.zone.channel.zone_in_alarm.label = Zone in Alarm +thing-type.dscalarm.zone.channel.zone_in_alarm.description = Zone In Alarm +thing-type.dscalarm.zone.channel.zone_message.label = Zone Message +thing-type.dscalarm.zone.channel.zone_message.description = Zone Message +thing-type.dscalarm.zone.channel.zone_status.label = Zone Status +thing-type.dscalarm.zone.channel.zone_status.description = Zone Status (Open/Closed) +thing-type.dscalarm.zone.channel.zone_tamper.label = Zone Tamper +thing-type.dscalarm.zone.channel.zone_tamper.description = Zone Tamper +thing-type.dscalarm.zone.channel.zone_tripped.label = Zone Tripped +thing-type.dscalarm.zone.channel.zone_tripped.description = Zone Tripped + +# thing types config + +thing-type.config.dscalarm.envisalink.connectionTimeout.label = Connection Timeout +thing-type.config.dscalarm.envisalink.connectionTimeout.description = TCP Socket Connection Timeout (milliseconds). +thing-type.config.dscalarm.envisalink.ipAddress.label = IP Address +thing-type.config.dscalarm.envisalink.ipAddress.description = The IP address of the EyezOn Envlisalink 3/2D Ethernet interface. +thing-type.config.dscalarm.envisalink.password.label = Password +thing-type.config.dscalarm.envisalink.password.description = The Password to login to the EyezOn Envlisalink 3/2D Ethernet interface. +thing-type.config.dscalarm.envisalink.pollPeriod.label = Poll Period +thing-type.config.dscalarm.envisalink.pollPeriod.description = The Poll Period (minutes). +thing-type.config.dscalarm.envisalink.port.label = Port +thing-type.config.dscalarm.envisalink.port.description = The TCP port to the EyezOn Envlisalink 3/2D Ethernet interface. +thing-type.config.dscalarm.it100.baud.label = Baud Rate +thing-type.config.dscalarm.it100.baud.description = The baud rate of the DSC IT-100. Valid values are 9600 (default), 19200, 38400, 57600, and 115200. +thing-type.config.dscalarm.it100.pollPeriod.label = Poll Period +thing-type.config.dscalarm.it100.pollPeriod.description = The Poll Period. +thing-type.config.dscalarm.it100.serialPort.label = IT-100 Bridge Serial Port +thing-type.config.dscalarm.it100.serialPort.description = The serial port name for the DSC IT-100. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux. +thing-type.config.dscalarm.panel.suppressAcknowledgementMsgs.label = Suppress Acknowledgement Messages +thing-type.config.dscalarm.panel.suppressAcknowledgementMsgs.description = Suppress Acknowledgement Messages When Received. +thing-type.config.dscalarm.panel.userCode.label = User Code +thing-type.config.dscalarm.panel.userCode.description = The User Code. +thing-type.config.dscalarm.partition.partitionNumber.label = Partition Number +thing-type.config.dscalarm.partition.partitionNumber.description = The Partition Number (1-8). +thing-type.config.dscalarm.tcpserver.connectionTimeout.label = Connection Timeout +thing-type.config.dscalarm.tcpserver.connectionTimeout.description = TCP Socket Connection Timeout (milliseconds). +thing-type.config.dscalarm.tcpserver.ipAddress.label = IP Address +thing-type.config.dscalarm.tcpserver.ipAddress.description = The IP address of the TCP Server. +thing-type.config.dscalarm.tcpserver.pollPeriod.label = Poll Period +thing-type.config.dscalarm.tcpserver.pollPeriod.description = The Poll Period (minutes). +thing-type.config.dscalarm.tcpserver.port.label = Port +thing-type.config.dscalarm.tcpserver.port.description = The TCP port to the TCP Server. +thing-type.config.dscalarm.tcpserver.protocol.label = Protocol +thing-type.config.dscalarm.tcpserver.protocol.description = The protocol used to interact with the DSC Alarm. Valid options are 'IT100 API' and 'Envisalink TPI'. The default is 'IT100 API'. +thing-type.config.dscalarm.tcpserver.protocol.option.1 = IT100 API +thing-type.config.dscalarm.tcpserver.protocol.option.2 = Envisalink TPI +thing-type.config.dscalarm.zone.partitionNumber.label = Partition Number +thing-type.config.dscalarm.zone.partitionNumber.description = The Partition Number (1-8). +thing-type.config.dscalarm.zone.zoneNumber.label = Zone Number +thing-type.config.dscalarm.zone.zoneNumber.description = The Zone Number (1-64). + +# channel types + +channel-type.dscalarm.arm_mode.label = Arm Mode +channel-type.dscalarm.arm_mode.description = Arm Mode +channel-type.dscalarm.arm_mode.state.option.0 = Disarm +channel-type.dscalarm.arm_mode.state.option.1 = Away +channel-type.dscalarm.arm_mode.state.option.2 = Stay +channel-type.dscalarm.arm_mode.state.option.3 = Zero +channel-type.dscalarm.bypass_mode.label = Bypass Mode +channel-type.dscalarm.bypass_mode.description = Bypass Mode (OFF=Armed, ON=Bypassed) +channel-type.dscalarm.command.label = Send Command +channel-type.dscalarm.command.description = Sends a DSC Alarm Command +channel-type.dscalarm.led.label = Keypad LED +channel-type.dscalarm.led.description = Keypad LED (0=Off, 1=On, 2=Flashing) +channel-type.dscalarm.led.state.option.0 = Off +channel-type.dscalarm.led.state.option.1 = On +channel-type.dscalarm.led.state.option.2 = Flashing +channel-type.dscalarm.message.label = Message +channel-type.dscalarm.message.description = Message Received +channel-type.dscalarm.panel_command.label = Panel Command +channel-type.dscalarm.panel_command.description = Send Command +channel-type.dscalarm.panel_command.state.option.-1 = None +channel-type.dscalarm.panel_command.state.option.0 = Poll +channel-type.dscalarm.panel_command.state.option.1 = Status Report +channel-type.dscalarm.panel_command.state.option.2 = Labels Request (Serial Only) +channel-type.dscalarm.panel_command.state.option.8 = Dump Zone Timers (TCP Only) +channel-type.dscalarm.panel_command.state.option.10 = Set Time/Date +channel-type.dscalarm.panel_command.state.option.200 = Send User Code +channel-type.dscalarm.reset.label = Reset +channel-type.dscalarm.reset.description = Reset Switch +channel-type.dscalarm.state.label = State +channel-type.dscalarm.state.description = State (On/Off) +channel-type.dscalarm.status.label = Status +channel-type.dscalarm.status.description = Status +channel-type.dscalarm.time.label = Time +channel-type.dscalarm.time.description = Time +channel-type.dscalarm.zone_status.label = Zone Status +channel-type.dscalarm.zone_status.description = Zone Status (Open/Closed) diff --git a/bundles/org.openhab.binding.dwdpollenflug/src/main/resources/OH-INF/i18n/dwdpollenflug.properties b/bundles/org.openhab.binding.dwdpollenflug/src/main/resources/OH-INF/i18n/dwdpollenflug.properties new file mode 100644 index 0000000000000..f4e41c85f49c6 --- /dev/null +++ b/bundles/org.openhab.binding.dwdpollenflug/src/main/resources/OH-INF/i18n/dwdpollenflug.properties @@ -0,0 +1,79 @@ +# binding + +binding.dwdpollenflug.name = DWD Pollenflug Binding +binding.dwdpollenflug.description = This is the binding for DWD Pollenflug. + +# thing types + +thing-type.dwdpollenflug.bridge.label = DWD Pollen Count Index (Bridge) +thing-type.dwdpollenflug.bridge.description = Bridge for accessing pollen count index data of the DWD +thing-type.dwdpollenflug.region.label = DWD Pollen Count Index (Region) +thing-type.dwdpollenflug.region.description = Pollen count index for a region or partregion +thing-type.dwdpollenflug.region.group.alder.label = Alder +thing-type.dwdpollenflug.region.group.alder.description = Information for alder +thing-type.dwdpollenflug.region.group.ambrosia.label = Ambrosia +thing-type.dwdpollenflug.region.group.ambrosia.description = Information for ambrosia +thing-type.dwdpollenflug.region.group.ash.label = Ash tree +thing-type.dwdpollenflug.region.group.ash.description = Information for ash tree +thing-type.dwdpollenflug.region.group.birch.label = Birch +thing-type.dwdpollenflug.region.group.birch.description = Information for birch +thing-type.dwdpollenflug.region.group.grasses.label = Grasses +thing-type.dwdpollenflug.region.group.grasses.description = Information for grasses +thing-type.dwdpollenflug.region.group.hazel.label = Hazel +thing-type.dwdpollenflug.region.group.hazel.description = Information for hazel +thing-type.dwdpollenflug.region.group.mugwort.label = Mugwort +thing-type.dwdpollenflug.region.group.mugwort.description = Information for mugwort +thing-type.dwdpollenflug.region.group.rye.label = Rye +thing-type.dwdpollenflug.region.group.rye.description = Information for rye + +# thing types config + +thing-type.config.dwdpollenflug.bridge.refresh.label = Refresh Interval +thing-type.config.dwdpollenflug.bridge.refresh.description = Time between two API requests in minutes. Minimum 15 minutes. +thing-type.config.dwdpollenflug.region.regionID.label = Region +thing-type.config.dwdpollenflug.region.regionID.description = The partregion or region that should be reported. +thing-type.config.dwdpollenflug.region.regionID.option.11 = Inseln und Marschen +thing-type.config.dwdpollenflug.region.regionID.option.12 = Geest, Schleswig-Holstein und Hamburg +thing-type.config.dwdpollenflug.region.regionID.option.20 = Mecklenburg-Vorpommern +thing-type.config.dwdpollenflug.region.regionID.option.31 = Westl. Niedersachsen/Bremen +thing-type.config.dwdpollenflug.region.regionID.option.32 = Östl. Niedersachsen +thing-type.config.dwdpollenflug.region.regionID.option.41 = Rhein.-Westfäl. Tiefland +thing-type.config.dwdpollenflug.region.regionID.option.42 = Ostwestfalen +thing-type.config.dwdpollenflug.region.regionID.option.43 = Mittelgebirge NRW +thing-type.config.dwdpollenflug.region.regionID.option.50 = Brandenburg und Berlin +thing-type.config.dwdpollenflug.region.regionID.option.61 = Tiefland Sachsen-Anhalt +thing-type.config.dwdpollenflug.region.regionID.option.62 = Harz +thing-type.config.dwdpollenflug.region.regionID.option.71 = Tiefland Thüringen +thing-type.config.dwdpollenflug.region.regionID.option.72 = Mittelgebirge Thüringen +thing-type.config.dwdpollenflug.region.regionID.option.81 = Tiefland Sachsen +thing-type.config.dwdpollenflug.region.regionID.option.82 = Mittelgebirge Sachsen +thing-type.config.dwdpollenflug.region.regionID.option.91 = Nordhessen und hess. Mittelgebirge +thing-type.config.dwdpollenflug.region.regionID.option.92 = Rhein-Main +thing-type.config.dwdpollenflug.region.regionID.option.101 = Rhein, Pfalz, Nahe und Mosel +thing-type.config.dwdpollenflug.region.regionID.option.102 = Mittelgebirgsbereich Rheinland-Pfalz +thing-type.config.dwdpollenflug.region.regionID.option.103 = Saarland +thing-type.config.dwdpollenflug.region.regionID.option.111 = Oberrhein und unteres Neckartal +thing-type.config.dwdpollenflug.region.regionID.option.112 = Hohenlohe/mittlerer Neckar/Oberschwaben +thing-type.config.dwdpollenflug.region.regionID.option.113 = Mittelgebirge Baden-Württemberg +thing-type.config.dwdpollenflug.region.regionID.option.121 = Allgäu/Oberbayern/Bay. Wald +thing-type.config.dwdpollenflug.region.regionID.option.122 = Donauniederungen +thing-type.config.dwdpollenflug.region.regionID.option.123 = Bayern n. der Donau, o. Bayr. Wald, o. Mainfranken +thing-type.config.dwdpollenflug.region.regionID.option.124 = Mainfranken + +# channel group types + +channel-group-type.dwdpollenflug.pollentype.label = Pollen Type Group +channel-group-type.dwdpollenflug.pollentype.description = For each pollen type there are three channels for today, tomorrow and day after tomorrow +channel-group-type.dwdpollenflug.pollentype.channel.dayafter_to.label = Day After Tomorrow +channel-group-type.dwdpollenflug.pollentype.channel.today.label = Today +channel-group-type.dwdpollenflug.pollentype.channel.tomorrow.label = Tomorrow +channel-group-type.dwdpollenflug.updates.label = Updates +channel-group-type.dwdpollenflug.updates.description = Information about data state +channel-group-type.dwdpollenflug.updates.channel.last_update.label = Last Update From DWD +channel-group-type.dwdpollenflug.updates.channel.next_update.label = Next Update From DWD +channel-group-type.dwdpollenflug.updates.channel.refreshed.label = Bridge Refreshed + +# channel types + +channel-type.dwdpollenflug.pollencount.label = Pollen Count +channel-type.dwdpollenflug.update.label = Update Time diff --git a/bundles/org.openhab.binding.dwdunwetter/src/main/resources/OH-INF/i18n/dwdunwetter.properties b/bundles/org.openhab.binding.dwdunwetter/src/main/resources/OH-INF/i18n/dwdunwetter.properties new file mode 100644 index 0000000000000..fae0439068d86 --- /dev/null +++ b/bundles/org.openhab.binding.dwdunwetter/src/main/resources/OH-INF/i18n/dwdunwetter.properties @@ -0,0 +1,55 @@ +# binding + +binding.dwdunwetter.name = DWD Unwetter Binding +binding.dwdunwetter.description = This is the binding for DWD Unwetter. + +# thing types + +thing-type.dwdunwetter.dwdwarnings.label = Weather Warnings +thing-type.dwdunwetter.dwdwarnings.description = Weather Warnings for an area. + +# thing types config + +thing-type.config.dwdunwetter.dwdwarnings.cellId.label = Cell-ID +thing-type.config.dwdunwetter.dwdwarnings.cellId.description = ID of the area to retrieve weather warnings. For a list of valid IDs look at https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_warncellids_csv.csv. With the % sign at the end it is possible to query multiple cells at once. For example with 8111% are cells retrieved that starts with 8111. +thing-type.config.dwdunwetter.dwdwarnings.refresh.label = Refresh in Minutes +thing-type.config.dwdunwetter.dwdwarnings.refresh.description = Time between to API requests in minutes. Minimum 15 minutes. +thing-type.config.dwdunwetter.dwdwarnings.warningCount.label = Number of Provided Warnings +thing-type.config.dwdunwetter.dwdwarnings.warningCount.description = Number of warnings to provide. For each warning there will multiple channels. The warnings are sorted by severity first and begin second so the first warning is always the one with the highest severity. + +# channel types + +channel-type.dwdunwetter.altitude.label = Height (from) +channel-type.dwdunwetter.altitude.description = Lower Height above sea level for which the warning is valid. +channel-type.dwdunwetter.ceiling.label = Height (to) +channel-type.dwdunwetter.ceiling.description = Upper Height above sea level for which the warning is valid. +channel-type.dwdunwetter.description.label = Description +channel-type.dwdunwetter.description.description = Textual description of the warning. +channel-type.dwdunwetter.effective.label = Issued +channel-type.dwdunwetter.effective.description = Issued Date and Time. +channel-type.dwdunwetter.event.label = Type +channel-type.dwdunwetter.event.description = Type of the warning, e.g. FROST. +channel-type.dwdunwetter.expires.label = Valid To +channel-type.dwdunwetter.expires.description = End Date and Time for which the warning is valid. +channel-type.dwdunwetter.headline.label = Headline +channel-type.dwdunwetter.headline.description = Headline of the warning like "Amtliche Warnung vor FROST". +channel-type.dwdunwetter.instruction.label = Instruction +channel-type.dwdunwetter.instruction.description = Instructions and safety information. +channel-type.dwdunwetter.lastUpdated.label = Last Updated +channel-type.dwdunwetter.lastUpdated.description = Timestamp of the last update from the endpoint. +channel-type.dwdunwetter.onset.label = Valid From +channel-type.dwdunwetter.onset.description = Start Date and Time for which the warning is valid. +channel-type.dwdunwetter.severity.label = Severity +channel-type.dwdunwetter.severity.description = Severity of the warning. Possible values are Minor, Moderate, Severe and Extreme. +channel-type.dwdunwetter.severity.state.option.Minor = Minor +channel-type.dwdunwetter.severity.state.option.Moderate = Moderate +channel-type.dwdunwetter.severity.state.option.Severe = Severe +channel-type.dwdunwetter.severity.state.option.Extreme = Extreme +channel-type.dwdunwetter.updated.label = Updated +channel-type.dwdunwetter.updated.description = Triggers NEW if a warning is send the first time. This happens after all other channels are populated. +channel-type.dwdunwetter.urgency.label = Urgency +channel-type.dwdunwetter.urgency.description = Urgency of the warning. Possible values are Immediate and Future. +channel-type.dwdunwetter.urgency.state.option.Immediate = Immediate +channel-type.dwdunwetter.urgency.state.option.Future = Future +channel-type.dwdunwetter.warning.label = Warning +channel-type.dwdunwetter.warning.description = ON if a warning is present, OFF else. While be switched to ON only after all other channels - except the trigger channel - are updated. Will be switched to OFF before all other channels are updated to UNDEF. diff --git a/bundles/org.openhab.binding.ecobee/src/main/resources/OH-INF/i18n/ecobee.properties b/bundles/org.openhab.binding.ecobee/src/main/resources/OH-INF/i18n/ecobee.properties new file mode 100644 index 0000000000000..96c6dcf0e0680 --- /dev/null +++ b/bundles/org.openhab.binding.ecobee/src/main/resources/OH-INF/i18n/ecobee.properties @@ -0,0 +1,327 @@ +# binding + +binding.ecobee.name = Ecobee Binding +binding.ecobee.description = This is the binding for Ecobee smart thermostats. + +# thing types + +thing-type.ecobee.account.label = Ecobee Account +thing-type.ecobee.account.description = Represents an account at Ecobee +thing-type.ecobee.sensor.label = Ecobee Remote Sensor +thing-type.ecobee.sensor.description = An Ecobee remote sensor +thing-type.ecobee.thermostat.label = Ecobee Thermostat +thing-type.ecobee.thermostat.description = An Ecobee thermostat +thing-type.ecobee.thermostat.group.alerts.label = Alert +thing-type.ecobee.thermostat.group.equipmentStatus.label = Equipment Status +thing-type.ecobee.thermostat.group.events.label = Running Event +thing-type.ecobee.thermostat.group.forecast0.label = Weather Forecast Today +thing-type.ecobee.thermostat.group.forecast1.label = Weather Forecast Tomorrow +thing-type.ecobee.thermostat.group.forecast2.label = Weather Forecast Day 2 +thing-type.ecobee.thermostat.group.forecast3.label = Weather Forecast Day 3 +thing-type.ecobee.thermostat.group.forecast4.label = Weather Forecast Day 4 +thing-type.ecobee.thermostat.group.forecast5.label = Weather Forecast Day 5 +thing-type.ecobee.thermostat.group.forecast6.label = Weather Forecast Day 6 +thing-type.ecobee.thermostat.group.forecast7.label = Weather Forecast Day 7 +thing-type.ecobee.thermostat.group.forecast8.label = Weather Forecast Day 8 +thing-type.ecobee.thermostat.group.houseDetails.label = House Details +thing-type.ecobee.thermostat.group.info.label = Thermostat Info +thing-type.ecobee.thermostat.group.location.label = Location +thing-type.ecobee.thermostat.group.management.label = Management +thing-type.ecobee.thermostat.group.program.label = Program +thing-type.ecobee.thermostat.group.runtime.label = Runtime +thing-type.ecobee.thermostat.group.settings.label = Settings +thing-type.ecobee.thermostat.group.technician.label = Technician +thing-type.ecobee.thermostat.group.version.label = Version +thing-type.ecobee.thermostat.group.weather.label = Weather Station + +# thing types config + +thing-type.config.ecobee.account.apiKey.label = API Key +thing-type.config.ecobee.account.apiKey.description = Enter the API key +thing-type.config.ecobee.account.apiTimeout.label = API Timeout +thing-type.config.ecobee.account.apiTimeout.description = Time in seconds to allow API request to complete +thing-type.config.ecobee.account.discoveryEnabled.label = Discovery Enabled +thing-type.config.ecobee.account.discoveryEnabled.description = Enable/disable automatic discovery +thing-type.config.ecobee.account.refreshIntervalNormal.label = Refresh Interval (Normal) +thing-type.config.ecobee.account.refreshIntervalNormal.description = Specifies the refresh interval in seconds +thing-type.config.ecobee.account.refreshIntervalQuick.label = Refresh Interval (Quick) +thing-type.config.ecobee.account.refreshIntervalQuick.description = Specifies time in seconds to wait after successful update, command or action before refresh +thing-type.config.ecobee.sensor.sensorId.label = Sensor Id +thing-type.config.ecobee.sensor.sensorId.description = Id assigned to this sensor (e.g. rs:101) +thing-type.config.ecobee.thermostat.thermostatId.label = Thermostat ID +thing-type.config.ecobee.thermostat.thermostatId.description = Thermostat ID assigned to this thermostat by Ecobee + +# channel group types + +channel-group-type.ecobee.alerts.label = First Alert in Alert List +channel-group-type.ecobee.equipmentStatus.label = Equipment Status +channel-group-type.ecobee.events.label = Currently Running Event +channel-group-type.ecobee.forecast.label = Weather Forecast +channel-group-type.ecobee.houseDetails.label = Thermostat House Detail +channel-group-type.ecobee.info.label = Thermostat Info +channel-group-type.ecobee.location.label = Thermostat Location +channel-group-type.ecobee.management.label = Thermostat Management +channel-group-type.ecobee.program.label = Thermostat Program +channel-group-type.ecobee.runtime.label = Thermostat Runtime +channel-group-type.ecobee.settings.label = Thermostat Settings +channel-group-type.ecobee.technician.label = Thermostat Technician +channel-group-type.ecobee.version.label = Thermostat Version +channel-group-type.ecobee.weather.label = Weather + +# channel types + +channel-type.ecobee.actualHumidity.label = Actual Humidity +channel-type.ecobee.actualTemperature.label = Actual Temperature +channel-type.ecobee.alertAcknowledgeRef.label = Acknowledge Ref +channel-type.ecobee.alertAcknowledgement.label = Acknowledgement +channel-type.ecobee.alertDate.label = Date +channel-type.ecobee.alertIsOperatorAlert.label = Is Operator Alert +channel-type.ecobee.alertNotificationType.label = Notification Type +channel-type.ecobee.alertNumber.label = Number +channel-type.ecobee.alertRemindMeLater.label = Remind Me Later +channel-type.ecobee.alertReminder.label = Reminder +channel-type.ecobee.alertSendEmail.label = Send Email +channel-type.ecobee.alertSeverity.label = Severity +channel-type.ecobee.alertShowIdt.label = Show IDT +channel-type.ecobee.alertShowWeb.label = Show Web +channel-type.ecobee.alertText.label = Text +channel-type.ecobee.alertThermostatIdentifier.label = Thermostat Identifier +channel-type.ecobee.alertTime.label = Time +channel-type.ecobee.alertType.label = Type +channel-type.ecobee.autoAway.label = Auto Away +channel-type.ecobee.autoHeatCoolFeatureEnabled.label = Auto Heat Cool Feature Enabled +channel-type.ecobee.auxMaxOutdoorTemp.label = Aux Max Outdoor Temp +channel-type.ecobee.auxOutdoorTempAlert.label = Aux Outdoor Temp Alert +channel-type.ecobee.auxOutdoorTempAlertNotify.label = Aux Outdoor Temp Alert Notify +channel-type.ecobee.auxOutdoorTempAlertNotifyTechnician.label = Aux Outdoor Temp Alert Notify Technician +channel-type.ecobee.auxRuntimeAlert.label = Aux Runtime Alert +channel-type.ecobee.auxRuntimeAlertNotify.label = Aux Runtime Alert Notify +channel-type.ecobee.auxRuntimeAlertNotifyTechnician.label = Aux Runtime Alert Notify Technician +channel-type.ecobee.backlightOffDuringSleep.label = Backlight Off During Sleep +channel-type.ecobee.backlightOffTime.label = Backlight Off Time +channel-type.ecobee.backlightOnIntensity.label = Backlight On Intensity +channel-type.ecobee.backlightSleepIntensity.label = Backlight Sleep Intensity +channel-type.ecobee.brand.label = Brand +channel-type.ecobee.coldTempAlert.label = Cold Temp Alert +channel-type.ecobee.coldTempAlertEnabled.label = Cold Temp Alert Enabled +channel-type.ecobee.compressorProtectionMinTemp.label = Compressor Protection Min Temp +channel-type.ecobee.compressorProtectionMinTime.label = Compressor Protection Min Time +channel-type.ecobee.condensationAvoid.label = Condensation Avoid +channel-type.ecobee.connectDateTime.label = Connected Date Time +channel-type.ecobee.connected.label = Connected +channel-type.ecobee.coolMaxTemp.label = Cool Max Temp +channel-type.ecobee.coolMinTemp.label = Cool Min Temp +channel-type.ecobee.coolRangeHigh.label = Cool Range High +channel-type.ecobee.coolRangeLow.label = Cool Range Low +channel-type.ecobee.coolStages.label = Cool Stages +channel-type.ecobee.coolingLockout.label = Cooling Lockout +channel-type.ecobee.currentClimateRef.label = Current Climate Ref +channel-type.ecobee.dehumidifierLevel.label = Dehumidifier Level +channel-type.ecobee.dehumidifierMode.label = Dehumidifier Mode +channel-type.ecobee.dehumidifyOvercoolOffset.label = Dehumidify Overcool Effect +channel-type.ecobee.dehumidifyWhenHeating.label = Dehumidify When Heating +channel-type.ecobee.dehumidifyWithAC.label = Dehumidify With AC +channel-type.ecobee.desiredCool.label = Desired Cool +channel-type.ecobee.desiredCoolRangeHigh.label = Desired Cool Range High +channel-type.ecobee.desiredCoolRangeLow.label = Desired Cool Range Low +channel-type.ecobee.desiredDehumidity.label = Desired Dehumidity +channel-type.ecobee.desiredFanMode.label = Desired Fan Mode +channel-type.ecobee.desiredHeat.label = Desired Heat +channel-type.ecobee.desiredHeatRangeHigh.label = Desired Heat Range High +channel-type.ecobee.desiredHeatRangeLow.label = Desired Heat Range Low +channel-type.ecobee.desiredHumidity.label = Desired Humidity +channel-type.ecobee.disableAlertsOnIdt.label = Disable Alerts On IDT +channel-type.ecobee.disableHeatPumpAlerts.label = Disable Heat Pump Alerts +channel-type.ecobee.disablePreCooling.label = Disable Pre Cooling +channel-type.ecobee.disablePreHeating.label = Disable Pre Heating +channel-type.ecobee.disconnectDateTime.label = Disconnected Date Timee +channel-type.ecobee.drAccept.label = DR Accept +channel-type.ecobee.eiLocation.label = EI Location +channel-type.ecobee.electricityBillCycleMonths.label = Electricity Bill Cycle Months +channel-type.ecobee.electricityBillStartMonth.label = Electricity Bill Start Month +channel-type.ecobee.electricityBillingDayOfMonth.label = Electricity Billing Day Of Month +channel-type.ecobee.enableElectricityBillAlert.label = Enable Electricity Bill Alert +channel-type.ecobee.enableProjectedElectricityBillAlert.label = Enable Projected Electricity Bill Alert +channel-type.ecobee.equipmentStatus.label = Equipment Status +channel-type.ecobee.eventCoolHoldTemp.label = Cool Hold Temp +channel-type.ecobee.eventCoolRelativeTemp.label = Cool Relative Temp +channel-type.ecobee.eventDrRampUpTemp.label = DR Ramp Up Temp +channel-type.ecobee.eventDrRampUpTime.label = DR Ramp Up Time +channel-type.ecobee.eventDutyCyclePercentage.label = Duty Cycle Percentage +channel-type.ecobee.eventEndDate.label = Event End Date +channel-type.ecobee.eventEndTime.label = Event End Time +channel-type.ecobee.eventFan.label = Fan +channel-type.ecobee.eventFanMinOnTime.label = Fan Min On Time +channel-type.ecobee.eventHeatHoldTemp.label = Heat Hold Temp +channel-type.ecobee.eventHeatRelativeTemp.label = Heat Relative Temp +channel-type.ecobee.eventHoldClimateRef.label = Hold Climate Ref +channel-type.ecobee.eventIsCoolOff.label = Is Cool Off +channel-type.ecobee.eventIsHeatOff.label = Is Heat Off +channel-type.ecobee.eventIsOccupied.label = Is Occupied +channel-type.ecobee.eventIsOptional.label = Is Optional +channel-type.ecobee.eventIsTemperatureAbsolute.label = Is Temperature Absolute +channel-type.ecobee.eventIsTemperatureRelative.label = Is Temperature Relative +channel-type.ecobee.eventLinkRef.label = Link Ref +channel-type.ecobee.eventName.label = Event Name +channel-type.ecobee.eventOccupiedSensorActive.label = Occupied Sensor Active +channel-type.ecobee.eventRunning.label = Event is Running +channel-type.ecobee.eventStartDate.label = Event Start Date +channel-type.ecobee.eventStartTime.label = Event Start Time +channel-type.ecobee.eventType.label = Event Type +channel-type.ecobee.eventUnoccupiedSensorActive.label = Unoccupied Sensor Active +channel-type.ecobee.eventVent.label = Vent +channel-type.ecobee.eventVentilatorMinOnTime.label = Ventilator Min On Time +channel-type.ecobee.fanControlRequired.label = Fan Control Required +channel-type.ecobee.fanMinOnTime.label = Fan Min On Time +channel-type.ecobee.features.label = Features +channel-type.ecobee.firstConnected.label = First Connected +channel-type.ecobee.followMeComfort.label = Follow Me Comfort +channel-type.ecobee.groupName.label = Group Name +channel-type.ecobee.groupRef.label = Group Ref +channel-type.ecobee.groupSetting.label = Group Setting +channel-type.ecobee.hasBoiler.label = Has Boiler +channel-type.ecobee.hasDehumidifier.label = Has Dehumidifier +channel-type.ecobee.hasElectric.label = Has Electric +channel-type.ecobee.hasErv.label = Has ERV +channel-type.ecobee.hasForcedAir.label = Has Forced Air +channel-type.ecobee.hasHeatPump.label = Has Heat Pump +channel-type.ecobee.hasHrv.label = Has HRV +channel-type.ecobee.hasHumidifier.label = Has Humidifier +channel-type.ecobee.hasUVFilter.label = Has UV Filter +channel-type.ecobee.heatCoolMinDelta.label = Heat Cool Min Delta +channel-type.ecobee.heatMaxTemp.label = Heat Max Temp +channel-type.ecobee.heatMinTemp.label = Heat Min Temp +channel-type.ecobee.heatPumpGroundWater.label = Heat Pump Ground Water +channel-type.ecobee.heatPumpReversalOnCool.label = Heat Pump Reversal On Cool +channel-type.ecobee.heatRangeHigh.label = Heat Range High +channel-type.ecobee.heatRangeLow.label = Heat Range Low +channel-type.ecobee.heatStages.label = Heat Stages +channel-type.ecobee.holdAction.label = Hold Action +channel-type.ecobee.hotTempAlert.label = Hot Temp Alert +channel-type.ecobee.hotTempAlertEnabled.label = Hot Temp Alert Enabled +channel-type.ecobee.housedetailsAge.label = Age +channel-type.ecobee.housedetailsNumberOfFloors.label = Number of Floors +channel-type.ecobee.housedetailsNumberOfOccupants.label = Number of Occupants +channel-type.ecobee.housedetailsNumberOfRooms.label = Number of Rooms +channel-type.ecobee.housedetailsSize.label = Size +channel-type.ecobee.housedetailsStyle.label = Style +channel-type.ecobee.housedetailsWindowEfficiency.label = Window Efficiency +channel-type.ecobee.humidifierMode.label = Humidifier Mode +channel-type.ecobee.humidity.label = Humidity +channel-type.ecobee.humidityAlertNotify.label = Humidity Alert Notify +channel-type.ecobee.humidityAlertNotifyTechnician.label = Humidity Alert Notify Technician +channel-type.ecobee.humidityHighAlert.label = Humidity High Alert +channel-type.ecobee.humidityLowAlert.label = Humidity Low Alert +channel-type.ecobee.hvacMode.label = HVAC Mode +channel-type.ecobee.identifier.label = Identifier +channel-type.ecobee.installerCodeRequired.label = Installer Code Required +channel-type.ecobee.isRegistered.label = Is Registered +channel-type.ecobee.isRentalProperty.label = Is Rental Property +channel-type.ecobee.isVentilatorTimerOn.label = Is Ventilator Timer On +channel-type.ecobee.lastModified.label = Last Modified +channel-type.ecobee.lastModified.label = Last Modified +channel-type.ecobee.lastServiceDate.label = Last Service Date +channel-type.ecobee.lastStatusModified.label = Last Status Modified +channel-type.ecobee.locale.label = Locale +channel-type.ecobee.locationCity.label = City +channel-type.ecobee.locationCountry.label = Country +channel-type.ecobee.locationIsDaylightSaving.label = Is Daylight Saving +channel-type.ecobee.locationMapCoordinates.label = Thermostat Location +channel-type.ecobee.locationPhoneNumber.label = Phone Number +channel-type.ecobee.locationPostalCode.label = Postal Code +channel-type.ecobee.locationProvinceState.label = Province/State +channel-type.ecobee.locationStreetAddress.label = Street Address +channel-type.ecobee.locationTimeZone.label = Time Zone +channel-type.ecobee.locationTimeZoneOffsetMinutes.label = Time Zone Offset Minutes +channel-type.ecobee.managementAdministrativeContact.label = Administrative Contact +channel-type.ecobee.managementBillingContact.label = Billing Contact +channel-type.ecobee.managementEmail.label = Email +channel-type.ecobee.managementName.label = Name +channel-type.ecobee.managementPhone.label = Phone +channel-type.ecobee.managementShowAlertIdt.label = Show Alert Idt +channel-type.ecobee.managementShowAlertWeb.label = Show Alert Web +channel-type.ecobee.managementWeb.label = Web +channel-type.ecobee.maxSetBack.label = Max Set Back +channel-type.ecobee.maxSetForward.label = Max Set Forward +channel-type.ecobee.modelNumber.label = Model Number +channel-type.ecobee.monthlyElectricityBillLimit.label = Monthly Electricity Bill Limit +channel-type.ecobee.monthsBetweenService.label = Months Between Service +channel-type.ecobee.name.label = Name +channel-type.ecobee.quickSaveSetBack.label = Quick Save Set Back +channel-type.ecobee.quickSaveSetForward.label = Quick Save Set Forward +channel-type.ecobee.randomStartDelayCool.label = Random Start Delay Cool +channel-type.ecobee.randomStartDelayHeat.label = Random Start Delay Heat +channel-type.ecobee.rawTemperature.label = Raw Temperature +channel-type.ecobee.remindMeDate.label = Remind Me Date +channel-type.ecobee.runtimeDate.label = Runtime Date +channel-type.ecobee.runtimeInterval.label = Runtime Interval +channel-type.ecobee.runtimeRev.label = Runtime Rev +channel-type.ecobee.sensorCode.label = Sensor Code +channel-type.ecobee.sensorGeneric.label = Generic Sensor +channel-type.ecobee.sensorHumidity.label = Sensor Humidity +channel-type.ecobee.sensorId.label = Sensor Id +channel-type.ecobee.sensorInUse.label = Sensor In Use +channel-type.ecobee.sensorName.label = Sensor Name +channel-type.ecobee.sensorOccupancy.label = Sensor Occupancy +channel-type.ecobee.sensorTemperature.label = Sensor Temperature +channel-type.ecobee.sensorType.label = Sensor Type +channel-type.ecobee.serviceRemindMe.label = Service Remind Me +channel-type.ecobee.serviceRemindTechnician.label = Service Remind Technician +channel-type.ecobee.showIconMode.label = Show Icon Mode +channel-type.ecobee.smartCirculation.label = Smart Circulation +channel-type.ecobee.soundAlertVolume.label = Sound Alert Volume +channel-type.ecobee.soundTickVolume.label = Sound Tick Volume +channel-type.ecobee.stage1CoolingDifferentialTemp.label = Stage 1 Cooling Differential Temp +channel-type.ecobee.stage1CoolingDissipationTime.label = Stage 1 Cooling Dissipation Time +channel-type.ecobee.stage1HeatingDifferentialTemp.label = Stage 1 Heating Differential Temp +channel-type.ecobee.stage1HeatingDissipationTime.label = Stage 1 Heating Dissipation Time +channel-type.ecobee.technicianCity.label = City +channel-type.ecobee.technicianContractorRef.label = Contractor Ref +channel-type.ecobee.technicianCountry.label = Country +channel-type.ecobee.technicianEmail.label = Email +channel-type.ecobee.technicianName.label = Name +channel-type.ecobee.technicianPhone.label = Phone +channel-type.ecobee.technicianPostalCode.label = Postal Code +channel-type.ecobee.technicianProvinceState.label = Province/State +channel-type.ecobee.technicianStreetAddress.label = Street Address +channel-type.ecobee.technicianWeb.label = Web +channel-type.ecobee.tempAlertNotify.label = Temp Alert Notify +channel-type.ecobee.tempAlertNotifyTechnician.label = Temp Alert Notify Technician +channel-type.ecobee.tempCorrection.label = Temp Correction +channel-type.ecobee.thermostatRev.label = Thermostat Rev +channel-type.ecobee.thermostatTime.label = Thermostat Time +channel-type.ecobee.useCelsius.label = Use Celsius +channel-type.ecobee.useTimeFormat12.label = Use Time Format 12 +channel-type.ecobee.useZoneController.label = Use Zone Controller +channel-type.ecobee.userAccessCode.label = User Access Code +channel-type.ecobee.userAccessSetting.label = User Access Settings +channel-type.ecobee.vent.label = Vent +channel-type.ecobee.ventilatorDehumidify.label = Ventilator Dehumidify +channel-type.ecobee.ventilatorFreeCooling.label = Ventilator Free Cooling +channel-type.ecobee.ventilatorMinOnTime.label = Ventilator Min On Time +channel-type.ecobee.ventilatorMinOnTimeAway.label = Ventilator Min On Time Away +channel-type.ecobee.ventilatorMinOnTimeHome.label = Ventilator Min On Time Home +channel-type.ecobee.ventilatorOffDateTime.label = Ventilator Off Date Time +channel-type.ecobee.ventilatorType.label = Ventilator Type +channel-type.ecobee.versionThermostatFirmwareVersion.label = Firmware Version +channel-type.ecobee.weatherCondition.label = Condition +channel-type.ecobee.weatherDateTime.label = Date Time +channel-type.ecobee.weatherDewpoint.label = Dewpoint +channel-type.ecobee.weatherPop.label = Probability of Precipitation +channel-type.ecobee.weatherPressure.label = Pressure +channel-type.ecobee.weatherRelativeHumidity.label = Relative Humidity +channel-type.ecobee.weatherSky.label = Sky +channel-type.ecobee.weatherSkyText.label = Sky Text +channel-type.ecobee.weatherTempHigh.label = High Temperature +channel-type.ecobee.weatherTempLow.label = Low Temperature +channel-type.ecobee.weatherTemperature.label = Temperature +channel-type.ecobee.weatherTimestamp.label = Timestamp +channel-type.ecobee.weatherVisibility.label = Visibility +channel-type.ecobee.weatherWeatherStation.label = Weather Station +channel-type.ecobee.weatherWeatherSymbol.label = Symbol +channel-type.ecobee.weatherWeatherSymbolText.label = Symbol Text +channel-type.ecobee.weatherWindBearing.label = Wind Bearing +channel-type.ecobee.weatherWindDirection.label = Wind Direction +channel-type.ecobee.weatherWindGust.label = Wind Gust +channel-type.ecobee.weatherWindSpeed.label = Wind Speed +channel-type.ecobee.wifiOfflineAlert.label = WiFi Offline Alert diff --git a/bundles/org.openhab.binding.ecotouch/src/main/resources/OH-INF/i18n/ecotouch.properties b/bundles/org.openhab.binding.ecotouch/src/main/resources/OH-INF/i18n/ecotouch.properties new file mode 100644 index 0000000000000..24d3c3b96affe --- /dev/null +++ b/bundles/org.openhab.binding.ecotouch/src/main/resources/OH-INF/i18n/ecotouch.properties @@ -0,0 +1,188 @@ +# binding + +binding.ecotouch.name = EcoTouch Binding +binding.ecotouch.description = This is the binding for a Waterkotte EcoTouch heat pump. + +# thing types + +thing-type.ecotouch.air.label = Waterkotte EcoTouch Air +thing-type.ecotouch.air.description = Waterkotte EcoTouch Air heat pump +thing-type.ecotouch.geo.label = Waterkotte EcoTouch Geo +thing-type.ecotouch.geo.description = Waterkotte EcoTouch Geo heat pump + +# thing types config + +thing-type.config.ecotouch.air.ip.label = Address of Heat Pump +thing-type.config.ecotouch.air.ip.description = Enter the IP address or the hostname of the EcoTouch display unit +thing-type.config.ecotouch.air.password.label = Password +thing-type.config.ecotouch.air.password.description = Since Waterkotte Display software version 1.6.xx, the password default value is waterkotte. Prior to that, the password default was wtkadmin +thing-type.config.ecotouch.air.refresh.label = Refresh Interval +thing-type.config.ecotouch.air.refresh.description = This is the refresh interval in seconds for all channels. +thing-type.config.ecotouch.air.username.label = Username +thing-type.config.ecotouch.air.username.description = Since Waterkotte Display software version 1.6.xx, the username default value is waterkotte. Prior to that, the username default was admin +thing-type.config.ecotouch.geo.ip.label = Address of Heat Pump +thing-type.config.ecotouch.geo.ip.description = Enter the IP address or the hostname of the EcoTouch display unit +thing-type.config.ecotouch.geo.password.label = Password +thing-type.config.ecotouch.geo.password.description = Since Waterkotte Display software version 1.6.xx, the password default value is waterkotte. Prior to that, the password default was wtkadmin +thing-type.config.ecotouch.geo.refresh.label = Refresh Interval +thing-type.config.ecotouch.geo.refresh.description = This is the refresh interval in seconds for all channels. +thing-type.config.ecotouch.geo.username.label = Username +thing-type.config.ecotouch.geo.username.description = Since Waterkotte Display software version 1.6.xx, the username default value is waterkotte. Prior to that, the username default was admin + +# channel types + +channel-type.ecotouch.adapt_heating.label = Adapt Heating +channel-type.ecotouch.adapt_heating.description = Adjust the Heating Temperature by an Offset +channel-type.ecotouch.alarm.label = Alarm +channel-type.ecotouch.compressor_power.label = Percent Power Compressor +channel-type.ecotouch.coolEnableTemp.label = Temperature Cooling Enable +channel-type.ecotouch.cop_cooling.label = COP Cooling +channel-type.ecotouch.cop_heating.label = COP Heating +channel-type.ecotouch.date_day.label = Day +channel-type.ecotouch.date_month.label = Month +channel-type.ecotouch.date_year.label = Year +channel-type.ecotouch.ecovent_CO2_value.label = EcoVent CO2 +channel-type.ecotouch.ecovent_mode.label = EcoVent Mode +channel-type.ecotouch.ecovent_mode.description = EcoVent Mode (0..5: Day, Night, Timer, Party, Vacation, Bypass) +channel-type.ecotouch.ecovent_moisture_value.label = EcoVent Air Moisture +channel-type.ecotouch.ecovent_output_y1.label = EcoVent Fan +channel-type.ecotouch.ecovent_temp_exhaust_air.label = EcoVent Exhaust Air +channel-type.ecotouch.ecovent_temp_exhaust_air.description = EcoVent Temperature Exhaust Air +channel-type.ecotouch.ecovent_temp_exit_air.label = EcoVent Exit Air +channel-type.ecotouch.ecovent_temp_exit_air.description = EcoVent Temperature Exit Air +channel-type.ecotouch.ecovent_temp_outdoor_air.label = EcoVent Outdoor Air +channel-type.ecotouch.ecovent_temp_outdoor_air.description = EcoVent Temperature Outdoor Air +channel-type.ecotouch.ecovent_temp_supply_air.label = EcoVent Supply Air +channel-type.ecotouch.ecovent_temp_supply_air.description = EcoVent Temperature Supply Air +channel-type.ecotouch.enable_cooling.label = Enable Cooling +channel-type.ecotouch.enable_heating.label = Enable Heating +channel-type.ecotouch.enable_pool.label = Enable Pool +channel-type.ecotouch.enable_pv.label = Enable PV +channel-type.ecotouch.enable_warmwater.label = Enable Water +channel-type.ecotouch.enable_warmwater.description = Enable Warm Water +channel-type.ecotouch.hysteresis_heating.label = Hysteresis Heating +channel-type.ecotouch.interruptions.label = Interruptions +channel-type.ecotouch.manual_4wayvalve.label = Enable 4Way Valve +channel-type.ecotouch.manual_4wayvalve.description = Operating Mode 4Way Valve +channel-type.ecotouch.manual_coolvalve.label = Enable Cooling Valve +channel-type.ecotouch.manual_coolvalve.description = Operating Mode Cooling Valve +channel-type.ecotouch.manual_heatingpump.label = Enable Heating Pump +channel-type.ecotouch.manual_heatingpump.description = Operating Mode Heating Pump +channel-type.ecotouch.manual_multiext.label = Enable Multi Ouput +channel-type.ecotouch.manual_multiext.description = Operating Mode Multi Ouput Ext +channel-type.ecotouch.manual_poolvalve.label = Enable Pool Valve +channel-type.ecotouch.manual_poolvalve.description = Operating Mode Pool Valve +channel-type.ecotouch.manual_solarpump1.label = Enable Solar Pump +channel-type.ecotouch.manual_solarpump1.description = Operating Mode Solar Pump +channel-type.ecotouch.manual_solarpump2.label = Enable Solar Pump 2 +channel-type.ecotouch.manual_solarpump2.description = Operating Mode Solar Pump 2 +channel-type.ecotouch.manual_sourcepump.label = Enable Source Pump +channel-type.ecotouch.manual_sourcepump.description = Operating Mode Source Pump +channel-type.ecotouch.manual_tankpump.label = Enable Tank Pump +channel-type.ecotouch.manual_tankpump.description = Operating Mode Tank Pump +channel-type.ecotouch.manual_valve.label = Enable Valve +channel-type.ecotouch.manual_valve.description = Operating Mode Valve +channel-type.ecotouch.maxVLTemp.label = maxVLTemp +channel-type.ecotouch.nviHeizkreisNorm.label = nviHeizkreisNorm +channel-type.ecotouch.nviNormAussen.label = nviNormAussen +channel-type.ecotouch.nviSollKuehlen.label = nviSollKuehlen +channel-type.ecotouch.nviTHeizgrenze.label = nviTHeizgrenze +channel-type.ecotouch.nviTHeizgrenzeSoll.label = nviTHeizgrenze Setpoint +channel-type.ecotouch.operating_hours_circulation_pump.label = Hours Circulation Pump +channel-type.ecotouch.operating_hours_circulation_pump.description = Operating Hours Circulation Pump +channel-type.ecotouch.operating_hours_compressor1.label = Hours Compressor 1 +channel-type.ecotouch.operating_hours_compressor1.description = Operating Hours Compressor 1 +channel-type.ecotouch.operating_hours_compressor2.label = Hours Compressor 2 +channel-type.ecotouch.operating_hours_compressor2.description = Operating Hours Compressor 2 +channel-type.ecotouch.operating_hours_solar.label = Hours Solar +channel-type.ecotouch.operating_hours_solar.description = Operating Hours Solar +channel-type.ecotouch.operating_hours_source_pump.label = Hours Source Pump +channel-type.ecotouch.operating_hours_source_pump.description = Operating Hours Source Pump +channel-type.ecotouch.percent_compressor.label = Percent Compressor +channel-type.ecotouch.percent_heat_circ_pump.label = Percent Circulation Pump +channel-type.ecotouch.percent_heat_circ_pump.description = Percent Heating Circulation Pump +channel-type.ecotouch.percent_source_pump.label = Percent Source Pump +channel-type.ecotouch.position_expansion_valve.label = Position Expansion Valve +channel-type.ecotouch.power_compressor.label = Power Compressor +channel-type.ecotouch.power_cooling.label = Power Cooling +channel-type.ecotouch.power_heating.label = Power Heating +channel-type.ecotouch.pressure_condensation.label = Pressure Condensation +channel-type.ecotouch.pressure_evaporation.label = Pressure Evaporation +channel-type.ecotouch.state.label = State +channel-type.ecotouch.state.description = A Bitfield which encodes the state of all valves, pumps and compressors +channel-type.ecotouch.state_alarm.label = State Alarm +channel-type.ecotouch.state_compressor1.label = State Compressor 1 +channel-type.ecotouch.state_compressor2.label = State Compressor 2 +channel-type.ecotouch.state_cooling.label = State Cooling +channel-type.ecotouch.state_cooling4way.label = State Cooling4Way +channel-type.ecotouch.state_evd.label = State EVD +channel-type.ecotouch.state_extheater.label = State External Heater +channel-type.ecotouch.state_heatingpump.label = State Heating Pump +channel-type.ecotouch.state_pool.label = State Pool +channel-type.ecotouch.state_service.label = State Service Mode +channel-type.ecotouch.state_solar.label = State Solar +channel-type.ecotouch.state_sourcepump.label = State Source Pump +channel-type.ecotouch.state_water.label = State Water +channel-type.ecotouch.tempSet0Deg.label = Heating Set 0°C +channel-type.ecotouch.tempSet0Deg.description = Heating Setpoint at 0°C Outside +channel-type.ecotouch.tempchange_cooling_pv.label = Change Cooling PV +channel-type.ecotouch.tempchange_cooling_pv.description = Temperature Change Cooling if PV +channel-type.ecotouch.tempchange_heating_pv.label = Change Heating PV +channel-type.ecotouch.tempchange_heating_pv.description = Temperature Change Heating if PV +channel-type.ecotouch.tempchange_pool_pv.label = Change Pool PV +channel-type.ecotouch.tempchange_pool_pv.description = Temperature Change Pool if PV +channel-type.ecotouch.tempchange_warmwater_pv.label = Change Water PV +channel-type.ecotouch.tempchange_warmwater_pv.description = Temperature Change Water if PV +channel-type.ecotouch.temperature2_outside_1h.label = Outside 1h Average +channel-type.ecotouch.temperature2_outside_1h.description = Temperature Outside 1h Average (A90) +channel-type.ecotouch.temperature_condensation.label = Temperature Condensation +channel-type.ecotouch.temperature_cooling_return.label = Cooling Return +channel-type.ecotouch.temperature_cooling_return.description = Temperature Cooling Return +channel-type.ecotouch.temperature_cooling_set.label = Cooling Set +channel-type.ecotouch.temperature_cooling_set.description = Temperature Cooling Setpoint +channel-type.ecotouch.temperature_cooling_set2.label = Cooling Set BMS +channel-type.ecotouch.temperature_cooling_set2.description = Temperature Cooling Setpoint BMS +channel-type.ecotouch.temperature_evaporation.label = Temperature Evaporation +channel-type.ecotouch.temperature_flow.label = Temperature Flow +channel-type.ecotouch.temperature_heating_return.label = Heating Return +channel-type.ecotouch.temperature_heating_return.description = Temperature Heating Return +channel-type.ecotouch.temperature_heating_set.label = Heating Set +channel-type.ecotouch.temperature_heating_set.description = Temperature Heating Setpoint +channel-type.ecotouch.temperature_heating_set2.label = Heating Set BMS +channel-type.ecotouch.temperature_heating_set2.description = Temperature Heating Setpoint BMS +channel-type.ecotouch.temperature_outside.label = Temperature Outside +channel-type.ecotouch.temperature_outside.description = The current outside temperature +channel-type.ecotouch.temperature_outside_1h.label = Average Temperature 1h +channel-type.ecotouch.temperature_outside_1h.description = The outside temperature averaged over one hour +channel-type.ecotouch.temperature_outside_24h.label = Average Temperature 24h +channel-type.ecotouch.temperature_outside_24h.description = The outside temperature averaged over one day +channel-type.ecotouch.temperature_pool.label = Temperature Pool +channel-type.ecotouch.temperature_pool_set.label = Pool Set +channel-type.ecotouch.temperature_pool_set.description = Temperature Pool Setpoint +channel-type.ecotouch.temperature_pool_set2.label = Pool Set BMS +channel-type.ecotouch.temperature_pool_set2.description = Temperature Pool Setpoint BMS +channel-type.ecotouch.temperature_return.label = Temperature Return +channel-type.ecotouch.temperature_return_set.label = Temperature Return Set +channel-type.ecotouch.temperature_room.label = Temperature Room +channel-type.ecotouch.temperature_room_1h.label = Avg. Room Temp 1h +channel-type.ecotouch.temperature_solar.label = Temperature Solar +channel-type.ecotouch.temperature_solar_flow.label = Temperature Solar Flow +channel-type.ecotouch.temperature_source_in.label = Temperature Source In +channel-type.ecotouch.temperature_source_out.label = Temperature Source Out +channel-type.ecotouch.temperature_storage.label = Temperature Storage +channel-type.ecotouch.temperature_suction.label = Temperature Suction +channel-type.ecotouch.temperature_suction_air.label = Temperature Suction Air +channel-type.ecotouch.temperature_sump.label = Temperature Sump +channel-type.ecotouch.temperature_surrounding.label = Temperature Surrounding +channel-type.ecotouch.temperature_water.label = Temperature Water +channel-type.ecotouch.temperature_water_set.label = Water Set +channel-type.ecotouch.temperature_water_set.description = Temperature Water Setpoint +channel-type.ecotouch.temperature_water_set2.label = Water Set BMS +channel-type.ecotouch.temperature_water_set2.description = Temperature Water Setpoint BMS +channel-type.ecotouch.time_hour.label = Hour +channel-type.ecotouch.time_minute.label = Minute +channel-type.ecotouch.version_bios.label = Version BIOS +channel-type.ecotouch.version_controller.label = Version Controller +channel-type.ecotouch.version_controller.description = Version Display Controller +channel-type.ecotouch.version_controller_build.label = Build Number Controller +channel-type.ecotouch.version_controller_build.description = Build Number Display Controller diff --git a/bundles/org.openhab.binding.elerotransmitterstick/src/main/resources/OH-INF/i18n/elerotransmitterstick.properties b/bundles/org.openhab.binding.elerotransmitterstick/src/main/resources/OH-INF/i18n/elerotransmitterstick.properties new file mode 100644 index 0000000000000..a7b338cb7b04d --- /dev/null +++ b/bundles/org.openhab.binding.elerotransmitterstick/src/main/resources/OH-INF/i18n/elerotransmitterstick.properties @@ -0,0 +1,27 @@ +# binding + +binding.elerotransmitterstick.name = Elero Transmitter Stick Binding +binding.elerotransmitterstick.description = This is the binding for Elero Transmitter Sticks. + +# thing types + +thing-type.elerotransmitterstick.elerochannel.label = Elero Channel +thing-type.elerotransmitterstick.elerochannel.description = One of the 15 elero channels available on an Elero Transmitter Stick. +thing-type.elerotransmitterstick.elerostick.label = Elero Transmitter Stick +thing-type.elerotransmitterstick.elerostick.description = Thing for an Elero Transmitter Stick + +# thing types config + +thing-type.config.elerotransmitterstick.elerochannel.channelId.label = Channel ID +thing-type.config.elerotransmitterstick.elerochannel.channelId.description = The id of this channel. +thing-type.config.elerotransmitterstick.elerostick.portName.label = Port Name +thing-type.config.elerotransmitterstick.elerostick.portName.description = The name of the port to which the Elero Transmitter Stick is connected. +thing-type.config.elerotransmitterstick.elerostick.updateInterval.label = Update Interval +thing-type.config.elerotransmitterstick.elerostick.updateInterval.description = The number of seconds to wait before requesting the status of the elero channels from the Elero Transmitter Stick. + +# channel types + +channel-type.elerotransmitterstick.control.label = Control +channel-type.elerotransmitterstick.control.description = Allows to control the devices connected to this elero channel or group by sending UP, DOWN, STOP commands. +channel-type.elerotransmitterstick.status.label = Status +channel-type.elerotransmitterstick.status.description = Read only channel providing the current status of this elero channel or group. diff --git a/bundles/org.openhab.binding.energenie/src/main/resources/OH-INF/i18n/energenie.properties b/bundles/org.openhab.binding.energenie/src/main/resources/OH-INF/i18n/energenie.properties new file mode 100644 index 0000000000000..38fd46859a91a --- /dev/null +++ b/bundles/org.openhab.binding.energenie/src/main/resources/OH-INF/i18n/energenie.properties @@ -0,0 +1,43 @@ +# binding + +binding.energenie.name = Energenie Binding +binding.energenie.description = This is the binding for Energenie. + +# thing types + +thing-type.energenie.pm2lan.label = EG-PM2-LAN +thing-type.energenie.pm2lan.description = Energenie programmable power strip with LAN interface +thing-type.energenie.pms2lan.label = EG-PMS2-LAN +thing-type.energenie.pms2lan.description = Energenie programmable power strip with LAN interface +thing-type.energenie.pmslan.label = EG-PMS-LAN +thing-type.energenie.pmslan.description = Energenie programmable power strip with LAN interface +thing-type.energenie.pmswlan.label = EG-PMS-WLAN +thing-type.energenie.pmswlan.description = Energenie programmable power strip with WLAN interface +thing-type.energenie.pwmlan.label = EGM-PWM-LAN +thing-type.energenie.pwmlan.description = Energenie energy meter with LAN interface + +# thing types config + +thing-type.config.energenie.config.host.label = IP-Address +thing-type.config.energenie.config.host.description = The IP address of this device +thing-type.config.energenie.config.password.label = Password +thing-type.config.energenie.config.password.description = The password of this device + +# channel types + +channel-type.energenie.current.label = Current +channel-type.energenie.current.description = Channel representing the current +channel-type.energenie.energy.label = Energy +channel-type.energenie.energy.description = Channel representing the energy consumption +channel-type.energenie.power.label = Power +channel-type.energenie.power.description = Channel representing the power consumption +channel-type.energenie.socket1.label = Socket 1 State +channel-type.energenie.socket1.description = Channel representing the state of socket 1 +channel-type.energenie.socket2.label = Socket 2 State +channel-type.energenie.socket2.description = Channel representing the state of socket 2 +channel-type.energenie.socket3.label = Socket 3 State +channel-type.energenie.socket3.description = Channel representing the state of socket 3 +channel-type.energenie.socket4.label = Socket 4 State +channel-type.energenie.socket4.description = Channel representing the state of socket 4 +channel-type.energenie.voltage.label = Voltage +channel-type.energenie.voltage.description = Channel representing the voltage diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/i18n/epsonprojector.properties b/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/i18n/epsonprojector.properties new file mode 100644 index 0000000000000..30090f428e1dd --- /dev/null +++ b/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/i18n/epsonprojector.properties @@ -0,0 +1,143 @@ +# binding + +binding.epsonprojector.name = Epson Projector Binding +binding.epsonprojector.description = This binding is compatible with Epson projectors which support the ESC/VP21 protocol + +# thing types + +thing-type.epsonprojector.projector-serial.label = Epson Projector - Serial +thing-type.epsonprojector.projector-serial.description = An Epson projector which supports the ESC/VP21 protocol via a serial port connection +thing-type.epsonprojector.projector-tcp.label = Epson Projector - TCP/IP +thing-type.epsonprojector.projector-tcp.description = An Epson projector which supports the ESC/VP21 protocol via the built-in ethernet port or a serial over IP connection + +# thing types config + +thing-type.config.epsonprojector.projector-serial.maxVolume.label = Volume Range +thing-type.config.epsonprojector.projector-serial.maxVolume.description = Set to Match the Volume Range Seen in the Projector's OSD +thing-type.config.epsonprojector.projector-serial.maxVolume.option.20 = Volume range is 0-20 +thing-type.config.epsonprojector.projector-serial.maxVolume.option.40 = Volume range is 0-40 +thing-type.config.epsonprojector.projector-serial.pollingInterval.label = Polling Interval +thing-type.config.epsonprojector.projector-serial.pollingInterval.description = Configures How Often to Poll the Projector for Updates (5-60; Default 10) +thing-type.config.epsonprojector.projector-serial.serialPort.label = Serial Port +thing-type.config.epsonprojector.projector-serial.serialPort.description = Serial Port to Use for Connecting to the Epson Projector +thing-type.config.epsonprojector.projector-tcp.host.label = Host +thing-type.config.epsonprojector.projector-tcp.host.description = IP address for the projector or serial over IP device +thing-type.config.epsonprojector.projector-tcp.maxVolume.label = Volume Range +thing-type.config.epsonprojector.projector-tcp.maxVolume.description = Set to Match the Volume Range Seen in the Projector's OSD +thing-type.config.epsonprojector.projector-tcp.maxVolume.option.20 = Volume range is 0-20 +thing-type.config.epsonprojector.projector-tcp.maxVolume.option.40 = Volume range is 0-40 +thing-type.config.epsonprojector.projector-tcp.pollingInterval.label = Polling Interval +thing-type.config.epsonprojector.projector-tcp.pollingInterval.description = Configures How Often to Poll the Projector for Updates (5-60; Default 10) +thing-type.config.epsonprojector.projector-tcp.port.label = Port +thing-type.config.epsonprojector.projector-tcp.port.description = Port for the projector or serial over IP device + +# channel types + +channel-type.epsonprojector.aspectratio.label = Aspect Ratio +channel-type.epsonprojector.aspectratio.description = Retrieve or Set the Aspect Ratio +channel-type.epsonprojector.aspectratio.state.option.NORMAL = NORMAL +channel-type.epsonprojector.aspectratio.state.option.AUTO = AUTO +channel-type.epsonprojector.aspectratio.state.option.FULL = FULL +channel-type.epsonprojector.aspectratio.state.option.ZOOM = ZOOM +channel-type.epsonprojector.aspectratio.state.option.WIDE = WIDE +channel-type.epsonprojector.aspectratio.state.option.ANAMORPHIC = ANAMORPHIC +channel-type.epsonprojector.aspectratio.state.option.SQUEEZE = SQUEEZE +channel-type.epsonprojector.aspectratio.state.option.RATIO4X3 = RATIO4X3 +channel-type.epsonprojector.aspectratio.state.option.ZOOM4X3 = ZOOM4X3 +channel-type.epsonprojector.aspectratio.state.option.RATIO16X9 = RATIO16X9 +channel-type.epsonprojector.aspectratio.state.option.UP16X9 = UP16X9 +channel-type.epsonprojector.aspectratio.state.option.DOWN16X9 = DOWN16X9 +channel-type.epsonprojector.aspectratio.state.option.REAL = REAL +channel-type.epsonprojector.autokeystone.label = Auto Keystone +channel-type.epsonprojector.autokeystone.description = Turn the Auto Keystone On or Off +channel-type.epsonprojector.background.label = Background +channel-type.epsonprojector.background.description = Select the Background Color/Logo +channel-type.epsonprojector.background.state.option.BLACK = BLACK +channel-type.epsonprojector.background.state.option.BLUE = BLUE +channel-type.epsonprojector.background.state.option.LOGO = LOGO +channel-type.epsonprojector.brightness.label = Brightness +channel-type.epsonprojector.brightness.description = Retrieve or Set the Brightness +channel-type.epsonprojector.colormode.label = Color Mode +channel-type.epsonprojector.colormode.description = Retrieve or Set the Color Mode +channel-type.epsonprojector.colormode.state.option.DYNAMIC = DYNAMIC +channel-type.epsonprojector.colormode.state.option.LIVINGROOM = LIVINGROOM +channel-type.epsonprojector.colormode.state.option.NATURAL = NATURAL +channel-type.epsonprojector.colormode.state.option.CINEMA = CINEMA +channel-type.epsonprojector.colormode.state.option.CINEMANIGHT = CINEMANIGHT +channel-type.epsonprojector.colormode.state.option.BWCINEMA = BWCINEMA +channel-type.epsonprojector.colormode.state.option.DIGITALCINEMA = DIGITALCINEMA +channel-type.epsonprojector.colormode.state.option.HD = HD +channel-type.epsonprojector.colormode.state.option.THX = THX +channel-type.epsonprojector.colormode.state.option.CINEMA3D = CINEMA3D +channel-type.epsonprojector.colormode.state.option.DYNAMIC3D = DYNAMIC3D +channel-type.epsonprojector.colormode.state.option.THX3D = THX3D +channel-type.epsonprojector.colormode.state.option.SRGB = SRGB +channel-type.epsonprojector.colormode.state.option.NORMAL = NORMAL +channel-type.epsonprojector.colormode.state.option.MEETING = MEETING +channel-type.epsonprojector.colormode.state.option.PRESENTATION = PRESENTATION +channel-type.epsonprojector.colormode.state.option.SPORTS = SPORTS +channel-type.epsonprojector.colormode.state.option.CUSTOM = CUSTOM +channel-type.epsonprojector.colormode.state.option.BLACKBOARD = BLACKBOARD +channel-type.epsonprojector.colormode.state.option.WHITEBOARD = WHITEBOARD +channel-type.epsonprojector.colormode.state.option.PHOTO = PHOTO +channel-type.epsonprojector.colormode.state.option.SILVER = SILVER +channel-type.epsonprojector.colormode.state.option.XVCOLOR = XVCOLOR +channel-type.epsonprojector.colormode.state.option.DICOMSIM = DICOMSIM +channel-type.epsonprojector.colormode.state.option.AUTO = AUTO +channel-type.epsonprojector.colortemperature.label = Color Temperature +channel-type.epsonprojector.colortemperature.description = Retrieve or Set the Color Temperature +channel-type.epsonprojector.contrast.label = Contrast +channel-type.epsonprojector.contrast.description = Retrieve or Set the Contrast +channel-type.epsonprojector.density.label = Density (Color Saturation) +channel-type.epsonprojector.density.description = Retrieve or Set the Density +channel-type.epsonprojector.errcode.label = ErrCode +channel-type.epsonprojector.errcode.description = Retrieves the Last Error Code +channel-type.epsonprojector.errmessage.label = ErrMessage +channel-type.epsonprojector.errmessage.description = Retrieves the Description of the Last Error +channel-type.epsonprojector.fleshtemperature.label = Flesh Temperature +channel-type.epsonprojector.fleshtemperature.description = Retrieve or Set the Flesh Temperature +channel-type.epsonprojector.freeze.label = Freeze Image +channel-type.epsonprojector.freeze.description = Turn the Freeze Screen Mode On or Off +channel-type.epsonprojector.gamma.label = Gamma +channel-type.epsonprojector.gamma.description = Retrieve or Set the Gamma Setting +channel-type.epsonprojector.gamma.state.option.G2_0 = G2_0 +channel-type.epsonprojector.gamma.state.option.G2_1 = G2_1 +channel-type.epsonprojector.gamma.state.option.G2_2 = G2_2 +channel-type.epsonprojector.gamma.state.option.G2_3 = G2_3 +channel-type.epsonprojector.gamma.state.option.G2_4 = G2_4 +channel-type.epsonprojector.gamma.state.option.CUSTOM = CUSTOM +channel-type.epsonprojector.horizontalkeystone.label = Horizontal Keystone +channel-type.epsonprojector.horizontalkeystone.description = Retrieve or Set the Horizontal Keystone +channel-type.epsonprojector.horizontalposition.label = Horizontal Position +channel-type.epsonprojector.horizontalposition.description = Retrieve or Set the Horizontal Position +channel-type.epsonprojector.horizontalreverse.label = Horizontal Reverse +channel-type.epsonprojector.horizontalreverse.description = Turn the Horizontal Reverse On or Off +channel-type.epsonprojector.keycode.label = KeyCode +channel-type.epsonprojector.keycode.description = Send a KEY Operation Command to the Projector +channel-type.epsonprojector.lamptime.label = Lamp Time +channel-type.epsonprojector.lamptime.description = Retrieves the Lamp Hours +channel-type.epsonprojector.luminance.label = Luminance +channel-type.epsonprojector.luminance.description = Retrieve or Set the Lamp Mode +channel-type.epsonprojector.luminance.state.option.NORMAL = NORMAL +channel-type.epsonprojector.luminance.state.option.ECO = ECO +channel-type.epsonprojector.luminance.state.option.MEDIUM = MEDIUM +channel-type.epsonprojector.mute.label = AV Mute +channel-type.epsonprojector.mute.description = Turn the AV Mute On or Off +channel-type.epsonprojector.powerstate.label = Power State +channel-type.epsonprojector.powerstate.description = Retrieves the Textual Power State of the Projector +channel-type.epsonprojector.source.label = Source +channel-type.epsonprojector.source.description = Retrieve or Set the Input Source +channel-type.epsonprojector.source.state.option.30 = HDMI1 +channel-type.epsonprojector.source.state.option.A0 = HDMI2 +channel-type.epsonprojector.source.state.option.14 = Component +channel-type.epsonprojector.source.state.option.20 = PC DSUB +channel-type.epsonprojector.source.state.option.41 = Video +channel-type.epsonprojector.source.state.option.42 = S-Video +channel-type.epsonprojector.tint.label = Tint +channel-type.epsonprojector.tint.description = Retrieve or Set the Tint +channel-type.epsonprojector.verticalkeystone.label = Vertical Keystone +channel-type.epsonprojector.verticalkeystone.description = Retrieve or Set the Vertical Keystone +channel-type.epsonprojector.verticalposition.label = Vertical Position +channel-type.epsonprojector.verticalposition.description = Retrieve or Set the Vertical Position +channel-type.epsonprojector.verticalreverse.label = Vertical Reverse +channel-type.epsonprojector.verticalreverse.description = Turn the Vertical Reverse On or Off diff --git a/bundles/org.openhab.binding.etherrain/src/main/resources/OH-INF/i18n/etherrain.properties b/bundles/org.openhab.binding.etherrain/src/main/resources/OH-INF/i18n/etherrain.properties new file mode 100644 index 0000000000000..28bc6612ed367 --- /dev/null +++ b/bundles/org.openhab.binding.etherrain/src/main/resources/OH-INF/i18n/etherrain.properties @@ -0,0 +1,59 @@ +# binding + +binding.etherrain.name = EtherRain Binding +binding.etherrain.description = This is the binding for EtherRain + +# thing types + +thing-type.etherrain.etherrain.label = EtherRain +thing-type.etherrain.etherrain.description = This is a stand alone EtherRain device that allows sprinkler control +thing-type.etherrain.etherrain.channel.clear.label = Clear +thing-type.etherrain.etherrain.channel.clear.description = Clears the currently running program +thing-type.etherrain.etherrain.channel.execute.label = Execute +thing-type.etherrain.etherrain.channel.execute.description = Commands EtherRain device to begin watering program + +# thing types config + +thing-type.config.etherrain.etherrain.host.label = Host Name +thing-type.config.etherrain.etherrain.host.description = The host name or IP address of the EtherRain Web API interface +thing-type.config.etherrain.etherrain.password.label = Password +thing-type.config.etherrain.etherrain.password.description = The admin password used to access the Web API interface +thing-type.config.etherrain.etherrain.port.label = Port +thing-type.config.etherrain.etherrain.port.description = Port of the EtherRain Web API interface +thing-type.config.etherrain.etherrain.programDelay.label = Program Delay +thing-type.config.etherrain.etherrain.programDelay.description = The amount of time, in minutes, that EtherRain will delay before starting a program +thing-type.config.etherrain.etherrain.refresh.label = Refresh +thing-type.config.etherrain.etherrain.refresh.description = The amount of time, in seconds, that openHAB should poll EtherRain +thing-type.config.etherrain.etherrain.zoneOnTime1.label = Zone 1 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime1.description = The amount of time, in minutes, that EtherRain will run zone 1 in program +thing-type.config.etherrain.etherrain.zoneOnTime2.label = Zone 2 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime2.description = The amount of time, in minutes, that EtherRain will run zone 2 in program +thing-type.config.etherrain.etherrain.zoneOnTime3.label = Zone 3 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime3.description = The amount of time, in minutes, that EtherRain will run zone 3 in program +thing-type.config.etherrain.etherrain.zoneOnTime4.label = Zone 4 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime4.description = The amount of time, in minutes, that EtherRain will run zone 4 in program +thing-type.config.etherrain.etherrain.zoneOnTime5.label = Zone 5 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime5.description = The amount of time, in minutes, that EtherRain will run zone 5 in program +thing-type.config.etherrain.etherrain.zoneOnTime6.label = Zone 6 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime6.description = The amount of time, in minutes, that EtherRain will run zone 6 in program +thing-type.config.etherrain.etherrain.zoneOnTime7.label = Zone 7 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime7.description = The amount of time, in minutes, that EtherRain will run zone 7 in program +thing-type.config.etherrain.etherrain.zoneOnTime8.label = Zone 8 Run Time +thing-type.config.etherrain.etherrain.zoneOnTime8.description = The amount of time, in minutes, that EtherRain will run zone 8 in program + +# channel types + +channel-type.etherrain.commandstatus.label = Command Status +channel-type.etherrain.commandstatus.description = Status of the last command given to the Etherrain +channel-type.etherrain.execute.label = Execute +channel-type.etherrain.execute.description = Send a command to the EtherRain Controller +channel-type.etherrain.operatingresult.label = Operating Result +channel-type.etherrain.operatingresult.description = Result of operating status +channel-type.etherrain.operatingstatus.label = Operating Status +channel-type.etherrain.operatingstatus.description = Current operating status of the Etherrain +channel-type.etherrain.rainsensor.label = Rain +channel-type.etherrain.rainsensor.description = Provides feedback on whether the EtherRain device has detected rain or not +channel-type.etherrain.relayindex.label = Relay Index +channel-type.etherrain.relayindex.description = Number of the last zone that was operating +channel-type.etherrain.runtime.label = Runtime +channel-type.etherrain.runtime.description = How long a zone will run in seconds diff --git a/bundles/org.openhab.binding.evohome/src/main/resources/OH-INF/i18n/evohome.properties b/bundles/org.openhab.binding.evohome/src/main/resources/OH-INF/i18n/evohome.properties new file mode 100644 index 0000000000000..5146ccc6c860d --- /dev/null +++ b/bundles/org.openhab.binding.evohome/src/main/resources/OH-INF/i18n/evohome.properties @@ -0,0 +1,52 @@ +# binding + +binding.evohome.name = evohome Binding +binding.evohome.description = The evohome binding controls the Honeywell evohome system. + +# thing types + +thing-type.evohome.account.label = evohome Account +thing-type.evohome.account.description = The evohome account is used to connect to your Total Connect Comfort (TCC) using your TCC username and password. +thing-type.evohome.display.label = evohome Display +thing-type.evohome.display.description = This represents the evohome control display. +thing-type.evohome.heatingzone.label = evohome Heating Zone +thing-type.evohome.heatingzone.description = This represents the evohome Heating Zone. + +# thing types config + +thing-type.config.evohome.account.group.auth.label = Authentication +thing-type.config.evohome.account.group.auth.description = Contains the settings needed to authenticate against the TCC service. +thing-type.config.evohome.account.password.label = Password +thing-type.config.evohome.account.password.description = Your TCC Password +thing-type.config.evohome.account.refreshInterval.label = Refresh Interval +thing-type.config.evohome.account.refreshInterval.description = The refresh interval to poll TCC (in seconds). +thing-type.config.evohome.account.username.label = Username +thing-type.config.evohome.account.username.description = Your TCC Username +thing-type.config.evohome.display.id.label = ID +thing-type.config.evohome.display.id.description = ID of the display +thing-type.config.evohome.display.name.label = Name +thing-type.config.evohome.display.name.description = Name of the display +thing-type.config.evohome.heatingzone.id.label = ID +thing-type.config.evohome.heatingzone.id.description = ID of the zone +thing-type.config.evohome.heatingzone.name.label = Name +thing-type.config.evohome.heatingzone.name.description = Name of the zone + +# channel types + +channel-type.evohome.setpoint.label = Set Point +channel-type.evohome.setpoint.description = Gets or sets the set point of this zone (0 cancels the override). +channel-type.evohome.setpointstatus.label = Set Point Status +channel-type.evohome.setpointstatus.description = Current set point status +channel-type.evohome.setpointstatus.state.option.PermanentOverride = Permanent override +channel-type.evohome.setpointstatus.state.option.FollowSchedule = Follow schedule +channel-type.evohome.setpointstatus.state.option.TemporaryOverride = Temporary override +channel-type.evohome.systemMode.label = System Mode +channel-type.evohome.systemMode.description = Current system mode +channel-type.evohome.systemMode.state.option.Auto = Normal +channel-type.evohome.systemMode.state.option.AutoWithEco = Eco +channel-type.evohome.systemMode.state.option.Away = Away +channel-type.evohome.systemMode.state.option.DayOff = Day off +channel-type.evohome.systemMode.state.option.HeatingOff = Off +channel-type.evohome.systemMode.state.option.Custom = Custom +channel-type.evohome.temperature.label = Temperature +channel-type.evohome.temperature.description = Current zone temperature diff --git a/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec.properties b/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec.properties new file mode 100644 index 0000000000000..a9d54a120bc2b --- /dev/null +++ b/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec.properties @@ -0,0 +1,35 @@ +# binding + +binding.exec.name = Exec Binding +binding.exec.description = This is the binding to execute arbitrary shell commands + +# thing types + +thing-type.exec.command.label = Command +thing-type.exec.command.description = The Command encapsulates a shell command to be executed + +# thing types config + +thing-type.config.exec.command.autorun.label = Autorun +thing-type.config.exec.command.autorun.description = When true, the command will execute each time the state of the input channel changes +thing-type.config.exec.command.command.label = Command +thing-type.config.exec.command.command.description = The command to execute +thing-type.config.exec.command.interval.label = Interval +thing-type.config.exec.command.interval.description = Interval, in seconds, the command will be repeatedly executed +thing-type.config.exec.command.timeout.label = Timeout +thing-type.config.exec.command.timeout.description = Time out, in seconds, the execution of the command will time out +thing-type.config.exec.command.transform.label = Transform +thing-type.config.exec.command.transform.description = The transformation to apply on the execution result, e.g. REGEX((.*)) + +# channel types + +channel-type.exec.exit.label = Exit Value +channel-type.exec.exit.description = The exit value of the last execution of the command +channel-type.exec.input.label = Input +channel-type.exec.input.description = Input that will be passed as second parameter to the command +channel-type.exec.lastexecution.label = Last Execution +channel-type.exec.lastexecution.description = Time/Date the command was last executed, in yyyy-MM-dd'T'HH:mm:ss.SSSZ format +channel-type.exec.output.label = Output +channel-type.exec.output.description = Output of the last execution of the command +channel-type.exec.run.label = Running +channel-type.exec.run.description = Send ON to execute the command and the current state tells whether it is running or not diff --git a/bundles/org.openhab.binding.feican/src/main/resources/OH-INF/i18n/feican.properties b/bundles/org.openhab.binding.feican/src/main/resources/OH-INF/i18n/feican.properties new file mode 100644 index 0000000000000..de966a329c67b --- /dev/null +++ b/bundles/org.openhab.binding.feican/src/main/resources/OH-INF/i18n/feican.properties @@ -0,0 +1,54 @@ +# binding + +binding.feican.name = Feican Binding +binding.feican.description = This is the binding for Feican light bulbs. + +# thing types + +thing-type.feican.bulb.label = Wifi RGBW Bulb +thing-type.feican.bulb.description = A dimmable light with changeable colors. + +# thing types config + +thing-type.config.feican.bulb.ipAddress.label = IP Address +thing-type.config.feican.bulb.ipAddress.description = IP Address of the device. + +# channel types + +channel-type.feican.color.label = Color +channel-type.feican.color.description = This channel supports adjusting the color of a light. +channel-type.feican.color_temperature.label = Color Temperature +channel-type.feican.color_temperature.description = This channel supports adjusting the color temperature from cold (0%) to warm (100%). +channel-type.feican.program.label = Program +channel-type.feican.program.description = This channel supports setting the bulb to a static, jumping, gradient or flashing light. +channel-type.feican.program.state.option.1 = Static red +channel-type.feican.program.state.option.2 = Static blue +channel-type.feican.program.state.option.3 = Static green +channel-type.feican.program.state.option.4 = Static cyan +channel-type.feican.program.state.option.5 = Static yellow +channel-type.feican.program.state.option.6 = Static purple +channel-type.feican.program.state.option.7 = Static white +channel-type.feican.program.state.option.8 = Tricolor jump +channel-type.feican.program.state.option.9 = 7-color jump +channel-type.feican.program.state.option.10 = Tricolor gradient +channel-type.feican.program.state.option.11 = 7-color gradient +channel-type.feican.program.state.option.12 = Red gradient +channel-type.feican.program.state.option.13 = Green gradient +channel-type.feican.program.state.option.14 = Blue gradient +channel-type.feican.program.state.option.15 = Yellow gradient +channel-type.feican.program.state.option.16 = Cyan gradient +channel-type.feican.program.state.option.17 = Purple gradient +channel-type.feican.program.state.option.18 = White gradient +channel-type.feican.program.state.option.19 = Red-Green gradient +channel-type.feican.program.state.option.20 = Red-Blue gradient +channel-type.feican.program.state.option.21 = Green-Blue gradient +channel-type.feican.program.state.option.22 = 7-color flash +channel-type.feican.program.state.option.23 = Red flash +channel-type.feican.program.state.option.24 = Green flash +channel-type.feican.program.state.option.25 = Blue flash +channel-type.feican.program.state.option.26 = Yellow flash +channel-type.feican.program.state.option.27 = Cyan flash +channel-type.feican.program.state.option.28 = Purple flash +channel-type.feican.program.state.option.29 = White flash +channel-type.feican.program_speed.label = Program Speed +channel-type.feican.program_speed.description = Speed of flash and gradient programs from 0 (slow) to 100 (fast). diff --git a/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties new file mode 100644 index 0000000000000..84564200bde5f --- /dev/null +++ b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties @@ -0,0 +1,267 @@ +# binding + +binding.fmiweather.name = FMI Weather Binding +binding.fmiweather.description = This is the binding for Finnish Meteorological Institute (FMI) Weather + +# thing types + +thing-type.fmiweather.forecast.label = FMI Weather Forecast +thing-type.fmiweather.forecast.description = Finnish Meteorological Institute (FMI) weather forecast +thing-type.fmiweather.forecast.group.forecastHours01.label = 1 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours01.description = This is the weather forecast in 1 hours. +thing-type.fmiweather.forecast.group.forecastHours02.label = 2 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours02.description = This is the weather forecast in 2 hours. +thing-type.fmiweather.forecast.group.forecastHours03.label = 3 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours03.description = This is the weather forecast in 3 hours. +thing-type.fmiweather.forecast.group.forecastHours04.label = 4 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours04.description = This is the weather forecast in 4 hours. +thing-type.fmiweather.forecast.group.forecastHours05.label = 5 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours05.description = This is the weather forecast in 5 hours. +thing-type.fmiweather.forecast.group.forecastHours06.label = 6 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours06.description = This is the weather forecast in 6 hours. +thing-type.fmiweather.forecast.group.forecastHours07.label = 7 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours07.description = This is the weather forecast in 7 hours. +thing-type.fmiweather.forecast.group.forecastHours08.label = 8 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours08.description = This is the weather forecast in 8 hours. +thing-type.fmiweather.forecast.group.forecastHours09.label = 9 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours09.description = This is the weather forecast in 9 hours. +thing-type.fmiweather.forecast.group.forecastHours10.label = 10 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours10.description = This is the weather forecast in 10 hours. +thing-type.fmiweather.forecast.group.forecastHours11.label = 11 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours11.description = This is the weather forecast in 11 hours. +thing-type.fmiweather.forecast.group.forecastHours12.label = 12 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours12.description = This is the weather forecast in 12 hours. +thing-type.fmiweather.forecast.group.forecastHours13.label = 13 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours13.description = This is the weather forecast in 13 hours. +thing-type.fmiweather.forecast.group.forecastHours14.label = 14 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours14.description = This is the weather forecast in 14 hours. +thing-type.fmiweather.forecast.group.forecastHours15.label = 15 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours15.description = This is the weather forecast in 15 hours. +thing-type.fmiweather.forecast.group.forecastHours16.label = 16 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours16.description = This is the weather forecast in 16 hours. +thing-type.fmiweather.forecast.group.forecastHours17.label = 17 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours17.description = This is the weather forecast in 17 hours. +thing-type.fmiweather.forecast.group.forecastHours18.label = 18 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours18.description = This is the weather forecast in 18 hours. +thing-type.fmiweather.forecast.group.forecastHours19.label = 19 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours19.description = This is the weather forecast in 19 hours. +thing-type.fmiweather.forecast.group.forecastHours20.label = 20 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours20.description = This is the weather forecast in 20 hours. +thing-type.fmiweather.forecast.group.forecastHours21.label = 21 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours21.description = This is the weather forecast in 21 hours. +thing-type.fmiweather.forecast.group.forecastHours22.label = 22 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours22.description = This is the weather forecast in 22 hours. +thing-type.fmiweather.forecast.group.forecastHours23.label = 23 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours23.description = This is the weather forecast in 23 hours. +thing-type.fmiweather.forecast.group.forecastHours24.label = 24 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours24.description = This is the weather forecast in 24 hours. +thing-type.fmiweather.forecast.group.forecastHours25.label = 25 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours25.description = This is the weather forecast in 25 hours. +thing-type.fmiweather.forecast.group.forecastHours26.label = 26 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours26.description = This is the weather forecast in 26 hours. +thing-type.fmiweather.forecast.group.forecastHours27.label = 27 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours27.description = This is the weather forecast in 27 hours. +thing-type.fmiweather.forecast.group.forecastHours28.label = 28 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours28.description = This is the weather forecast in 28 hours. +thing-type.fmiweather.forecast.group.forecastHours29.label = 29 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours29.description = This is the weather forecast in 29 hours. +thing-type.fmiweather.forecast.group.forecastHours30.label = 30 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours30.description = This is the weather forecast in 30 hours. +thing-type.fmiweather.forecast.group.forecastHours31.label = 31 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours31.description = This is the weather forecast in 31 hours. +thing-type.fmiweather.forecast.group.forecastHours32.label = 32 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours32.description = This is the weather forecast in 32 hours. +thing-type.fmiweather.forecast.group.forecastHours33.label = 33 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours33.description = This is the weather forecast in 33 hours. +thing-type.fmiweather.forecast.group.forecastHours34.label = 34 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours34.description = This is the weather forecast in 34 hours. +thing-type.fmiweather.forecast.group.forecastHours35.label = 35 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours35.description = This is the weather forecast in 35 hours. +thing-type.fmiweather.forecast.group.forecastHours36.label = 36 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours36.description = This is the weather forecast in 36 hours. +thing-type.fmiweather.forecast.group.forecastHours37.label = 37 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours37.description = This is the weather forecast in 37 hours. +thing-type.fmiweather.forecast.group.forecastHours38.label = 38 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours38.description = This is the weather forecast in 38 hours. +thing-type.fmiweather.forecast.group.forecastHours39.label = 39 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours39.description = This is the weather forecast in 39 hours. +thing-type.fmiweather.forecast.group.forecastHours40.label = 40 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours40.description = This is the weather forecast in 40 hours. +thing-type.fmiweather.forecast.group.forecastHours41.label = 41 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours41.description = This is the weather forecast in 41 hours. +thing-type.fmiweather.forecast.group.forecastHours42.label = 42 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours42.description = This is the weather forecast in 42 hours. +thing-type.fmiweather.forecast.group.forecastHours43.label = 43 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours43.description = This is the weather forecast in 43 hours. +thing-type.fmiweather.forecast.group.forecastHours44.label = 44 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours44.description = This is the weather forecast in 44 hours. +thing-type.fmiweather.forecast.group.forecastHours45.label = 45 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours45.description = This is the weather forecast in 45 hours. +thing-type.fmiweather.forecast.group.forecastHours46.label = 46 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours46.description = This is the weather forecast in 46 hours. +thing-type.fmiweather.forecast.group.forecastHours47.label = 47 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours47.description = This is the weather forecast in 47 hours. +thing-type.fmiweather.forecast.group.forecastHours48.label = 48 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours48.description = This is the weather forecast in 48 hours. +thing-type.fmiweather.forecast.group.forecastHours49.label = 49 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours49.description = This is the weather forecast in 49 hours. +thing-type.fmiweather.forecast.group.forecastHours50.label = 50 Hours Forecast +thing-type.fmiweather.forecast.group.forecastHours50.description = This is the weather forecast in 50 hours. +thing-type.fmiweather.forecast.group.forecastNow.label = Forecast for the Current Time +thing-type.fmiweather.forecast.group.forecastNow.description = This is the weather forecast for the current time +thing-type.fmiweather.observation.label = FMI Current Weather (Observation) +thing-type.fmiweather.observation.description = Finnish Meteorological Institute (FMI) weather observation + +# thing types config + +thing-type.config.fmiweather.forecast.location.label = Location +thing-type.config.fmiweather.forecast.location.description = Location of weather in geographical coordinates (latitude,longitude). +thing-type.config.fmiweather.observation.fmisid.label = FMISID of the Weather Station +thing-type.config.fmiweather.observation.fmisid.description = Station ID (FMISID) of the weather observation station

See https://en.ilmatieteenlaitos.fi/observation-stations for a list of observation stations. Select 'Weather' station for widest set of observations. + +# channel group types + +channel-group-type.fmiweather.current-group.label = Current Weather +channel-group-type.fmiweather.current-group.description = This is the current weather. +channel-group-type.fmiweather.group-forecast-advanced.label = Forecast +channel-group-type.fmiweather.group-forecast-advanced.description = This is hourly weather forecast. +channel-group-type.fmiweather.group-forecast.label = Forecast +channel-group-type.fmiweather.group-forecast.description = This is hourly weather forecast. + +# channel types + +channel-type.fmiweather.clouds-channel.label = Cloudiness +channel-type.fmiweather.clouds-channel.description = Given as percentage, 0% being clear skies, and 100% being overcast. UNDEF when cloud coverage could not be determined. Takes into account all cloud layers. +channel-type.fmiweather.forecast-time-channel.label = Forecast Time +channel-type.fmiweather.forecast-time-channel.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.fmiweather.humidity-channel.label = Humidity +channel-type.fmiweather.precipitation-channel.label = Precipitation +channel-type.fmiweather.precipitation-channel.description = Precipitation in one hour +channel-type.fmiweather.precipitation-intensity-channel.label = Precipitation Intensity +channel-type.fmiweather.precipitation-intensity-channel.description = Equivalent to the precipitation amount if the same intensity prevails for an hour. +channel-type.fmiweather.present-weather-channel.label = Prevailing Weather +channel-type.fmiweather.present-weather-channel.description = Prevailing weather code (WaWa field) according to WMO code 4680. For Finnish explanation, consult https://www.ilmatieteenlaitos.fi/latauspalvelun-pikaohje +channel-type.fmiweather.present-weather-channel.state.option.00 = No significant weather observed +channel-type.fmiweather.present-weather-channel.state.option.01 = Clouds generally dissolving or becoming less developed during the past hour +channel-type.fmiweather.present-weather-channel.state.option.02 = State of sky on the whole unchanged during the past hour +channel-type.fmiweather.present-weather-channel.state.option.03 = Clouds generally forming or developing during the past hour +channel-type.fmiweather.present-weather-channel.state.option.04 = Haze or smoke, or dust in suspension in the air, visibility equal to, or greater than, 1 km +channel-type.fmiweather.present-weather-channel.state.option.05 = Haze or smoke, or dust in suspension in the air, visibility less than 1 km +channel-type.fmiweather.present-weather-channel.state.option.10 = Mist +channel-type.fmiweather.present-weather-channel.state.option.11 = Diamond dust +channel-type.fmiweather.present-weather-channel.state.option.12 = Distant lightning +channel-type.fmiweather.present-weather-channel.state.option.18 = Squalls +channel-type.fmiweather.present-weather-channel.state.option.19 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.20 = Fog +channel-type.fmiweather.present-weather-channel.state.option.21 = Precipitation +channel-type.fmiweather.present-weather-channel.state.option.22 = Drizzle (not freezing) or snow grains +channel-type.fmiweather.present-weather-channel.state.option.23 = Rain (not freezing) +channel-type.fmiweather.present-weather-channel.state.option.24 = Snow +channel-type.fmiweather.present-weather-channel.state.option.25 = Freezing drizzle or freezing rain +channel-type.fmiweather.present-weather-channel.state.option.26 = Thunderstorm (with or without precipitation) +channel-type.fmiweather.present-weather-channel.state.option.27 = Blowing or drifting snow or sand +channel-type.fmiweather.present-weather-channel.state.option.28 = Blowing or drifting snow or sand, visibility equal to, or greater than, 1 km +channel-type.fmiweather.present-weather-channel.state.option.29 = Blowing or drifting snow or sand, visibility less than 1 km +channel-type.fmiweather.present-weather-channel.state.option.30 = Fog +channel-type.fmiweather.present-weather-channel.state.option.31 = Fog or ice fog in patches +channel-type.fmiweather.present-weather-channel.state.option.32 = Fog or ice fog, has become thinner during the past hour +channel-type.fmiweather.present-weather-channel.state.option.33 = Fog or ice fog, no appreciable change during the past hour +channel-type.fmiweather.present-weather-channel.state.option.34 = Fog or ice fog, has begun or become thicker during the past hour +channel-type.fmiweather.present-weather-channel.state.option.35 = Fog, depositing rime +channel-type.fmiweather.present-weather-channel.state.option.40 = Precipitation +channel-type.fmiweather.present-weather-channel.state.option.41 = Precipitation, slight or moderate +channel-type.fmiweather.present-weather-channel.state.option.42 = Precipitation, heavy +channel-type.fmiweather.present-weather-channel.state.option.43 = Liquid precipitation, slight or moderate +channel-type.fmiweather.present-weather-channel.state.option.44 = Liquid precipitation, heavy +channel-type.fmiweather.present-weather-channel.state.option.45 = Solid precipitation, slight or moderate +channel-type.fmiweather.present-weather-channel.state.option.46 = Solid precipitation, heavy +channel-type.fmiweather.present-weather-channel.state.option.47 = Freezing precipitation, slight or moderate +channel-type.fmiweather.present-weather-channel.state.option.48 = Freezing precipitation, heavy +channel-type.fmiweather.present-weather-channel.state.option.49 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.50 = Drizzle +channel-type.fmiweather.present-weather-channel.state.option.51 = Drizzle, not freezing, slight +channel-type.fmiweather.present-weather-channel.state.option.52 = Drizzle, not freezing, moderate +channel-type.fmiweather.present-weather-channel.state.option.53 = Drizzle, not freezing, heavy +channel-type.fmiweather.present-weather-channel.state.option.54 = Drizzle, freezing, slight +channel-type.fmiweather.present-weather-channel.state.option.55 = Drizzle, freezing, moderate +channel-type.fmiweather.present-weather-channel.state.option.56 = Drizzle, freezing, heavy +channel-type.fmiweather.present-weather-channel.state.option.57 = Drizzle and rain, slight +channel-type.fmiweather.present-weather-channel.state.option.58 = Drizzle and rain, moderate or heavy +channel-type.fmiweather.present-weather-channel.state.option.59 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.60 = Rain +channel-type.fmiweather.present-weather-channel.state.option.61 = Rain, not freezing, slight +channel-type.fmiweather.present-weather-channel.state.option.62 = Rain, not freezing, moderate +channel-type.fmiweather.present-weather-channel.state.option.63 = Rain, not freezing, heavy +channel-type.fmiweather.present-weather-channel.state.option.64 = Rain, freezing, slight +channel-type.fmiweather.present-weather-channel.state.option.65 = Rain, freezing, moderate +channel-type.fmiweather.present-weather-channel.state.option.66 = Rain, freezing, heavy +channel-type.fmiweather.present-weather-channel.state.option.67 = Rain (or drizzle) and snow, slight +channel-type.fmiweather.present-weather-channel.state.option.68 = Rain (or drizzle) and snow, moderate or heavy +channel-type.fmiweather.present-weather-channel.state.option.69 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.70 = Snow +channel-type.fmiweather.present-weather-channel.state.option.71 = Snow, slight +channel-type.fmiweather.present-weather-channel.state.option.72 = Snow, moderate +channel-type.fmiweather.present-weather-channel.state.option.73 = Snow, heavy +channel-type.fmiweather.present-weather-channel.state.option.74 = Ice pellets, slight +channel-type.fmiweather.present-weather-channel.state.option.75 = Ice pellets, moderate +channel-type.fmiweather.present-weather-channel.state.option.76 = Ice pellets, heavy +channel-type.fmiweather.present-weather-channel.state.option.77 = Snow grains +channel-type.fmiweather.present-weather-channel.state.option.78 = Ice crystals +channel-type.fmiweather.present-weather-channel.state.option.79 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.80 = Shower(s) or intermittent precipitation +channel-type.fmiweather.present-weather-channel.state.option.81 = Rain shower(s) or intermittent rain, slight +channel-type.fmiweather.present-weather-channel.state.option.82 = Rain shower(s) or intermittent rain, moderate +channel-type.fmiweather.present-weather-channel.state.option.83 = Rain shower(s) or intermittent rain, heavy +channel-type.fmiweather.present-weather-channel.state.option.84 = Rain shower(s) or intermittent rain, violent +channel-type.fmiweather.present-weather-channel.state.option.85 = Snow shower(s) or intermittent snow, slight +channel-type.fmiweather.present-weather-channel.state.option.86 = Snow shower(s) or intermittent snow, moderate +channel-type.fmiweather.present-weather-channel.state.option.87 = Snow shower(s) or intermittent snow, heavy +channel-type.fmiweather.present-weather-channel.state.option.88 = Reserved +channel-type.fmiweather.present-weather-channel.state.option.89 = Hail +channel-type.fmiweather.present-weather-channel.state.option.90 = Thunderstorm +channel-type.fmiweather.present-weather-channel.state.option.91 = Thunderstorm, slight or moderate, with no precipitation +channel-type.fmiweather.present-weather-channel.state.option.92 = Thunderstorm, slight or moderate, with rain showers and/or snow showers +channel-type.fmiweather.present-weather-channel.state.option.93 = Thunderstorm, slight or moderate, with hail +channel-type.fmiweather.present-weather-channel.state.option.94 = Thunderstorm, heavy, with no precipitation +channel-type.fmiweather.present-weather-channel.state.option.95 = Thunderstorm, heavy, with rain showers and/or snow showers +channel-type.fmiweather.present-weather-channel.state.option.96 = Thunderstorm, heavy, with hail +channel-type.fmiweather.present-weather-channel.state.option.99 = Tornado +channel-type.fmiweather.pressure-channel.label = Pressure +channel-type.fmiweather.snow-depth-channel.label = Snow depth +channel-type.fmiweather.temperature-channel.label = Temperature +channel-type.fmiweather.time-channel.label = Observation Time +channel-type.fmiweather.time-channel.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.fmiweather.total-cloud-cover-channel.label = Total Cloud Cover +channel-type.fmiweather.visibility-channel.label = Visibility +channel-type.fmiweather.weather-id-channel.label = Prevailing Weather Id +channel-type.fmiweather.weather-id-channel.description = Prevailing weather code (WeatherSymbol3 field). For Finnish explanation, consult https://www.ilmatieteenlaitos.fi/latauspalvelun-pikaohje +channel-type.fmiweather.weather-id-channel.state.option.1 = clear +channel-type.fmiweather.weather-id-channel.state.option.2 = partly cloudy +channel-type.fmiweather.weather-id-channel.state.option.21 = light showers +channel-type.fmiweather.weather-id-channel.state.option.22 = moderate showers +channel-type.fmiweather.weather-id-channel.state.option.23 = heavy showers +channel-type.fmiweather.weather-id-channel.state.option.3 = cloudy +channel-type.fmiweather.weather-id-channel.state.option.31 = light rain +channel-type.fmiweather.weather-id-channel.state.option.32 = moderate rain +channel-type.fmiweather.weather-id-channel.state.option.33 = heavy rain +channel-type.fmiweather.weather-id-channel.state.option.41 = light snow showers +channel-type.fmiweather.weather-id-channel.state.option.42 = moderate snow showers +channel-type.fmiweather.weather-id-channel.state.option.43 = heavy snow showers +channel-type.fmiweather.weather-id-channel.state.option.51 = light snowfall +channel-type.fmiweather.weather-id-channel.state.option.52 = moderate snowfall +channel-type.fmiweather.weather-id-channel.state.option.53 = heavy snowfall +channel-type.fmiweather.weather-id-channel.state.option.61 = thundershowers +channel-type.fmiweather.weather-id-channel.state.option.62 = heavy thundershowers +channel-type.fmiweather.weather-id-channel.state.option.63 = thunder +channel-type.fmiweather.weather-id-channel.state.option.64 = heavy thunder +channel-type.fmiweather.weather-id-channel.state.option.71 = light sleet showers +channel-type.fmiweather.weather-id-channel.state.option.72 = moderate sleet showers +channel-type.fmiweather.weather-id-channel.state.option.73 = heavy sleet showers +channel-type.fmiweather.weather-id-channel.state.option.81 = light sleet +channel-type.fmiweather.weather-id-channel.state.option.82 = moderate sleet +channel-type.fmiweather.weather-id-channel.state.option.83 = heavy sleet +channel-type.fmiweather.weather-id-channel.state.option.91 = haze +channel-type.fmiweather.weather-id-channel.state.option.92 = fog +channel-type.fmiweather.wind-direction-channel.label = Wind Direction +channel-type.fmiweather.wind-gust-channel.label = Wind Gust +channel-type.fmiweather.wind-speed-channel.label = Wind Speed diff --git a/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/i18n/folderwatcher.properties b/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/i18n/folderwatcher.properties new file mode 100644 index 0000000000000..68501d5ece57c --- /dev/null +++ b/bundles/org.openhab.binding.folderwatcher/src/main/resources/OH-INF/i18n/folderwatcher.properties @@ -0,0 +1,52 @@ +# binding + +binding.folderwatcher.name = FolderWatcher Binding +binding.folderwatcher.description = This binding will monitor specified location for new files and trigger event channel with new file names. + +# thing types + +thing-type.folderwatcher.ftpfolder.label = FTP Folder +thing-type.folderwatcher.ftpfolder.description = FTP folder to be watched +thing-type.folderwatcher.localfolder.label = Local Folder +thing-type.folderwatcher.localfolder.description = Local folder to be watched + +# thing types config + +thing-type.config.folderwatcher.ftpfolder.connectionTimeout.label = Connection Timeout +thing-type.config.folderwatcher.ftpfolder.connectionTimeout.description = Connection timeout for FTP request, sec +thing-type.config.folderwatcher.ftpfolder.diffHours.label = Timestamp Difference +thing-type.config.folderwatcher.ftpfolder.diffHours.description = How many hours back to analyze +thing-type.config.folderwatcher.ftpfolder.ftpAddress.label = FTP Server +thing-type.config.folderwatcher.ftpfolder.ftpAddress.description = Address of FTP server +thing-type.config.folderwatcher.ftpfolder.ftpDir.label = Root Directory +thing-type.config.folderwatcher.ftpfolder.ftpDir.description = Root directory to be watched +thing-type.config.folderwatcher.ftpfolder.ftpPassword.label = Password +thing-type.config.folderwatcher.ftpfolder.ftpPassword.description = FTP server password +thing-type.config.folderwatcher.ftpfolder.ftpPort.label = FTP Port +thing-type.config.folderwatcher.ftpfolder.ftpPort.description = FTP server's port +thing-type.config.folderwatcher.ftpfolder.ftpUsername.label = Username +thing-type.config.folderwatcher.ftpfolder.ftpUsername.description = User name +thing-type.config.folderwatcher.ftpfolder.listHidden.label = List Hidden +thing-type.config.folderwatcher.ftpfolder.listHidden.description = Allow listing of hidden files +thing-type.config.folderwatcher.ftpfolder.listRecursiveFtp.label = List Sub Folders +thing-type.config.folderwatcher.ftpfolder.listRecursiveFtp.description = Allow listing of sub folders +thing-type.config.folderwatcher.ftpfolder.pollInterval.label = Polling Interval +thing-type.config.folderwatcher.ftpfolder.pollInterval.description = Interval for polling folder changes, sec +thing-type.config.folderwatcher.ftpfolder.secureMode.label = FTP Security +thing-type.config.folderwatcher.ftpfolder.secureMode.description = FTP Security settings +thing-type.config.folderwatcher.ftpfolder.secureMode.option.NONE = None +thing-type.config.folderwatcher.ftpfolder.secureMode.option.IMPLICIT = TLS/SSL Implicit +thing-type.config.folderwatcher.ftpfolder.secureMode.option.EXPLICIT = TLS/SSL Explicit +thing-type.config.folderwatcher.localfolder.listHiddenLocal.label = List Hidden +thing-type.config.folderwatcher.localfolder.listHiddenLocal.description = Allow listing of hidden files +thing-type.config.folderwatcher.localfolder.listRecursiveLocal.label = List Sub Folders +thing-type.config.folderwatcher.localfolder.listRecursiveLocal.description = Allow listing of sub folders +thing-type.config.folderwatcher.localfolder.localDir.label = Local Directory +thing-type.config.folderwatcher.localfolder.localDir.description = Local directory to be watched +thing-type.config.folderwatcher.localfolder.pollIntervalLocal.label = Polling Interval +thing-type.config.folderwatcher.localfolder.pollIntervalLocal.description = Interval for polling folder changes, sec + +# channel types + +channel-type.folderwatcher.newfile-channel.label = New File Name(s) +channel-type.folderwatcher.newfile-channel.description = A new file name diff --git a/bundles/org.openhab.binding.folding/src/main/resources/OH-INF/i18n/folding.properties b/bundles/org.openhab.binding.folding/src/main/resources/OH-INF/i18n/folding.properties new file mode 100644 index 0000000000000..8152b75e0ffad --- /dev/null +++ b/bundles/org.openhab.binding.folding/src/main/resources/OH-INF/i18n/folding.properties @@ -0,0 +1,34 @@ +# binding + +binding.folding.name = Folding@home +binding.folding.description = Control Folding@home clients on computers. + +# thing types + +thing-type.folding.client.label = Client +thing-type.folding.client.description = Folding@home client daemon (represented as bridge). +thing-type.folding.slot.label = Slot +thing-type.folding.slot.description = Folding client compute slot. + +# thing types config + +thing-type.config.folding.client.host.label = Host +thing-type.config.folding.client.host.description = Hostname or IP address +thing-type.config.folding.client.password.label = Password +thing-type.config.folding.client.password.description = Authentication password (leave empty for no p/w). +thing-type.config.folding.client.polling.label = Polling Interval +thing-type.config.folding.client.polling.description = Polling interval in seconds (0=polling disabled). +thing-type.config.folding.client.port.label = Port +thing-type.config.folding.slot.id.label = Slot ID +thing-type.config.folding.slot.id.description = Slot ID, "00", "01", etc. + +# channel types + +channel-type.folding.description.label = Description +channel-type.folding.description.description = Description of the Folding@home slot. +channel-type.folding.finish.label = Finish +channel-type.folding.finish.description = Finish current work then pause. +channel-type.folding.run.label = Run +channel-type.folding.run.description = Slot running. +channel-type.folding.status.label = Status +channel-type.folding.status.description = Current status diff --git a/bundles/org.openhab.binding.foobot/src/main/resources/OH-INF/i18n/foobot.properties b/bundles/org.openhab.binding.foobot/src/main/resources/OH-INF/i18n/foobot.properties new file mode 100644 index 0000000000000..23bf752fcfd0b --- /dev/null +++ b/bundles/org.openhab.binding.foobot/src/main/resources/OH-INF/i18n/foobot.properties @@ -0,0 +1,41 @@ +# binding + +binding.foobot.name = Foobot +binding.foobot.description = Foobot binding allow users to connect to their foobots in home or office and get real-time updates on the Air Quality. + +# thing types + +thing-type.foobot.account.label = Foobot Account +thing-type.foobot.account.description = Your Foobot account. +thing-type.foobot.device.label = Foobot +thing-type.foobot.device.description = A Foobot device. + +# thing types config + +thing-type.config.foobot.account.apiKey.label = API Key +thing-type.config.foobot.account.apiKey.description = You can request your API Key from https://api.foobot.io/apidoc/index.html +thing-type.config.foobot.account.refreshInterval.label = Refresh Interval +thing-type.config.foobot.account.refreshInterval.description = Specifies the refresh interval in minutes. +thing-type.config.foobot.account.username.label = Username +thing-type.config.foobot.account.username.description = The e-mail address you use to login to your Foobot account +thing-type.config.foobot.device.uuid.label = UUID +thing-type.config.foobot.device.uuid.description = The device UUID + +# channel types + +channel-type.foobot.api-key-limit-remaining.label = Remaining Api Limit +channel-type.foobot.api-key-limit-remaining.description = The remaining number of calls that can be made to the api today +channel-type.foobot.co2.label = Carbon Dioxide +channel-type.foobot.co2.description = Carbon dioxide Level +channel-type.foobot.gpi.label = Pollution Index +channel-type.foobot.gpi.description = Global Pollution Index Level +channel-type.foobot.humidity.label = Humidity +channel-type.foobot.humidity.description = Humidity Level +channel-type.foobot.pm.label = Particulate Matter +channel-type.foobot.pm.description = Particulate Matter Level +channel-type.foobot.temperature.label = Temperature +channel-type.foobot.temperature.description = Temperature +channel-type.foobot.time.label = Last Readout +channel-type.foobot.time.description = The last time the sensor data was uploaded to Foobot +channel-type.foobot.voc.label = Volatile Compounds +channel-type.foobot.voc.description = Volatile Organic Compounds Level diff --git a/bundles/org.openhab.binding.freebox/src/main/resources/OH-INF/i18n/freebox.properties b/bundles/org.openhab.binding.freebox/src/main/resources/OH-INF/i18n/freebox.properties new file mode 100644 index 0000000000000..257d17d13791a --- /dev/null +++ b/bundles/org.openhab.binding.freebox/src/main/resources/OH-INF/i18n/freebox.properties @@ -0,0 +1,151 @@ +# binding + +binding.freebox.name = Freebox Binding +binding.freebox.description = The Freebox binding requests your Freebox Server for various operational informations. + +# thing types + +thing-type.freebox.airplay.label = AirPlay Receiver +thing-type.freebox.airplay.description = Provides media control from one AirPlay device +thing-type.freebox.net_device.label = Network Device +thing-type.freebox.net_device.description = Provides network device reachability +thing-type.freebox.net_interface.label = Network Interface +thing-type.freebox.net_interface.description = Provides network interface reachability +thing-type.freebox.phone.label = Phone +thing-type.freebox.phone.description = Provides various informations regarding the phone state and the phone calls +thing-type.freebox.server.label = Freebox Server +thing-type.freebox.server.description = Provides various informations regarding the status of the Freebox Server + +# thing types config + +thing-type.config.freebox.airplay.acceptAllMp3.label = Accept All MP3 +thing-type.config.freebox.airplay.acceptAllMp3.description = Accept any bitrate for MP3 audio or only bitrates greater than 64 kbps +thing-type.config.freebox.airplay.name.label = Name +thing-type.config.freebox.airplay.name.description = Name of the AirPlay device +thing-type.config.freebox.airplay.password.label = Password +thing-type.config.freebox.airplay.password.description = AirPlay password +thing-type.config.freebox.net_device.macAddress.label = MAC Address +thing-type.config.freebox.net_device.macAddress.description = The MAC address of the network device +thing-type.config.freebox.net_interface.ipAddress.label = IP Address +thing-type.config.freebox.net_interface.ipAddress.description = The IP address (v4 or v6) of the network interface +thing-type.config.freebox.phone.refreshPhoneCallsInterval.label = Phone Calls Refresh Interval +thing-type.config.freebox.phone.refreshPhoneCallsInterval.description = The refresh interval in seconds which is used to poll given Freebox Server for phone calls +thing-type.config.freebox.phone.refreshPhoneInterval.label = Phone State Refresh Interval +thing-type.config.freebox.phone.refreshPhoneInterval.description = The refresh interval in seconds which is used to poll given Freebox Server for phone state +thing-type.config.freebox.server.appToken.label = Application Token +thing-type.config.freebox.server.appToken.description = Token generated by the Freebox server +thing-type.config.freebox.server.discoverAirPlayReceiver.label = Enable AirPlay Receiver Discovery +thing-type.config.freebox.server.discoverAirPlayReceiver.description = Enable the discovery of AirPlay receiver things +thing-type.config.freebox.server.discoverNetDevice.label = Enable Network Device Discovery +thing-type.config.freebox.server.discoverNetDevice.description = Enable the discovery of network device things +thing-type.config.freebox.server.discoverNetInterface.label = Enable Network Interface Discovery +thing-type.config.freebox.server.discoverNetInterface.description = Enable the discovery of network interface things +thing-type.config.freebox.server.discoverPhone.label = Enable Phone Discovery +thing-type.config.freebox.server.discoverPhone.description = Enable the discovery of phone things +thing-type.config.freebox.server.fqdn.label = Freebox Server FQDN +thing-type.config.freebox.server.fqdn.description = The IP address / FQDN of the Freebox Server (can include port number) +thing-type.config.freebox.server.refreshInterval.label = Refresh Interval +thing-type.config.freebox.server.refreshInterval.description = The refresh interval in seconds which is used to poll given Freebox Server +thing-type.config.freebox.server.useOnlyHttp.label = Use Only HTTP API +thing-type.config.freebox.server.useOnlyHttp.description = Use HTTP API even if HTTPS is available + +# channel group types + +channel-group-type.freebox.accepted.label = Accepted Call +channel-group-type.freebox.accepted.description = The last accepted phone call +channel-group-type.freebox.any.label = Call +channel-group-type.freebox.any.description = The last phone call +channel-group-type.freebox.missed.label = Missed Call +channel-group-type.freebox.missed.description = The last missed phone call +channel-group-type.freebox.outgoing.label = Outgoing Call +channel-group-type.freebox.outgoing.description = The last outgoing phone call +channel-group-type.freebox.state.label = Phone +channel-group-type.freebox.state.description = The phone state + +# channel types + +channel-type.freebox.airmedia_status.label = Air Media Enabled +channel-type.freebox.airmedia_status.description = Indicates whether Air Media is enabled +channel-type.freebox.bytes_down.label = Downloaded +channel-type.freebox.bytes_down.description = Total downloaded bytes since last connection +channel-type.freebox.bytes_up.label = Uploaded +channel-type.freebox.bytes_up.description = Total uploaded bytes since last connection +channel-type.freebox.call_duration.label = Duration +channel-type.freebox.call_duration.description = Call duration in seconds +channel-type.freebox.call_name.label = Call Name +channel-type.freebox.call_name.description = Called name for outgoing calls. Caller name for incoming calls +channel-type.freebox.call_number.label = Phone Number +channel-type.freebox.call_number.description = Called number for outgoing calls. Caller number for incoming calls +channel-type.freebox.call_status.label = Call Type +channel-type.freebox.call_status.description = Call Type (ingoing, outgoing, missed) +channel-type.freebox.call_status.state.option.ingoing = Ingoing call +channel-type.freebox.call_status.state.option.outgoing = Outgoing call +channel-type.freebox.call_status.state.option.missing = Missed call +channel-type.freebox.call_timestamp.label = Timestamp +channel-type.freebox.call_timestamp.description = Call creation timestamp +channel-type.freebox.called_name.label = Called Name +channel-type.freebox.called_name.description = Called name +channel-type.freebox.called_number.label = Phone Number +channel-type.freebox.called_number.description = Called number +channel-type.freebox.caller_name.label = Caller Name +channel-type.freebox.caller_name.description = Caller name +channel-type.freebox.caller_number.label = Phone Number +channel-type.freebox.caller_number.description = Caller number +channel-type.freebox.fanspeed.label = Fan Speed +channel-type.freebox.fanspeed.description = Actual measured fan speed (rpm) of the Freebox Server +channel-type.freebox.ftp_status.label = FTP Server Enabled +channel-type.freebox.ftp_status.description = Indicates whether the FTP server is enabled +channel-type.freebox.ftth_status.label = FTTH Status +channel-type.freebox.ftth_status.description = Status of the Fiber Optic line +channel-type.freebox.fwversion.label = Firmware Version +channel-type.freebox.fwversion.description = Version of the Freebox Server Firmware +channel-type.freebox.ipv4.label = IP Address +channel-type.freebox.ipv4.description = Public IP Address of the Freebox Server +channel-type.freebox.lcd_brightness.label = Screen Brightness +channel-type.freebox.lcd_brightness.description = Brightness level of the screen in percent +channel-type.freebox.lcd_forced.label = Forced Orientation +channel-type.freebox.lcd_forced.description = Indicates whether the screen orientation forced +channel-type.freebox.lcd_orientation.label = Screen Orientation +channel-type.freebox.lcd_orientation.description = Screen Orientation in degrees +channel-type.freebox.lcd_orientation.state.option.0 = Horizontal +channel-type.freebox.lcd_orientation.state.option.90 = Turned left +channel-type.freebox.lcd_orientation.state.option.180 = Reversed +channel-type.freebox.lcd_orientation.state.option.270 = Turned right +channel-type.freebox.line_status.label = Line Status +channel-type.freebox.line_status.description = Status of network line connexion +channel-type.freebox.onhook.label = On-hook +channel-type.freebox.onhook.description = Indicates whether the phone is on hook +channel-type.freebox.playurl.label = Play Audio or Video URL +channel-type.freebox.playurl.description = Play an audio or video media from the given URL +channel-type.freebox.rate_down.label = Download Rate +channel-type.freebox.rate_down.description = Current download rate in byte/s +channel-type.freebox.rate_up.label = Upload Rate +channel-type.freebox.rate_up.description = Current upload rate in byte/s +channel-type.freebox.reachable.label = Reachable +channel-type.freebox.reachable.description = Indicates whether the network device is reachable +channel-type.freebox.reboot.label = Reboot Freebox +channel-type.freebox.reboot.description = Reboots the Freebox server +channel-type.freebox.restarted.label = Just Restarted +channel-type.freebox.restarted.description = Has the Freebox server have restarted during the last poll period +channel-type.freebox.ringing.label = Ringing +channel-type.freebox.ringing.description = Is the phone ringing +channel-type.freebox.sambafileshare_status.label = Window File Sharing Enabled +channel-type.freebox.sambafileshare_status.description = Indicates whether Window File Sharing is enabled +channel-type.freebox.sambaprintershare_status.label = Window Printer Sharing Enabled +channel-type.freebox.sambaprintershare_status.description = Indicates whether Window Printer Sharing is enabled +channel-type.freebox.stop.label = Stop Playback +channel-type.freebox.stop.description = Stop the media playback +channel-type.freebox.tempcpub.label = CPUb Temperature +channel-type.freebox.tempcpub.description = Actual measured CPU Broadcom (xDSL) temperature of the Freebox Server +channel-type.freebox.tempcpum.label = CPUm Temperature +channel-type.freebox.tempcpum.description = Actual measured CPU Marvell temperature of the Freebox Server +channel-type.freebox.tempswitch.label = Switch Temperature +channel-type.freebox.tempswitch.description = Actual measured switch temperature of the Freebox Server +channel-type.freebox.upnpav_status.label = UPnP AV Enabled +channel-type.freebox.upnpav_status.description = Indicates whether UPnP AV is enabled +channel-type.freebox.uptime.label = Server Uptime +channel-type.freebox.uptime.description = Time since last reboot of the Freebox Server +channel-type.freebox.wifi_status.label = Wifi Enabled +channel-type.freebox.wifi_status.description = Indicates whether the wifi network is enabled +channel-type.freebox.xdsl_status.label = xDSL Status +channel-type.freebox.xdsl_status.description = Status of the xDSL line diff --git a/bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/i18n/fronius.properties b/bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/i18n/fronius.properties new file mode 100644 index 0000000000000..8a605c9cb4b4d --- /dev/null +++ b/bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/i18n/fronius.properties @@ -0,0 +1,89 @@ +# binding + +binding.fronius.name = Fronius Binding +binding.fronius.description = Binding for Fronius inverters. + +# thing types + +thing-type.fronius.bridge.label = Fronius Bridge +thing-type.fronius.bridge.description = A bridge to connect Fronius devices +thing-type.fronius.meter.label = Fronius Smart Meter +thing-type.fronius.meter.description = Fronius Smart Meter +thing-type.fronius.meter.channel.currentacphase1.label = AC Current Phase 1 +thing-type.fronius.meter.channel.currentacphase2.label = AC Current Phase 2 +thing-type.fronius.meter.channel.currentacphase3.label = AC Current Phase 3 +thing-type.fronius.meter.channel.energyrealsumconsumed.label = Real Energy Consumed +thing-type.fronius.meter.channel.energyrealsumproduced.label = Real Energy Produced +thing-type.fronius.meter.channel.powerfactorphase1.label = Power Factor Phase 1 +thing-type.fronius.meter.channel.powerfactorphase2.label = Power Factor Phase 2 +thing-type.fronius.meter.channel.powerfactorphase3.label = Power Factor Phase 3 +thing-type.fronius.meter.channel.powerrealphase1.label = Real Power Phase 1 +thing-type.fronius.meter.channel.powerrealphase2.label = Real Power Phase 2 +thing-type.fronius.meter.channel.powerrealphase3.label = Real Power Phase 3 +thing-type.fronius.meter.channel.voltageacphase1.label = AC Voltage Phase 1 +thing-type.fronius.meter.channel.voltageacphase2.label = AC Voltage Phase 2 +thing-type.fronius.meter.channel.voltageacphase3.label = AC Voltage Phase 3 +thing-type.fronius.powerinverter.label = Fronius Symo Inverter +thing-type.fronius.powerinverter.description = Fronius Symo power inverter +thing-type.fronius.powerinverter.channel.powerflowchannelpakku.label = Charge / Discharge of Battery +thing-type.fronius.powerinverter.channel.powerflowchannelpgrid.label = Grid Power +thing-type.fronius.powerinverter.channel.powerflowchannelppv.label = Current Solar Yield +thing-type.fronius.powerinverter.channel.powerflowinverter1power.label = Power Flow (Inverter 1) +thing-type.fronius.powerinverter.channel.powerflowinverter1soc.label = State of Charge (Inverter 1) + +# thing types config + +thing-type.config.fronius.bridge.hostname.label = Hostname +thing-type.config.fronius.bridge.hostname.description = The hostname or IP address of the Fronius gateway/device +thing-type.config.fronius.bridge.refreshInterval.label = Refresh Interval +thing-type.config.fronius.bridge.refreshInterval.description = Specifies the refresh interval in seconds. +thing-type.config.fronius.meter.deviceId.label = Device ID +thing-type.config.fronius.meter.deviceId.description = Specific device identifier +thing-type.config.fronius.powerinverter.deviceId.label = Device ID +thing-type.config.fronius.powerinverter.deviceId.description = Specific device identifier + +# channel types + +channel-type.fronius.day_energy.label = Day Energy +channel-type.fronius.day_energy.description = Energy generated on current day +channel-type.fronius.devicestatus_errorcode.label = Error Code +channel-type.fronius.devicestatus_errorcode.description = Current device error code +channel-type.fronius.devicestatus_statuscode.label = Status Code +channel-type.fronius.devicestatus_statuscode.description = Current device status code +channel-type.fronius.fac.label = AC Frequency +channel-type.fronius.fac.description = AC frequency +channel-type.fronius.iac.label = AC Current +channel-type.fronius.iac.description = AC current +channel-type.fronius.idc.label = DC Current +channel-type.fronius.idc.description = DC current +channel-type.fronius.inverter1Power.label = Inverter 1 Power +channel-type.fronius.inverter1Power.description = Inverter 1 Power +channel-type.fronius.inverter1Soc.label = Inverter 1 State of Charge +channel-type.fronius.inverter1Soc.description = Inverter 1 State of Charge +channel-type.fronius.meter_ac_current.label = AC Current +channel-type.fronius.meter_ac_voltage.label = AC Voltage +channel-type.fronius.meter_enable.label = Enabled +channel-type.fronius.meter_enable.description = Enabled +channel-type.fronius.meter_energy.label = Energy +channel-type.fronius.meter_location.label = Location +channel-type.fronius.meter_location.description = Meter Location Code +channel-type.fronius.meter_powerfactor.label = Power Factor +channel-type.fronius.meter_powerreal.label = Power +channel-type.fronius.pAkku.label = Battery Power +channel-type.fronius.pAkku.description = Battery Power ( + discharge, - charge ) +channel-type.fronius.pGrid.label = Grid Power +channel-type.fronius.pGrid.description = Grid Power ( + from grid, - to grid ) +channel-type.fronius.pLoad.label = Load Power +channel-type.fronius.pLoad.description = Load Power ( + generator, - consumer ) +channel-type.fronius.pPv.label = Solar Plant Power +channel-type.fronius.pPv.description = Current Solar Plant Power +channel-type.fronius.pac.label = AC Power +channel-type.fronius.pac.description = AC power +channel-type.fronius.total_energy.label = Total Energy +channel-type.fronius.total_energy.description = Energy generated overall +channel-type.fronius.uac.label = AC Voltage +channel-type.fronius.uac.description = AC voltage +channel-type.fronius.udc.label = DC Voltage +channel-type.fronius.udc.description = DC voltage +channel-type.fronius.year_energy.label = Year Energy +channel-type.fronius.year_energy.description = Energy generated in current year diff --git a/bundles/org.openhab.binding.fsinternetradio/src/main/resources/OH-INF/i18n/fsinternetradio.properties b/bundles/org.openhab.binding.fsinternetradio/src/main/resources/OH-INF/i18n/fsinternetradio.properties new file mode 100644 index 0000000000000..3a3a64e93b4ef --- /dev/null +++ b/bundles/org.openhab.binding.fsinternetradio/src/main/resources/OH-INF/i18n/fsinternetradio.properties @@ -0,0 +1,39 @@ +# binding + +binding.fsinternetradio.name = FSInternetRadio Binding +binding.fsinternetradio.description = This is the binding for internet radios based on the Frontier Silicon chipset. + +# thing types + +thing-type.fsinternetradio.radio.label = Internet Radio +thing-type.fsinternetradio.radio.description = An internet radio device based on the Frontier Silicon chipset. + +# thing types config + +thing-type.config.fsinternetradio.radio.ip.label = Network Address +thing-type.config.fsinternetradio.radio.ip.description = The IP address (name or numeric) of the internet radio. +thing-type.config.fsinternetradio.radio.pin.label = Pin +thing-type.config.fsinternetradio.radio.pin.description = The PIN configured in the internet radio (default: 1234). +thing-type.config.fsinternetradio.radio.port.label = Port +thing-type.config.fsinternetradio.radio.port.description = The port of the internet radio (default: 80). +thing-type.config.fsinternetradio.radio.refresh.label = Refresh Interval +thing-type.config.fsinternetradio.radio.refresh.description = Specifies the refresh interval in seconds. + +# channel types + +channel-type.fsinternetradio.mode.label = Mode +channel-type.fsinternetradio.mode.description = The radio mode, e.g. FM radio, internet radio, AUX, etc. +channel-type.fsinternetradio.mute.label = Mute +channel-type.fsinternetradio.mute.description = Mute the radio. +channel-type.fsinternetradio.play-info-name.label = Current Title +channel-type.fsinternetradio.play-info-name.description = The name of the current radio station or track. +channel-type.fsinternetradio.play-info-text.label = Info Text +channel-type.fsinternetradio.play-info-text.description = Additional information e.g. of the current radio station. +channel-type.fsinternetradio.power.label = Power +channel-type.fsinternetradio.power.description = Switch the radio on or off. +channel-type.fsinternetradio.preset.label = Preset +channel-type.fsinternetradio.preset.description = Preset radio stations configured in the radio. +channel-type.fsinternetradio.volume-absolute.label = Volume +channel-type.fsinternetradio.volume-absolute.description = Volume (min=0, max=32). +channel-type.fsinternetradio.volume-percent.label = Volume +channel-type.fsinternetradio.volume-percent.description = Volume (in percent). diff --git a/bundles/org.openhab.binding.ftpupload/src/main/resources/OH-INF/i18n/ftpupload.properties b/bundles/org.openhab.binding.ftpupload/src/main/resources/OH-INF/i18n/ftpupload.properties new file mode 100644 index 0000000000000..2544d19ea9dc3 --- /dev/null +++ b/bundles/org.openhab.binding.ftpupload/src/main/resources/OH-INF/i18n/ftpupload.properties @@ -0,0 +1,38 @@ +# binding + +binding.ftpupload.name = FTP Upload Binding +binding.ftpupload.description = This binding is for receiving files via FTP. + +# binding config + +binding.config.ftpupload.idleTimeout.label = Idle Timeout +binding.config.ftpupload.idleTimeout.description = The number of seconds before an inactive client is disconnected. If this value is set to 0, the idle time is disabled. +binding.config.ftpupload.passivePorts.label = Passive Port Range +binding.config.ftpupload.passivePorts.description = A string of passive ports, can contain a single port (as an integer), multiple ports seperated by commas (e.g. 123,124,125) or ranges of ports, including open ended ranges (e.g. 123-125, 30000-, -1023). Combinations for single ports and ranges is also supported. Empty (default) allows all ports as passive ports. +binding.config.ftpupload.port.label = TCP Port +binding.config.ftpupload.port.description = TCP port of the FTP server + +# thing types + +thing-type.ftpupload.imagereceiver.label = Image Receiver +thing-type.ftpupload.imagereceiver.description = Receive image files via FTP. + +# thing types config + +thing-type.config.ftpupload.imagereceiver.password.label = Password +thing-type.config.ftpupload.imagereceiver.password.description = Password +thing-type.config.ftpupload.imagereceiver.userName.label = User Name +thing-type.config.ftpupload.imagereceiver.userName.description = Username + +# channel types + +channel-type.ftpupload.image-channel.label = Image +channel-type.ftpupload.image-channel.description = Image received via FTP +channel-type.ftpupload.image-received.label = Image File Received Trigger Channel + +# channel types config + +channel-type.config.ftpupload.image-channel.filename.label = Filename +channel-type.config.ftpupload.image-channel.filename.description = Filename to match received files. Supports regular expression patterns. +channel-type.config.ftpupload.image-received.filename.label = Filename +channel-type.config.ftpupload.image-received.filename.description = Filename to match received files. Supports regular expression patterns. diff --git a/bundles/org.openhab.binding.gardena/src/main/resources/OH-INF/i18n/gardena.properties b/bundles/org.openhab.binding.gardena/src/main/resources/OH-INF/i18n/gardena.properties new file mode 100644 index 0000000000000..506d570bbc997 --- /dev/null +++ b/bundles/org.openhab.binding.gardena/src/main/resources/OH-INF/i18n/gardena.properties @@ -0,0 +1,264 @@ +# binding + +binding.gardena.name = Gardena Smart System Binding +binding.gardena.description = This is the binding for Gardena smart system. + +# thing types + +thing-type.gardena.account.label = Gardena Smart System Account +thing-type.gardena.account.description = The Gardena smart system account +thing-type.gardena.irrigation_control.label = Gardena Smart Irrigation Control +thing-type.gardena.irrigation_control.description = Represents a Gardena smart Irrigation Control +thing-type.gardena.irrigation_control.group.valveFive.label = Valve 5 Properties +thing-type.gardena.irrigation_control.group.valveFive_commands.label = Valve 5 Commands +thing-type.gardena.irrigation_control.group.valveFour.label = Valve 4 Properties +thing-type.gardena.irrigation_control.group.valveFour_commands.label = Valve 4 Commands +thing-type.gardena.irrigation_control.group.valveOne.label = Valve 1 Properties +thing-type.gardena.irrigation_control.group.valveOne_commands.label = Valve 1 Commands +thing-type.gardena.irrigation_control.group.valveSix.label = Valve 6 Properties +thing-type.gardena.irrigation_control.group.valveSix_commands.label = Valve 6 Commands +thing-type.gardena.irrigation_control.group.valveThree.label = Valve 3 Properties +thing-type.gardena.irrigation_control.group.valveThree_commands.label = Valve 3 Commands +thing-type.gardena.irrigation_control.group.valveTwo.label = Valve 2 Properties +thing-type.gardena.irrigation_control.group.valveTwo_commands.label = Valve 2 Commands +thing-type.gardena.mower.label = Gardena Smart SILENO Mower +thing-type.gardena.mower.description = Represents any Gardena smart SILENO mower model +thing-type.gardena.power.label = Gardena Smart Power Adapter +thing-type.gardena.power.description = Represents a Gardena smart Power Adapter +thing-type.gardena.pump.label = Gardena Smart Pressure Pump +thing-type.gardena.pump.description = Represents a Gardena smart Pressure Pump +thing-type.gardena.sensor.label = Gardena Smart Sensor +thing-type.gardena.sensor.description = Represents a Gardena smart Sensor +thing-type.gardena.water_control.label = Gardena Smart Water Control +thing-type.gardena.water_control.description = Represents a Gardena smart Water Control + +# thing types config + +thing-type.config.gardena.account.apiKey.label = API Key +thing-type.config.gardena.account.apiKey.description = The Gardena smart system integration API key +thing-type.config.gardena.account.connectionTimeout.label = Connection Timeout +thing-type.config.gardena.account.connectionTimeout.description = The timeout in seconds for connections to Gardena smart system integration API +thing-type.config.gardena.account.email.label = Email +thing-type.config.gardena.account.email.description = Email address for logging in to Gardena smart system +thing-type.config.gardena.account.password.label = Password +thing-type.config.gardena.account.password.description = Password for logging in to Gardena smart system + +# channel group types + +channel-group-type.gardena.commonProperties.label = Common Properties +channel-group-type.gardena.commonProperties.description = Properties that are common across devices +channel-group-type.gardena.commonProperties.channel.batteryLevel_timestamp.label = Battery Level Timestamp +channel-group-type.gardena.commonProperties.channel.batteryState_timestamp.label = Battery State Timestamp +channel-group-type.gardena.commonProperties.channel.lastUpdate_timestamp.label = LastUpdate Timestamp +channel-group-type.gardena.commonProperties.channel.rfLinkLevel_timestamp.label = RF Link Level Timestamp +channel-group-type.gardena.commonProperties.channel.rfLinkState_timestamp.label = RF Link State Timestamp +channel-group-type.gardena.mowerCommands.label = Mower Commands +channel-group-type.gardena.mowerCommands.description = Commands to control a mower +channel-group-type.gardena.mowerCommands.channel.commandDuration.label = Mowing Duration +channel-group-type.gardena.mowerCommands.channel.park_until_further_notice.label = Pause Schedule +channel-group-type.gardena.mowerCommands.channel.park_until_further_notice.description = Cancel the current operation, return to charging station, ignore schedule +channel-group-type.gardena.mowerCommands.channel.park_until_next_task.label = Park +channel-group-type.gardena.mowerCommands.channel.park_until_next_task.description = Cancel the current operation and return to charging station +channel-group-type.gardena.mowerCommands.channel.start_dont_override.label = Start Schedule +channel-group-type.gardena.mowerCommands.channel.start_dont_override.description = Automatic operation +channel-group-type.gardena.mowerCommands.channel.start_seconds_to_override.label = Start Mowing with Duration +channel-group-type.gardena.mowerCommands.channel.start_seconds_to_override.description = Manual operation, use Mowing Duration to define duration +channel-group-type.gardena.mowerProperties.label = Mower Properties +channel-group-type.gardena.mowerProperties.description = Properties of a mower +channel-group-type.gardena.mowerProperties.channel.activity_timestamp.label = Activity Timestamp +channel-group-type.gardena.mowerProperties.channel.lastErrorCode_timestamp.label = Last Error Code Timestamp +channel-group-type.gardena.mowerProperties.channel.state_timestamp.label = State Timestamp +channel-group-type.gardena.powerSocketCommands.label = Power Socket Commands +channel-group-type.gardena.powerSocketCommands.description = Commands to control a power socket +channel-group-type.gardena.powerSocketCommands.channel.commandDuration.label = Switch on Duration +channel-group-type.gardena.powerSocketCommands.channel.pause.label = Pause Until Specified Time +channel-group-type.gardena.powerSocketCommands.channel.pause.description = Skip automatic operation until specified time. The currently active operation will NOT be cancelled +channel-group-type.gardena.powerSocketCommands.channel.start_override.label = Manual On +channel-group-type.gardena.powerSocketCommands.channel.start_override.description = Manual on +channel-group-type.gardena.powerSocketCommands.channel.start_seconds_to_override.label = Manual On with Duration +channel-group-type.gardena.powerSocketCommands.channel.start_seconds_to_override.description = Manual operation, use Switch on Duration to define duration +channel-group-type.gardena.powerSocketCommands.channel.stop_until_next_task.label = Off, Continue Schedule +channel-group-type.gardena.powerSocketCommands.channel.stop_until_next_task.description = Immediately switch off, continue with the schedule +channel-group-type.gardena.powerSocketCommands.channel.unpause.label = Start Schedule +channel-group-type.gardena.powerSocketCommands.channel.unpause.description = Restore automatic operation if it was paused +channel-group-type.gardena.powerSocketProperties.label = Power Socket Properties +channel-group-type.gardena.powerSocketProperties.description = Properties of a power socket +channel-group-type.gardena.powerSocketProperties.channel.activity_timestamp.label = Activity Timestamp +channel-group-type.gardena.powerSocketProperties.channel.duration_timestamp.label = Duration Timestamp +channel-group-type.gardena.powerSocketProperties.channel.lastErrorCode_timestamp.label = Last Error Code Timestamp +channel-group-type.gardena.powerSocketProperties.channel.state_timestamp.label = State Timestamp +channel-group-type.gardena.sensorProperties.label = Sensor Properties +channel-group-type.gardena.sensorProperties.description = Properties of a sensor +channel-group-type.gardena.sensorProperties.channel.ambientTemperature.label = Ambient Temperature +channel-group-type.gardena.sensorProperties.channel.ambientTemperature_timestamp.label = Ambient Temperature Timestamp +channel-group-type.gardena.sensorProperties.channel.lightIntensity_timestamp.label = Light Intensity Timestamp +channel-group-type.gardena.sensorProperties.channel.soilHumidity_timestamp.label = Soil Humidity Timestamp +channel-group-type.gardena.sensorProperties.channel.soilTemperature.label = Soil Temperature +channel-group-type.gardena.sensorProperties.channel.soilTemperature_timestamp.label = Soil Temperature Timestamp +channel-group-type.gardena.valveCommands.label = Valve Commands +channel-group-type.gardena.valveCommands.description = Commands to control a valve +channel-group-type.gardena.valveCommands.channel.commandDuration.label = Irrigation Duration +channel-group-type.gardena.valveCommands.channel.pause.label = Pause Until Specified Time +channel-group-type.gardena.valveCommands.channel.pause.description = Skip automatic operation until specified time. The currently active operation might or might not be cancelled (depends on device model) +channel-group-type.gardena.valveCommands.channel.start_seconds_to_override.label = Open Valve with Duration +channel-group-type.gardena.valveCommands.channel.start_seconds_to_override.description = Manual operation, use Irrigation Duration to define duration +channel-group-type.gardena.valveCommands.channel.stop_until_next_task.label = Close Valve, Continue Schedule +channel-group-type.gardena.valveCommands.channel.stop_until_next_task.description = Cancel the current watering, continue with the schedule +channel-group-type.gardena.valveCommands.channel.unpause.label = Start Schedule +channel-group-type.gardena.valveCommands.channel.unpause.description = Restore automatic operation if it was paused +channel-group-type.gardena.valveProperties.label = Valve Properties +channel-group-type.gardena.valveProperties.description = Properties of a valve +channel-group-type.gardena.valveProperties.channel.activity_timestamp.label = Activity Timestamp +channel-group-type.gardena.valveProperties.channel.lastErrorCode_timestamp.label = Last Error Code Timestamp +channel-group-type.gardena.valveProperties.channel.state_timestamp.label = State Timestamp +channel-group-type.gardena.valveSetCommands.label = Valve Set Commands +channel-group-type.gardena.valveSetCommands.description = Commands to control a valve set +channel-group-type.gardena.valveSetCommands.channel.stop_until_next_task.label = Close All Valves +channel-group-type.gardena.valveSetCommands.channel.stop_until_next_task.description = Immediately close all valves +channel-group-type.gardena.valveSetProperties.label = Valve Set Properties +channel-group-type.gardena.valveSetProperties.description = Properties of a valve set +channel-group-type.gardena.valveSetProperties.channel.lastErrorCode_timestamp.label = Last Error Code Timestamp +channel-group-type.gardena.valveSetProperties.channel.state_timestamp.label = State Timestamp + +# channel types + +channel-type.gardena.activity.label = Activity +channel-type.gardena.activity.description = The activity of the device +channel-type.gardena.activity.state.option.OFF = Off +channel-type.gardena.activity.state.option.FOREVER_ON = Switched on by a manual action, no switch off scheduled +channel-type.gardena.activity.state.option.TIME_LIMITED_ON = Switched on by a manual action, the switch off is scheduled +channel-type.gardena.activity.state.option.SCHEDULED_ON = Operating by schedule, current state is 'on' +channel-type.gardena.activity.state.option.CLOSED = Valve closed +channel-type.gardena.activity.state.option.MANUAL_WATERING = Irrigation active +channel-type.gardena.activity.state.option.SCHEDULED_WATERING = Irrigation active +channel-type.gardena.activity.state.option.PAUSED = In a waiting state with hatch closed +channel-type.gardena.activity.state.option.OK_CUTTING = Mowing +channel-type.gardena.activity.state.option.OK_CUTTING_TIMER_OVERRIDDEN = Mowing +channel-type.gardena.activity.state.option.OK_SEARCHING = Searching charging station +channel-type.gardena.activity.state.option.OK_LEAVING = Leaving charging station +channel-type.gardena.activity.state.option.OK_CHARGING = Charging +channel-type.gardena.activity.state.option.PARKED_TIMER = Parked according to timer +channel-type.gardena.activity.state.option.PARKED_PARK_SELECTED = Parked until further notice +channel-type.gardena.activity.state.option.PARKED_AUTOTIMER = Parked because of insufficient grass height +channel-type.gardena.activity.state.option.NONE = None +channel-type.gardena.batteryState.label = Battery State +channel-type.gardena.batteryState.description = The state of the battery +channel-type.gardena.batteryState.state.option.OK = OK +channel-type.gardena.batteryState.state.option.LOW = Low +channel-type.gardena.batteryState.state.option.REPLACE_NOW = Replace now +channel-type.gardena.batteryState.state.option.OUT_OF_OPERATION = Out of operation +channel-type.gardena.batteryState.state.option.CHARGING = Charging +channel-type.gardena.batteryState.state.option.NO_BATTERY = No battery +channel-type.gardena.batteryState.state.option.UNKNOWN = Unknown +channel-type.gardena.duration.label = Duration +channel-type.gardena.duration.description = Duration in minutes +channel-type.gardena.gardenaCommand.label = Command +channel-type.gardena.gardenaCommand.description = A command for a device +channel-type.gardena.lastErrorCode.label = Last Error Code +channel-type.gardena.lastErrorCode.description = The last error code +channel-type.gardena.lastErrorCode.state.option.UNKNOWN = Unknown +channel-type.gardena.lastErrorCode.state.option.NO_MESSAGE = No Message +channel-type.gardena.lastErrorCode.state.option.OUTSIDE_WORKING_AREA = Outside working area +channel-type.gardena.lastErrorCode.state.option.NO_LOOP_SIGNAL = No loop signal +channel-type.gardena.lastErrorCode.state.option.WRONG_LOOP_SIGNAL = Wrong loop signal +channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_FRONT = Loop sensor problem, front +channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_REAR = Loop sensor problem, rear +channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_LEFT = Loop sensor problem, left +channel-type.gardena.lastErrorCode.state.option.LOOP_SENSOR_PROBLEM_RIGHT = Loop sensor problem, right +channel-type.gardena.lastErrorCode.state.option.WRONG_PIN_CODE = Wrong PIN code +channel-type.gardena.lastErrorCode.state.option.TRAPPED = Trapped +channel-type.gardena.lastErrorCode.state.option.UPSIDE_DOWN = Upside down +channel-type.gardena.lastErrorCode.state.option.EMPTY_BATTERY = Empty battery +channel-type.gardena.lastErrorCode.state.option.NO_DRIVE = No drive +channel-type.gardena.lastErrorCode.state.option.TEMPORARILY_LIFTED = Mower lifted +channel-type.gardena.lastErrorCode.state.option.LIFTED = Lifted +channel-type.gardena.lastErrorCode.state.option.STUCK_IN_CHARGING_STATION = Stuck in charging station +channel-type.gardena.lastErrorCode.state.option.CHARGING_STATION_BLOCKED = Charging station blocked +channel-type.gardena.lastErrorCode.state.option.COLLISION_SENSOR_PROBLEM_REAR = Collision sensor problem, rear +channel-type.gardena.lastErrorCode.state.option.COLLISION_SENSOR_PROBLEM_FRONT = Collision sensor problem, front +channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_BLOCKED_RIGHT = Wheel motor blocked, right +channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_BLOCKED_LEFT = Wheel motor blocked, left +channel-type.gardena.lastErrorCode.state.option.WHEEL_DRIVE_PROBLEM_RIGHT = Wheel drive problem, right +channel-type.gardena.lastErrorCode.state.option.WHEEL_DRIVE_PROBLEM_LEFT = Wheel drive problem, left +channel-type.gardena.lastErrorCode.state.option.CUTTING_MOTOR_DRIVE_DEFECT = Cutting motor drive blocked +channel-type.gardena.lastErrorCode.state.option.CUTTING_SYSTEM_BLOCKED = Cutting system blocked +channel-type.gardena.lastErrorCode.state.option.INVALID_SUB_DEVICE_COMBINATION = Invalid sub-device combination +channel-type.gardena.lastErrorCode.state.option.MEMORY_CIRCUIT_PROBLEM = Memory circuit problem +channel-type.gardena.lastErrorCode.state.option.CHARGING_SYSTEM_PROBLEM = Charging system problem +channel-type.gardena.lastErrorCode.state.option.STOP_BUTTON_PROBLEM = STOP button problem +channel-type.gardena.lastErrorCode.state.option.TILT_SENSOR_PROBLEM = Tilt sensor problem +channel-type.gardena.lastErrorCode.state.option.MOWER_TILTED = Mower tilted +channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_OVERLOADED_RIGHT = Wheel motor overloaded, right +channel-type.gardena.lastErrorCode.state.option.WHEEL_MOTOR_OVERLOADED_LEFT = Wheel motor overloaded, left +channel-type.gardena.lastErrorCode.state.option.CHARGING_CURRENT_TOO_HIGH = Charging current too high +channel-type.gardena.lastErrorCode.state.option.ELECTRONIC_PROBLEM = Electronic problem +channel-type.gardena.lastErrorCode.state.option.CUTTING_MOTOR_PROBLEM = Cutting motor problem +channel-type.gardena.lastErrorCode.state.option.LIMITED_CUTTING_HEIGHT_RANGE = Limited cutting height range +channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_DRIVE = Cutting height problem, drive +channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_CURR = Cutting height problem, current +channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM_DIR = Cutting height problem, direction +channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_BLOCKED = Cutting height blocked +channel-type.gardena.lastErrorCode.state.option.CUTTING_HEIGHT_PROBLEM = Cutting height problem +channel-type.gardena.lastErrorCode.state.option.BATTERY_PROBLEM = Battery problem +channel-type.gardena.lastErrorCode.state.option.TOO_MANY_BATTERIES = Battery problem +channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_SWITCHED_OFF = Alarm! Mower switched off +channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_STOPPED = Alarm! Mower stopped +channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_LIFTED = Alarm! Mower lifted +channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_TILTED = Alarm! Mower tilted +channel-type.gardena.lastErrorCode.state.option.ALARM_MOWER_IN_MOTION = Alarm! Mower in motion +channel-type.gardena.lastErrorCode.state.option.ALARM_OUTSIDE_GEOFENCE = Alarm! Outside geofence +channel-type.gardena.lastErrorCode.state.option.SLIPPED = Mower has slipped +channel-type.gardena.lastErrorCode.state.option.INVALID_BATTERY_COMBINATION = Invalid battery combination +channel-type.gardena.lastErrorCode.state.option.UNINITIALISED = Unknown status of the mower +channel-type.gardena.lastErrorCode.state.option.WAIT_UPDATING = Mower waiting, updating firmware +channel-type.gardena.lastErrorCode.state.option.WAIT_POWER_UP = Mower powering up +channel-type.gardena.lastErrorCode.state.option.OFF_DISABLED = Mower disabled on main switch +channel-type.gardena.lastErrorCode.state.option.OFF_HATCH_OPEN = Mower in waiting state with hatch open +channel-type.gardena.lastErrorCode.state.option.OFF_HATCH_CLOSED = Mower in waiting state with hatch closed +channel-type.gardena.lastErrorCode.state.option.PARKED_DAILY_LIMIT_REACHED = Mower has completed cutting due to daily limit reached +channel-type.gardena.lastErrorCode.state.option.TIMER_CANCELLED = Time cancelled +channel-type.gardena.lastErrorCode.state.option.CONCURRENT_LIMIT_REACHED = Can't open valve because at most 2 valves can be open at the same time +channel-type.gardena.lastErrorCode.state.option.NOT_CONNECTED = No valve was connected +channel-type.gardena.lastErrorCode.state.option.VALVE_CURRENT_MAX_EXCEEDED = The valve has been closed because the valve is draining more current than allowed +channel-type.gardena.lastErrorCode.state.option.TOTAL_CURRENT_MAX_EXCEEDED = The valve has been closed because the total current used was more than the allowed maximum +channel-type.gardena.lastErrorCode.state.option.WATERING_CANCELED = Watering was canceled +channel-type.gardena.lastErrorCode.state.option.MASTER_VALVE = Master valve is not connected +channel-type.gardena.lastErrorCode.state.option.WATERING_DURATION_TOO_SHORT = Watering duration to short +channel-type.gardena.lastErrorCode.state.option.VALVE_BROKEN = Electrical connection to the valve is broken, or the inductor is damaged +channel-type.gardena.lastErrorCode.state.option.FROST_PREVENTS_STARTING = Because of frost valve stays closed +channel-type.gardena.lastErrorCode.state.option.LOW_BATTERY_PREVENTS_STARTING = Because of low battery valve stays closed +channel-type.gardena.lastErrorCode.state.option.VALVE_POWER_SUPPLY_FAILED = Power supply failed +channel-type.gardena.lastErrorCode.state.option.VOLTAGE_DROP = A voltage drop was detected at the power supply +channel-type.gardena.lastErrorCode.state.option.WRONG_POWER_SUPPLY = Wrong power supply is connected +channel-type.gardena.lastErrorCode.state.option.NO_MCU_CONNECTION = Unable to communicate with secondary MCU +channel-type.gardena.lightIntensity.label = Light Intensity +channel-type.gardena.lightIntensity.description = Light intensity in Lux +channel-type.gardena.mowerCommandDuration.label = Command Duration +channel-type.gardena.mowerCommandDuration.description = A duration in minutes for a command +channel-type.gardena.name.label = Name +channel-type.gardena.name.description = The name of the device +channel-type.gardena.operatingHours.label = Operating Hours +channel-type.gardena.operatingHours.description = The operating hours +channel-type.gardena.powerCommandDuration.label = Command Duration +channel-type.gardena.powerCommandDuration.description = A duration in minutes for a command +channel-type.gardena.rfLinkState.label = RF Link State +channel-type.gardena.rfLinkState.description = The state of the RF link +channel-type.gardena.rfLinkState.state.option.ONLINE = Online +channel-type.gardena.rfLinkState.state.option.OFFLINE = Offline +channel-type.gardena.rfLinkState.state.option.UNKNOWN = Unknown +channel-type.gardena.soilHumidity.label = Soil Humidity +channel-type.gardena.soilHumidity.description = Soil humidity in percent +channel-type.gardena.state.label = State +channel-type.gardena.state.description = The state of the device +channel-type.gardena.state.state.option.OK = OK +channel-type.gardena.state.state.option.WARNING = Warning +channel-type.gardena.state.state.option.ERROR = Error +channel-type.gardena.state.state.option.UNAVAILABLE = Unavailable +channel-type.gardena.temperature.label = Temperature +channel-type.gardena.temperature.description = The temperature +channel-type.gardena.timestamp.label = Timestamp +channel-type.gardena.timestamp.description = Timestamp +channel-type.gardena.timestampRefresh.label = Timestamp +channel-type.gardena.timestampRefresh.description = Timestamp +channel-type.gardena.valveCommandDuration.label = Command Duration +channel-type.gardena.valveCommandDuration.description = A duration in minutes for a command diff --git a/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/i18n/generacmobilelink.properties b/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/i18n/generacmobilelink.properties new file mode 100644 index 0000000000000..8bb93ed20eca7 --- /dev/null +++ b/bundles/org.openhab.binding.generacmobilelink/src/main/resources/OH-INF/i18n/generacmobilelink.properties @@ -0,0 +1,39 @@ +# binding + +binding.generacmobilelink.name = GeneracMobileLink Binding +binding.generacmobilelink.description = This binding monitors Generac manufactured generators through the MobileLink cloud service. + +# thing types + +thing-type.generacmobilelink.account.label = MobileLink Account +thing-type.generacmobilelink.account.description = MobileLink Cloud Account +thing-type.generacmobilelink.generator.label = MobileLink Generator +thing-type.generacmobilelink.generator.description = MobileLink Generator + +# thing types config + +thing-type.config.generacmobilelink.account.password.label = Password +thing-type.config.generacmobilelink.account.password.description = Account password +thing-type.config.generacmobilelink.account.refreshInterval.label = Refresh Interval +thing-type.config.generacmobilelink.account.refreshInterval.description = Specifies the refresh interval in seconds +thing-type.config.generacmobilelink.account.username.label = Username +thing-type.config.generacmobilelink.account.username.description = Account username +thing-type.config.generacmobilelink.generator.generatorId.label = Generator ID +thing-type.config.generacmobilelink.generator.generatorId.description = Generator ID + +# channel types + +channel-type.generacmobilelink.batteryVoltage.label = Battery Voltage Status +channel-type.generacmobilelink.blueLight.label = Blue Light Status +channel-type.generacmobilelink.connected.label = Connected +channel-type.generacmobilelink.currentAlarmDescription.label = Current Alarm Description +channel-type.generacmobilelink.exerciseHours.label = Number of Hours Exercised +channel-type.generacmobilelink.fuelLevel.label = Fuel Level +channel-type.generacmobilelink.fuelType.label = Fuel Type +channel-type.generacmobilelink.greenLight.label = Green Light Status +channel-type.generacmobilelink.redLight.label = Red Light Status +channel-type.generacmobilelink.runHours.label = Number of Hours Run +channel-type.generacmobilelink.serviceStatus.label = Service Status +channel-type.generacmobilelink.status.label = Status +channel-type.generacmobilelink.statusDate.label = Last Status Date +channel-type.generacmobilelink.yellowLight.label = Yellow Light Status diff --git a/bundles/org.openhab.binding.globalcache/src/main/resources/OH-INF/i18n/globalcache.properties b/bundles/org.openhab.binding.globalcache/src/main/resources/OH-INF/i18n/globalcache.properties new file mode 100644 index 0000000000000..3f31c39567e3f --- /dev/null +++ b/bundles/org.openhab.binding.globalcache/src/main/resources/OH-INF/i18n/globalcache.properties @@ -0,0 +1,159 @@ +# binding + +binding.globalcache.name = GlobalCache Binding +binding.globalcache.description = Binding for GlobalCache iTach and GC-100 devices supporting infrared, serial, and contact closure interfaces. + +# thing types + +thing-type.globalcache.gc100_06.label = GlobalCache GC-100-06 +thing-type.globalcache.gc100_06.description = GC-100-06 Infrared and Serial Device +thing-type.globalcache.gc100_12.label = GlobalCache GC-100-12 +thing-type.globalcache.gc100_12.description = GC-100-12 Infrared, Serial, and Contact Closure Device +thing-type.globalcache.itachCC.label = GlobalCache iTach CC +thing-type.globalcache.itachCC.description = iTach Contact Closure Device (WF2CC or IP2CC) +thing-type.globalcache.itachFlex.label = GlobalCache iTach Flex +thing-type.globalcache.itachFlex.description = iTach Flex Device +thing-type.globalcache.itachIR.label = GlobalCache iTach IR +thing-type.globalcache.itachIR.description = iTach Infrared Device (WF2IR or IP2IR) +thing-type.globalcache.itachSL.label = GlobalCache iTach SL +thing-type.globalcache.itachSL.description = iTach Serial Device (WF2SL or IP2SL) +thing-type.globalcache.zmote.label = Zmote IR +thing-type.globalcache.zmote.description = Zmote Infrared Device + +# thing types config + +thing-type.config.globalcache.gc100_06.enableTwoWay1.label = Enable Two Way +thing-type.config.globalcache.gc100_06.enableTwoWay1.description = Enable two-way serial communication +thing-type.config.globalcache.gc100_06.eomDelimiter1.label = End-of-message Delimiter +thing-type.config.globalcache.gc100_06.eomDelimiter1.description = URL encoded end-of-message delimiter string for receiving messages +thing-type.config.globalcache.gc100_06.ipAddress.label = Network Address +thing-type.config.globalcache.gc100_06.ipAddress.description = Enter the IP address of the iTach CC device +thing-type.config.globalcache.gc100_06.mapFilename.label = Map File +thing-type.config.globalcache.gc100_06.mapFilename.description = Enter name of file containing mapping of commands to IR and Serial codes +thing-type.config.globalcache.gc100_12.enableTwoWay1.label = Enable Two Way Port 1 +thing-type.config.globalcache.gc100_12.enableTwoWay1.description = Enable two-way serial communication on serial port 1 +thing-type.config.globalcache.gc100_12.enableTwoWay2.label = Enable Two Way Port 2 +thing-type.config.globalcache.gc100_12.enableTwoWay2.description = Enable two-way serial communication on serial port 2 +thing-type.config.globalcache.gc100_12.eomDelimiter1.label = End-of-message Delimiter Port 1 +thing-type.config.globalcache.gc100_12.eomDelimiter1.description = URL encoded end-of-message delimiter string for receiving messages on serial port 1 +thing-type.config.globalcache.gc100_12.eomDelimiter2.label = End-of-message Delimiter Port 2 +thing-type.config.globalcache.gc100_12.eomDelimiter2.description = URL encoded end-of-message delimiter string for receiving messages on serial port 2 +thing-type.config.globalcache.gc100_12.ipAddress.label = Network Address +thing-type.config.globalcache.gc100_12.ipAddress.description = Enter the IP address of the iTach CC device +thing-type.config.globalcache.gc100_12.mapFilename.label = Map File +thing-type.config.globalcache.gc100_12.mapFilename.description = Enter name of file containing mapping of commands to IR and Serial codes +thing-type.config.globalcache.itachCC.ipAddress.label = Network Address +thing-type.config.globalcache.itachCC.ipAddress.description = Enter the IP address of the iTach CC device +thing-type.config.globalcache.itachFlex.activeCable.label = Active Cable +thing-type.config.globalcache.itachFlex.activeCable.description = This setting should match the Current Active Cable in the Flex configuration +thing-type.config.globalcache.itachFlex.activeCable.option.FLEX_INFRARED = Infrared +thing-type.config.globalcache.itachFlex.activeCable.option.FLEX_SERIAL = Serial +thing-type.config.globalcache.itachFlex.activeCable.option.FLEX_RELAY = Relay/Sensor +thing-type.config.globalcache.itachFlex.enableTwoWay1.label = Enable Two Way +thing-type.config.globalcache.itachFlex.enableTwoWay1.description = Enable two-way serial communication +thing-type.config.globalcache.itachFlex.eomDelimiter1.label = End-of-message Delimiter +thing-type.config.globalcache.itachFlex.eomDelimiter1.description = URL encoded end-of-message delimiter string for receiving messages +thing-type.config.globalcache.itachFlex.ipAddress.label = Network Address +thing-type.config.globalcache.itachFlex.ipAddress.description = Enter the IP address of the iTach Flex device +thing-type.config.globalcache.itachFlex.mapFilename.label = Map File +thing-type.config.globalcache.itachFlex.mapFilename.description = Enter name of file containing mapping of commands to IR and Serial codes +thing-type.config.globalcache.itachIR.ipAddress.label = Network Address +thing-type.config.globalcache.itachIR.ipAddress.description = Enter the IP address of the iTach IR device +thing-type.config.globalcache.itachIR.mapFilename.label = Map File +thing-type.config.globalcache.itachIR.mapFilename.description = Enter name of file containing mapping of commands to IR and Serial codes +thing-type.config.globalcache.itachSL.enableTwoWay1.label = Enable Two Way +thing-type.config.globalcache.itachSL.enableTwoWay1.description = Enable two-way serial communication +thing-type.config.globalcache.itachSL.eomDelimiter1.label = End-of-message Delimiter +thing-type.config.globalcache.itachSL.eomDelimiter1.description = URL encoded end-of-message delimiter string for receiving messages +thing-type.config.globalcache.itachSL.ipAddress.label = Network Address +thing-type.config.globalcache.itachSL.ipAddress.description = Enter the IP address of the iTach SL device +thing-type.config.globalcache.itachSL.mapFilename.label = Map File +thing-type.config.globalcache.itachSL.mapFilename.description = Enter namer of file containing mapping of commands to IR and Serial codes +thing-type.config.globalcache.zmote.ipAddress.label = Network Address +thing-type.config.globalcache.zmote.ipAddress.description = Enter the IP address of the Zmote device +thing-type.config.globalcache.zmote.mapFilename.label = Map File +thing-type.config.globalcache.zmote.mapFilename.description = Enter name of file containing mapping of commands to IR codes + +# channel group types + +channel-group-type.globalcache.cc-m1.label = Module 1 +channel-group-type.globalcache.cc-m1.description = Contact Closure Module +channel-group-type.globalcache.cc-m1.channel.c1.label = Connector 1 +channel-group-type.globalcache.cc-m1.channel.c1.description = Contact closure on connector 1. +channel-group-type.globalcache.cc-m1.channel.c2.label = Connector 2 +channel-group-type.globalcache.cc-m1.channel.c2.description = Contact closure on connector 2. +channel-group-type.globalcache.cc-m1.channel.c3.label = Connector 3 +channel-group-type.globalcache.cc-m1.channel.c3.description = Contact closure on connector 3. +channel-group-type.globalcache.cc-m3.label = Module 3 +channel-group-type.globalcache.cc-m3.description = Contact Closure Module +channel-group-type.globalcache.cc-m3.channel.c1.label = Connector 1 +channel-group-type.globalcache.cc-m3.channel.c1.description = Contact closure on connector 1. +channel-group-type.globalcache.cc-m3.channel.c2.label = Connector 2 +channel-group-type.globalcache.cc-m3.channel.c2.description = Contact closure on connector 2. +channel-group-type.globalcache.cc-m3.channel.c3.label = Connector 3 +channel-group-type.globalcache.cc-m3.channel.c3.description = Contact closure on connector 3. +channel-group-type.globalcache.ir-m1-c1.label = Module 1 +channel-group-type.globalcache.ir-m1-c1.description = Infrared Module +channel-group-type.globalcache.ir-m1-c1.channel.c1.label = Connector 1 +channel-group-type.globalcache.ir-m1-c1.channel.c1.description = ZMote infrared emitter. +channel-group-type.globalcache.ir-m1.label = Module 1 +channel-group-type.globalcache.ir-m1.description = Infrared Module +channel-group-type.globalcache.ir-m1.channel.c1.label = Connector 1 +channel-group-type.globalcache.ir-m1.channel.c1.description = Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug. +channel-group-type.globalcache.ir-m1.channel.c2.label = Connector 2 +channel-group-type.globalcache.ir-m1.channel.c2.description = Infrared emitter on connector 2. +channel-group-type.globalcache.ir-m1.channel.c3.label = Connector 3 +channel-group-type.globalcache.ir-m1.channel.c3.description = Infrared emitter/blaster on connector 3. +channel-group-type.globalcache.ir-m2.label = Module 2 +channel-group-type.globalcache.ir-m2.description = Infrared Module +channel-group-type.globalcache.ir-m2.channel.c1.label = Connector 1 +channel-group-type.globalcache.ir-m2.channel.c1.description = Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug. +channel-group-type.globalcache.ir-m2.channel.c2.label = Connector 2 +channel-group-type.globalcache.ir-m2.channel.c2.description = Infrared emitter on connector 2. +channel-group-type.globalcache.ir-m2.channel.c3.label = Connector 3 +channel-group-type.globalcache.ir-m2.channel.c3.description = Infrared emitter/blaster on connector 3. +channel-group-type.globalcache.ir-m4.label = Module 4 +channel-group-type.globalcache.ir-m4.description = Infrared Module +channel-group-type.globalcache.ir-m4.channel.c1.label = Connector 1 +channel-group-type.globalcache.ir-m4.channel.c1.description = Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug. +channel-group-type.globalcache.ir-m4.channel.c2.label = Connector 2 +channel-group-type.globalcache.ir-m4.channel.c2.description = Infrared emitter on connector 2. +channel-group-type.globalcache.ir-m4.channel.c3.label = Connector 3 +channel-group-type.globalcache.ir-m4.channel.c3.description = Infrared emitter/blaster on connector 3. +channel-group-type.globalcache.ir-m5.label = Module 5 +channel-group-type.globalcache.ir-m5.description = Infrared Module +channel-group-type.globalcache.ir-m5.channel.c1.label = Connector 1 +channel-group-type.globalcache.ir-m5.channel.c1.description = Infrared emitter on connector 1. Connector 1 is the connector closest to the power plug. +channel-group-type.globalcache.ir-m5.channel.c2.label = Connector 2 +channel-group-type.globalcache.ir-m5.channel.c2.description = Infrared emitter on connector 2. +channel-group-type.globalcache.ir-m5.channel.c3.label = Connector 3 +channel-group-type.globalcache.ir-m5.channel.c3.description = Infrared emitter/blaster on connector 3. +channel-group-type.globalcache.sl-m1.label = Module 1 +channel-group-type.globalcache.sl-m1.description = Serial Module +channel-group-type.globalcache.sl-m1.channel.c1.label = Connector 1 (mapped) +channel-group-type.globalcache.sl-m1.channel.c1.description = Mapped commands to serial port +channel-group-type.globalcache.sl-m1.channel.c1-direct.label = Connector 1 (direct) +channel-group-type.globalcache.sl-m1.channel.c1-direct.description = Direct commands to serial port +channel-group-type.globalcache.sl-m1.channel.c1-receive.label = Connector 1 (receive) +channel-group-type.globalcache.sl-m1.channel.c1-receive.description = Data received on serial port +channel-group-type.globalcache.sl-m2.label = Module 2 +channel-group-type.globalcache.sl-m2.description = Serial Module +channel-group-type.globalcache.sl-m2.channel.c1.label = Connector 1 (mapped) +channel-group-type.globalcache.sl-m2.channel.c1.description = Mapped commands to serial port +channel-group-type.globalcache.sl-m2.channel.c1-direct.label = Connector 1 (direct) +channel-group-type.globalcache.sl-m2.channel.c1-direct.description = Direct commands to serial port +channel-group-type.globalcache.sl-m2.channel.c1-receive.label = Connector 1 (receive) +channel-group-type.globalcache.sl-m2.channel.c1-receive.description = Data received on serial port + +# channel types + +channel-type.globalcache.channel-type-cc.label = Contact Closure +channel-type.globalcache.channel-type-cc.description = Transmits contact closure command on module:connector +channel-type.globalcache.channel-type-ir.label = Infrared +channel-type.globalcache.channel-type-ir.description = Transmits infrared command on module:connector +channel-type.globalcache.channel-type-sl-direct.label = Serial +channel-type.globalcache.channel-type-sl-direct.description = Transmits serial command on module:connector bypassing MAP transform +channel-type.globalcache.channel-type-sl-receive.label = Serial Receive +channel-type.globalcache.channel-type-sl-receive.description = Data received on the serial port from the device +channel-type.globalcache.channel-type-sl.label = Serial +channel-type.globalcache.channel-type-sl.description = Transmits serial command on module:connector diff --git a/bundles/org.openhab.binding.goecharger/src/main/resources/OH-INF/i18n/goecharger.properties b/bundles/org.openhab.binding.goecharger/src/main/resources/OH-INF/i18n/goecharger.properties new file mode 100644 index 0000000000000..01e424a126059 --- /dev/null +++ b/bundles/org.openhab.binding.goecharger/src/main/resources/OH-INF/i18n/goecharger.properties @@ -0,0 +1,73 @@ +# binding + +binding.goecharger.name = Go-eCharger Binding +binding.goecharger.description = This is the binding for Go-eCharger. + +# thing types + +thing-type.goecharger.goe.label = Go-eCharger +thing-type.goecharger.goe.description = Go-eCharger thing that represents the wallbox configuration and readings + +# thing types config + +thing-type.config.goecharger.goe.ip.label = IP Address +thing-type.config.goecharger.goe.ip.description = The IP address of the Go-eCharger +thing-type.config.goecharger.goe.refreshInterval.label = Refresh Interval +thing-type.config.goecharger.goe.refreshInterval.description = Refresh interval for acquiring data from Go-eCharger in seconds + +# channel types + +channel-type.goecharger.alw.label = Allow Charging +channel-type.goecharger.alw.description = If true charging is allowed +channel-type.goecharger.ast.label = Access Configuration +channel-type.goecharger.ast.description = Currently set access configuration of the Go-eCharger +channel-type.goecharger.ast.state.option.OPEN = Open +channel-type.goecharger.ast.state.option.RFID = RFID +channel-type.goecharger.ast.state.option.TIMER = Timer +channel-type.goecharger.ast.state.option.AWATTAR = aWATTar +channel-type.goecharger.cbl.label = Cable Encoding +channel-type.goecharger.cbl.description = Specifies the max amps that can be charged with that cable +channel-type.goecharger.cl1.label = Current L1 +channel-type.goecharger.cl1.description = Current on L1 +channel-type.goecharger.cl2.label = Current L2 +channel-type.goecharger.cl2.description = Current on L2 +channel-type.goecharger.cl3.label = Current L3 +channel-type.goecharger.cl3.description = Current on L3 +channel-type.goecharger.current.label = Maximum Current +channel-type.goecharger.current.description = Maximum current per phase allowed to use for charging +channel-type.goecharger.err.label = Error Code +channel-type.goecharger.err.description = Error code of Go-eCharger +channel-type.goecharger.err.state.option.NONE = None +channel-type.goecharger.err.state.option.RCCB = RCCB +channel-type.goecharger.err.state.option.NO_GROUND = No ground +channel-type.goecharger.err.state.option.INTERNAL = Internal +channel-type.goecharger.eto.label = Total Charged Energy +channel-type.goecharger.eto.description = Amount of energy that has been charged since installation +channel-type.goecharger.fmw.label = Firmware +channel-type.goecharger.fmw.description = Firmware Version +channel-type.goecharger.pha.label = Phases +channel-type.goecharger.pha.description = Amount of phases currently used for charging +channel-type.goecharger.pl1.label = Power L1 +channel-type.goecharger.pl1.description = Power on L1 +channel-type.goecharger.pl2.label = Power L2 +channel-type.goecharger.pl2.description = Power on L2 +channel-type.goecharger.pl3.label = Power L3 +channel-type.goecharger.pl3.description = Power on L3 +channel-type.goecharger.pwm.label = PWM signal status +channel-type.goecharger.pwm.description = Pulse-width modulation signal status +channel-type.goecharger.pwm.state.option.READY_NO_CAR = Ready (no car) +channel-type.goecharger.pwm.state.option.CHARGING = Charging +channel-type.goecharger.pwm.state.option.WAITING_FOR_CAR = Waiting for car +channel-type.goecharger.pwm.state.option.CHARGING_DONE_CAR_CONNECTED = Charging done (car connected) +channel-type.goecharger.scl.label = Current Session Charge Energy Limit +channel-type.goecharger.scl.description = Wallbox stops charging after defined value, deactivate with value 0 +channel-type.goecharger.scs.label = Current Session Charged Energy +channel-type.goecharger.scs.description = Amount of energy that has been charged in this session +channel-type.goecharger.tmp.label = Temperature +channel-type.goecharger.tmp.description = Temperature of the Go-eCharger +channel-type.goecharger.vl1.label = Voltage L1 +channel-type.goecharger.vl1.description = Voltage on L1 +channel-type.goecharger.vl2.label = Voltage L2 +channel-type.goecharger.vl2.description = Voltage on L2 +channel-type.goecharger.vl3.label = Voltage L3 +channel-type.goecharger.vl3.description = Voltage on L3 diff --git a/bundles/org.openhab.binding.gpio/src/main/resources/OH-INF/i18n/gpio.properties b/bundles/org.openhab.binding.gpio/src/main/resources/OH-INF/i18n/gpio.properties new file mode 100644 index 0000000000000..6d8dc3cebc22f --- /dev/null +++ b/bundles/org.openhab.binding.gpio/src/main/resources/OH-INF/i18n/gpio.properties @@ -0,0 +1,39 @@ +# binding + +binding.gpio.name = GPIO Binding +binding.gpio.description = Adds GPIO support to openHAB. + +# thing types + +thing-type.gpio.pigpio-remote.label = Pigpio Remote +thing-type.gpio.pigpio-remote.description = The remote pigpio thing represents a remote raspberry pi with pigpio installed. Pins are channels. + +# thing types config + +thing-type.config.gpio.pigpio-remote.host.label = Network Address +thing-type.config.gpio.pigpio-remote.host.description = Network address of the Raspberry Pi. +thing-type.config.gpio.pigpio-remote.port.label = Port +thing-type.config.gpio.pigpio-remote.port.description = Port of pigpio on the remote Raspberry Pi. + +# channel types + +channel-type.gpio.pigpio-digital-input.label = GPIO Digital Input +channel-type.gpio.pigpio-digital-input.description = Get digital state of a GPIO Pin +channel-type.gpio.pigpio-digital-output.label = GPIO Digital Output +channel-type.gpio.pigpio-digital-output.description = Set digital state of a GPIO Pin + +# channel types config + +channel-type.config.gpio.pigpio-digital-input.debouncingTime.label = Delay Time +channel-type.config.gpio.pigpio-digital-input.debouncingTime.description = Time in ms to double check if value hasn't changed +channel-type.config.gpio.pigpio-digital-input.gpioId.label = GPIO Pin +channel-type.config.gpio.pigpio-digital-input.gpioId.description = GPIO pin to use as input +channel-type.config.gpio.pigpio-digital-input.invert.label = Invert +channel-type.config.gpio.pigpio-digital-input.pullupdown.label = Pull Up/Down Resistor +channel-type.config.gpio.pigpio-digital-input.pullupdown.description = Configure Pull Up/Down Resistor of GPIO pin +channel-type.config.gpio.pigpio-digital-input.pullupdown.option.OFF = Off +channel-type.config.gpio.pigpio-digital-input.pullupdown.option.DOWN = Pull Down +channel-type.config.gpio.pigpio-digital-input.pullupdown.option.UP = Pull Up +channel-type.config.gpio.pigpio-digital-output.gpioId.label = GPIO Pin +channel-type.config.gpio.pigpio-digital-output.gpioId.description = GPIO pin to use as output +channel-type.config.gpio.pigpio-digital-output.invert.label = Invert diff --git a/bundles/org.openhab.binding.gpstracker/src/main/resources/OH-INF/i18n/gpstracker.properties b/bundles/org.openhab.binding.gpstracker/src/main/resources/OH-INF/i18n/gpstracker.properties new file mode 100644 index 0000000000000..4ece0eb41c17f --- /dev/null +++ b/bundles/org.openhab.binding.gpstracker/src/main/resources/OH-INF/i18n/gpstracker.properties @@ -0,0 +1,37 @@ +# binding + +binding.gpstracker.name = GPSTracker Binding +binding.gpstracker.description = GPS tracking with OwnTracks and GPSLogger support over HTTP + +# thing types + +thing-type.gpstracker.tracker.label = Tracker Device +thing-type.gpstracker.tracker.description = Device running tracker application + +# thing types config + +thing-type.config.gpstracker.tracker.trackerId.label = Tracker Id +thing-type.config.gpstracker.tracker.trackerId.description = Id configured in tracker application. + +# channel types + +channel-type.gpstracker.gpsAccuracy.label = Accuracy +channel-type.gpstracker.gpsAccuracy.description = GPS accuracy +channel-type.gpstracker.lastReport.label = Last Seen +channel-type.gpstracker.lastReport.description = Last report timestamp +channel-type.gpstracker.lastReport.state.pattern = %1$tF %1$tR +channel-type.gpstracker.regionDistance.label = Distance +channel-type.gpstracker.regionDistance.description = Distance from region +channel-type.gpstracker.regionTrigger.label = Region Trigger +channel-type.gpstracker.regionTrigger.description = Trigger channel for entering/leaving regions. Payload is the region name with prefix > for entering and < for leaving. + +# channel types config + +channel-type.config.gpstracker.distance.accuracyThreshold.label = Accuracy Threshold +channel-type.config.gpstracker.distance.accuracyThreshold.description = Location accuracy threshold in m or yd (0 to disable) +channel-type.config.gpstracker.distance.regionCenterLocation.label = Region Center +channel-type.config.gpstracker.distance.regionCenterLocation.description = Location of the region center +channel-type.config.gpstracker.distance.regionName.label = Region Name +channel-type.config.gpstracker.distance.regionName.description = Region name payload for trigger channel event +channel-type.config.gpstracker.distance.regionRadius.label = Region Radius +channel-type.config.gpstracker.distance.regionRadius.description = Region circle radius in m or yd diff --git a/bundles/org.openhab.binding.groheondus/src/main/resources/OH-INF/i18n/groheondus.properties b/bundles/org.openhab.binding.groheondus/src/main/resources/OH-INF/i18n/groheondus.properties new file mode 100644 index 0000000000000..4bebfcd913a0d --- /dev/null +++ b/bundles/org.openhab.binding.groheondus/src/main/resources/OH-INF/i18n/groheondus.properties @@ -0,0 +1,58 @@ +# binding + +binding.groheondus.name = GROHE ONDUS Binding +binding.groheondus.description = Provides an integration for GROHE Appliances in openHAB + +# thing types + +thing-type.groheondus.account.label = GROHE ONDUS Account +thing-type.groheondus.account.description = This is an interface to the GROHE ONDUS Account as it is used by the app. If username and password are not set, you can configure to use a `refreshToken` to login. Read the README to get more info. +thing-type.groheondus.sense.label = GROHE SENSE Appliance +thing-type.groheondus.sense.description = A SENSE device +thing-type.groheondus.senseguard.label = GROHE SENSE GUARD Appliance +thing-type.groheondus.senseguard.description = A SENSE GUARD device + +# thing types config + +thing-type.config.groheondus.account.password.label = Password +thing-type.config.groheondus.account.password.description = Password as used in the GROHE ONDUS App. +thing-type.config.groheondus.account.username.label = Username +thing-type.config.groheondus.account.username.description = Username as used in the GROHE ONDUS App, usually your e-mail address. +thing-type.config.groheondus.sense.applianceId.label = Appliance ID +thing-type.config.groheondus.sense.applianceId.description = The UUID of the appliance as retrieved from the GROHE ONDUS API. +thing-type.config.groheondus.sense.locationId.label = Location ID +thing-type.config.groheondus.sense.locationId.description = The ID of the location the room is in as retrieved from the GROHE ONDUS API. +thing-type.config.groheondus.sense.pollingInterval.label = Polling Interval +thing-type.config.groheondus.sense.pollingInterval.description = The interval in seconds used to poll the API for new data. +thing-type.config.groheondus.sense.roomId.label = Room ID +thing-type.config.groheondus.sense.roomId.description = The ID of the room the appliance is in as retrieved from the GROHE ONDUS API. +thing-type.config.groheondus.senseguard.applianceId.label = Appliance ID +thing-type.config.groheondus.senseguard.applianceId.description = The UUID of the appliance as retrieved from the GROHE ONDUS API. +thing-type.config.groheondus.senseguard.locationId.label = Location ID +thing-type.config.groheondus.senseguard.locationId.description = The ID of the location the room is in as retrieved from the GROHE ONDUS API. +thing-type.config.groheondus.senseguard.pollingInterval.label = Polling Interval +thing-type.config.groheondus.senseguard.pollingInterval.description = The interval in seconds used to poll the API for new data. Defaults to the configuration of the appliance itself as retrieved from the API, usually 15 minutes. +thing-type.config.groheondus.senseguard.roomId.label = Room ID +thing-type.config.groheondus.senseguard.roomId.description = The ID of the room the appliance is in as retrieved from the GROHE ONDUS API. + +# channel types + +channel-type.groheondus.humidity.label = Humidity +channel-type.groheondus.humidity.description = The humidity reported by the device +channel-type.groheondus.name.label = Appliance Name +channel-type.groheondus.name.description = The name of the appliance +channel-type.groheondus.pressure.label = Pressure +channel-type.groheondus.pressure.description = The pressure of your water supply +channel-type.groheondus.temperature.label = Temperature +channel-type.groheondus.temperature.description = The temperature reported by the device +channel-type.groheondus.temperature_guard.label = Temperature +channel-type.groheondus.temperature_guard.description = The ambient temperature of the appliance +channel-type.groheondus.valve_open.label = Valve Open +channel-type.groheondus.valve_open.description = Valve switch +channel-type.groheondus.waterconsumption.label = Water Consumption +channel-type.groheondus.waterconsumption.description = The amount of water consumed in the given time period. + +# channel types config + +channel-type.config.groheondus.waterconsumption.timeframe.label = Timeframe +channel-type.config.groheondus.waterconsumption.timeframe.description = The timeframe in days to get the water consumption of diff --git a/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/i18n/haassohnpelletstove.properties b/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/i18n/haassohnpelletstove.properties new file mode 100644 index 0000000000000..a3aad9881072c --- /dev/null +++ b/bundles/org.openhab.binding.haassohnpelletstove/src/main/resources/OH-INF/i18n/haassohnpelletstove.properties @@ -0,0 +1,41 @@ +# binding + +binding.haassohnpelletstove.name = Haas and Sohn Pelletstove Binding +binding.haassohnpelletstove.description = This binding communicates with Haas and Sohn Pelletstoves through the optional WIFI module. It allows to power the stove on and off and receives different operation information. + +# thing types + +thing-type.haassohnpelletstove.oven.label = Haas+Sohn Oven +thing-type.haassohnpelletstove.oven.description = The binding for Haas and Sohn Pelletstove communicates with a Haas and Sohn Pelletstove through the optional WLAN-Modul. More information can be found here: https://www.haassohn.com/de/ihr-plus/WLAN-Funktion. It allows to power on/off the stove as well as receiving different operation information about the stove. + +# thing types config + +thing-type.config.haassohnpelletstove.oven.hostIP.label = IP Address +thing-type.config.haassohnpelletstove.oven.hostIP.description = Please add the IP Address of the WIFI Module of the Haas and Sohn oven here +thing-type.config.haassohnpelletstove.oven.hostPIN.label = PIN +thing-type.config.haassohnpelletstove.oven.hostPIN.description = Please add the PIN of your oven here. You can find it in the Menu directly in your oven. +thing-type.config.haassohnpelletstove.oven.refreshRate.label = Refresh Rate +thing-type.config.haassohnpelletstove.oven.refreshRate.description = How often the Pellet Stove should schedule a refresh after a channel is linked to an item. Temperature data will be refreshed according this set time in seconds. Valid input is 0 - 999. + +# channel types + +channel-type.haassohnpelletstove.cleaningIn.label = Next Cleaning Window +channel-type.haassohnpelletstove.cleaningIn.description = Provides a time forecast in hours:minutes when the stove need to be cleaned next as String +channel-type.haassohnpelletstove.consumption.label = Total Consumption Stove +channel-type.haassohnpelletstove.consumption.description = Provides the information about the total consumption of pellets of the stove as number:mass +channel-type.haassohnpelletstove.ecoMode.label = On/Off Eco Mode +channel-type.haassohnpelletstove.ecoMode.description = To turn the Eco Mode on/off for the stove as switch +channel-type.haassohnpelletstove.ignitions.label = Ignitions Stove +channel-type.haassohnpelletstove.ignitions.description = Receives the total amount of ignitions of the stove as string +channel-type.haassohnpelletstove.isTemp.label = Is Temperature Stove +channel-type.haassohnpelletstove.isTemp.description = Receives the is temperature of the stove as number:temperature +channel-type.haassohnpelletstove.maintenanceIn.label = Next Maintenance +channel-type.haassohnpelletstove.maintenanceIn.description = Provides a pellet forecast when the stove need to be maintained next in kilogram as number:mass +channel-type.haassohnpelletstove.mode.label = Mode Stove +channel-type.haassohnpelletstove.mode.description = Receives the actual mode of the stove as string +channel-type.haassohnpelletstove.onTime.label = Operation Hours Stove +channel-type.haassohnpelletstove.onTime.description = Provides the information of the operating hours of stove as number +channel-type.haassohnpelletstove.power.label = On/Off Stove +channel-type.haassohnpelletstove.power.description = To turn the stove on/off as switch +channel-type.haassohnpelletstove.spTemp.label = Set Temperature Stove +channel-type.haassohnpelletstove.spTemp.description = Set the target temperature of the stove as number:temperature diff --git a/bundles/org.openhab.binding.harmonyhub/src/main/resources/OH-INF/i18n/harmonyhub.properties b/bundles/org.openhab.binding.harmonyhub/src/main/resources/OH-INF/i18n/harmonyhub.properties new file mode 100644 index 0000000000000..7e8c8dbc26183 --- /dev/null +++ b/bundles/org.openhab.binding.harmonyhub/src/main/resources/OH-INF/i18n/harmonyhub.properties @@ -0,0 +1,39 @@ +# binding + +binding.harmonyhub.name = HarmonyHub Binding +binding.harmonyhub.description = The HarmonyHub Binding integrates Logitech Harmony hubs and remotes. + +# thing types + +thing-type.harmonyhub.device.label = Harmony Device +thing-type.harmonyhub.device.description = Logitech Harmony Hub Device +thing-type.harmonyhub.hub.label = Harmony Hub +thing-type.harmonyhub.hub.description = A Logitech Harmony Hub +thing-type.harmonyhub.hub.channel.activityStarted.label = Activity Started Trigger +thing-type.harmonyhub.hub.channel.activityStarted.description = Triggered when an activity is started +thing-type.harmonyhub.hub.channel.activityStarting.label = Activity Starting Trigger +thing-type.harmonyhub.hub.channel.activityStarting.description = Triggered when an activity is starting +thing-type.harmonyhub.hub.channel.buttonPress.label = Button Press +thing-type.harmonyhub.hub.channel.buttonPress.description = The label/name of the button to press on a Harmony Hub which will be sent to the device associated with the current activity and label + +# thing types config + +thing-type.config.harmonyhub.device.id.label = ID +thing-type.config.harmonyhub.device.id.description = Numeric ID of the Harmony Device (ID or name is required) +thing-type.config.harmonyhub.device.name.label = Name +thing-type.config.harmonyhub.device.name.description = Name of the Harmony Device (name or ID is required) +thing-type.config.harmonyhub.hub.heartBeatInterval.label = Heart Beat Interval +thing-type.config.harmonyhub.hub.heartBeatInterval.description = Heartbeat keep alive time in seconds. +thing-type.config.harmonyhub.hub.host.label = Host +thing-type.config.harmonyhub.hub.host.description = Host or IP address of hub. + +# channel types + +channel-type.harmonyhub.buttonPress.label = Button Press +channel-type.harmonyhub.buttonPress.description = The label/name of the button to press on a Harmony Hub device (write only) +channel-type.harmonyhub.currentActivity.label = Current Activity +channel-type.harmonyhub.currentActivity.description = The label/name of the current activity of a Harmony Hub +channel-type.harmonyhub.eventTrigger.label = Harmony Hub Event Trigger +channel-type.harmonyhub.eventTrigger.description = Triggered when Harmony Hub sent an event with activity status +channel-type.harmonyhub.player.label = Player Control +channel-type.harmonyhub.player.description = Send player commands (Rewind,FastForward,Play,Pause,SkipForward,SkipBackwards) to the device associated with the current running activity. diff --git a/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/i18n/haywardomnilogic.properties b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/i18n/haywardomnilogic.properties new file mode 100644 index 0000000000000..d4e90ad8965c4 --- /dev/null +++ b/bundles/org.openhab.binding.haywardomnilogic/src/main/resources/OH-INF/i18n/haywardomnilogic.properties @@ -0,0 +1,150 @@ +# binding + +binding.haywardomnilogic.name = Hayward OmniLogix Binding +binding.haywardomnilogic.description = Binding for the Hayward OmniLogix swimming pool automation controller. + +# thing types + +thing-type.haywardomnilogic.backyard.label = Backyard +thing-type.haywardomnilogic.backyard.description = The Hayward Backyard +thing-type.haywardomnilogic.bow.label = Body of Water +thing-type.haywardomnilogic.bow.description = The Hayward Body of Water +thing-type.haywardomnilogic.bridge.label = Hayward OmniLogix Connection +thing-type.haywardomnilogic.bridge.description = Connection to Hayward's Server +thing-type.haywardomnilogic.chlorinator.label = Chlorinator +thing-type.haywardomnilogic.chlorinator.description = Chlorinator +thing-type.haywardomnilogic.colorlogic.label = Color Logic Light +thing-type.haywardomnilogic.colorlogic.description = Color Logic Light +thing-type.haywardomnilogic.filter.label = Filter +thing-type.haywardomnilogic.filter.description = Filter Equipment +thing-type.haywardomnilogic.heater.label = Heater +thing-type.haywardomnilogic.heater.description = Heater +thing-type.haywardomnilogic.pump.label = Pump +thing-type.haywardomnilogic.pump.description = Pump +thing-type.haywardomnilogic.relay.label = Relay +thing-type.haywardomnilogic.relay.description = Relay +thing-type.haywardomnilogic.sensor.label = Sensor +thing-type.haywardomnilogic.sensor.description = Sensor +thing-type.haywardomnilogic.virtualHeater.label = Virtual Heater +thing-type.haywardomnilogic.virtualHeater.description = Virtual Heater + +# thing types config + +thing-type.config.haywardomnilogic.bridge.alarmPollTime.label = Alarm Poll Delay +thing-type.config.haywardomnilogic.bridge.alarmPollTime.description = How often to request alarm data from Hayward Server. Enter 0 to disable. +thing-type.config.haywardomnilogic.bridge.endpointUrl.label = Endpoint URL +thing-type.config.haywardomnilogic.bridge.endpointUrl.description = The URL of the Hayward API Server +thing-type.config.haywardomnilogic.bridge.password.label = Password +thing-type.config.haywardomnilogic.bridge.password.description = The password to connect to the server. +thing-type.config.haywardomnilogic.bridge.telemetryPollTime.label = Telemetry Poll Delay +thing-type.config.haywardomnilogic.bridge.telemetryPollTime.description = How often to request telemetry data from Hayward Server +thing-type.config.haywardomnilogic.bridge.username.label = User Name +thing-type.config.haywardomnilogic.bridge.username.description = The username to connect to the server. + +# channel types + +channel-type.haywardomnilogic.airTemp.label = Air Temp +channel-type.haywardomnilogic.airTemp.description = Air Temp +channel-type.haywardomnilogic.alarm.label = Alarm +channel-type.haywardomnilogic.alarm.description = Alarm +channel-type.haywardomnilogic.avgSaltLevel.label = Average Salt Level +channel-type.haywardomnilogic.avgSaltLevel.description = Average Salt Level +channel-type.haywardomnilogic.backyardstate.label = State +channel-type.haywardomnilogic.backyardstate.description = State +channel-type.haywardomnilogic.backyardstate.state.option.0 = Powered Off +channel-type.haywardomnilogic.backyardstate.state.option.1 = Normal +channel-type.haywardomnilogic.backyardstate.state.option.2 = Service Mode +channel-type.haywardomnilogic.backyardstate.state.option.3 = Config Mode +channel-type.haywardomnilogic.backyardstate.state.option.4 = Timed Service Mode +channel-type.haywardomnilogic.backyardstatus.label = Status +channel-type.haywardomnilogic.backyardstatus.description = Status +channel-type.haywardomnilogic.backyardstatus.state.option.1 = Normal +channel-type.haywardomnilogic.backyardstatus.state.option.2 = Alarm +channel-type.haywardomnilogic.backyardstatus.state.option.3 = Expired +channel-type.haywardomnilogic.backyardstatus.state.option.4 = Lost Link +channel-type.haywardomnilogic.backyardstatus.state.option.5 = Service Mode +channel-type.haywardomnilogic.bow.label = Body of Water +channel-type.haywardomnilogic.bow.description = The Body of Water ID +channel-type.haywardomnilogic.chlorAlert.label = Chlorinator Alert +channel-type.haywardomnilogic.chlorAlert.description = Chlorinator Alert +channel-type.haywardomnilogic.chlorAlert.state.option.0 = None +channel-type.haywardomnilogic.chlorAlert.state.option.16 = Low T-Cell Temperature +channel-type.haywardomnilogic.chlorError.label = Chlorinator Error +channel-type.haywardomnilogic.chlorOperatingMode.label = Operating Mode +channel-type.haywardomnilogic.chlorOperatingMode.description = Operating Mode +channel-type.haywardomnilogic.chlorOperatingMode.state.option.0 = Off +channel-type.haywardomnilogic.chlorOperatingMode.state.option.1 = Timed Percent +channel-type.haywardomnilogic.chlorOperatingMode.state.option.2 = ORP Autosense +channel-type.haywardomnilogic.currentSetpoint.label = Current Setpoint +channel-type.haywardomnilogic.currentSetpoint.description = Current Setpoint +channel-type.haywardomnilogic.currentShow.label = Current Show +channel-type.haywardomnilogic.currentShow.description = Current Show +channel-type.haywardomnilogic.currentShow.state.option.0 = Voodoo Lounge +channel-type.haywardomnilogic.currentShow.state.option.1 = Deep Blue Sea +channel-type.haywardomnilogic.currentShow.state.option.2 = Royal Blue +channel-type.haywardomnilogic.currentShow.state.option.3 = Afternoon Sky +channel-type.haywardomnilogic.currentShow.state.option.4 = Aqua Green +channel-type.haywardomnilogic.currentShow.state.option.5 = Emerald +channel-type.haywardomnilogic.currentShow.state.option.6 = Cloud White +channel-type.haywardomnilogic.currentShow.state.option.7 = Warm Red +channel-type.haywardomnilogic.currentShow.state.option.8 = Flamingo +channel-type.haywardomnilogic.currentShow.state.option.9 = Vivid Violet +channel-type.haywardomnilogic.currentShow.state.option.10 = Sangria +channel-type.haywardomnilogic.currentShow.state.option.11 = Twilight +channel-type.haywardomnilogic.currentShow.state.option.12 = Tranquility +channel-type.haywardomnilogic.currentShow.state.option.13 = Gemstone +channel-type.haywardomnilogic.currentShow.state.option.14 = USA +channel-type.haywardomnilogic.currentShow.state.option.15 = Mardi Gras +channel-type.haywardomnilogic.currentShow.state.option.16 = Cool Cabaret +channel-type.haywardomnilogic.data.label = Data +channel-type.haywardomnilogic.data.description = Sensor Data +channel-type.haywardomnilogic.enable.label = Heater Enable +channel-type.haywardomnilogic.enable.description = Heater Enable +channel-type.haywardomnilogic.filterLastSpeed.label = Last Speed +channel-type.haywardomnilogic.filterLastSpeed.description = Last Speed +channel-type.haywardomnilogic.filterSpeed.label = Filter Speed +channel-type.haywardomnilogic.filterSpeed.description = Filter Speed in % +channel-type.haywardomnilogic.filterState.label = Filter State +channel-type.haywardomnilogic.filterState.description = Filter State +channel-type.haywardomnilogic.filterState.state.option.0 = Off +channel-type.haywardomnilogic.filterState.state.option.1 = Running +channel-type.haywardomnilogic.filterState.state.option.2 = Priming +channel-type.haywardomnilogic.filterState.state.option.3 = Waiting to Turn Off +channel-type.haywardomnilogic.filterState.state.option.4 = Waiting to Turn Off Manual +channel-type.haywardomnilogic.filterState.state.option.5 = Heater Extend +channel-type.haywardomnilogic.filterState.state.option.6 = Heater Cool Down +channel-type.haywardomnilogic.filterState.state.option.7 = Suspended +channel-type.haywardomnilogic.filterState.state.option.8 = CSAD Extend +channel-type.haywardomnilogic.filterState.state.option.9 = Filter Superchlorinate +channel-type.haywardomnilogic.filterState.state.option.10 = Filter Force Priming +channel-type.haywardomnilogic.filterState.state.option.11 = Filter Waiting for Pump to Turn Off +channel-type.haywardomnilogic.instantSaltLevel.label = Instant Salt Level +channel-type.haywardomnilogic.instantSaltLevel.description = Instant Salt Level +channel-type.haywardomnilogic.lightState.label = Light State +channel-type.haywardomnilogic.lightState.description = Light State +channel-type.haywardomnilogic.lightState.state.option.0 = Off +channel-type.haywardomnilogic.lightState.state.option.1 = On +channel-type.haywardomnilogic.lightState.state.option.4 = 15 Sec White Light +channel-type.haywardomnilogic.lightState.state.option.7 = Powering Off +channel-type.haywardomnilogic.pumpSpeed.label = Pump Speed in % +channel-type.haywardomnilogic.pumpSpeed.description = Pump Speed +channel-type.haywardomnilogic.scMode.label = scMode +channel-type.haywardomnilogic.scMode.description = scMode +channel-type.haywardomnilogic.scMode.state.option.0 = Off +channel-type.haywardomnilogic.scMode.state.option.1 = Super Chlorinating +channel-type.haywardomnilogic.state.label = Heater State +channel-type.haywardomnilogic.state.description = Heater State +channel-type.haywardomnilogic.status.label = Status +channel-type.haywardomnilogic.status.description = Status +channel-type.haywardomnilogic.timedPercent.label = Salt Output (%) +channel-type.haywardomnilogic.timedPercent.description = Current salt output setting for the chlorinator (%). +channel-type.haywardomnilogic.valvePosition.label = Valve Position +channel-type.haywardomnilogic.valvePosition.description = Valve Position +channel-type.haywardomnilogic.valvePosition.state.option.0 = Off +channel-type.haywardomnilogic.valvePosition.state.option.1 = Pool Only +channel-type.haywardomnilogic.valvePosition.state.option.2 = Spa Only +channel-type.haywardomnilogic.valvePosition.state.option.3 = Spill Over +channel-type.haywardomnilogic.waterFlow.label = Flow Sensor +channel-type.haywardomnilogic.waterFlow.description = Flow Sensor +channel-type.haywardomnilogic.waterTemp.label = Water Temp +channel-type.haywardomnilogic.waterTemp.description = Water Temp diff --git a/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/i18n/hccrubbishcollection.properties b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/i18n/hccrubbishcollection.properties new file mode 100644 index 0000000000000..8320d33ac8085 --- /dev/null +++ b/bundles/org.openhab.binding.hccrubbishcollection/src/main/resources/OH-INF/i18n/hccrubbishcollection.properties @@ -0,0 +1,39 @@ +# binding + +binding.hccrubbishcollection.name = HCC Rubbish Collection Binding +binding.hccrubbishcollection.description = Get the rubbish collection dates for Hamilton City Council (New Zealand). + +# thing types + +thing-type.hccrubbishcollection.collection.label = HCC NZ Rubbish Collection +thing-type.hccrubbishcollection.collection.description = Rubbish collection days for Hamilton City Council (NZ). +thing-type.hccrubbishcollection.collection.channel.general.label = General Bin Collection Date +thing-type.hccrubbishcollection.collection.channel.general.description = The next collection date of the general rubbish (red bin). +thing-type.hccrubbishcollection.collection.channel.recycling.label = Recycling Bin Collection Date +thing-type.hccrubbishcollection.collection.channel.recycling.description = The next collection date of the recycling (yellow bin and green bin). + +# thing types config + +thing-type.config.hccrubbishcollection.collection.address.label = Address +thing-type.config.hccrubbishcollection.collection.address.description = The street address to get rubbish collection dates for. + +# channel types + +channel-type.hccrubbishcollection.bin.label = Collection Date +channel-type.hccrubbishcollection.bin.state.pattern = %1$tY-%1$tm-%1$td +channel-type.hccrubbishcollection.collection-event.label = Collection Event +channel-type.hccrubbishcollection.collection-event.description = Event for the day when collection occurs. +channel-type.hccrubbishcollection.day.label = Collection Day +channel-type.hccrubbishcollection.day.description = The rubbish collection Day of the Week +channel-type.hccrubbishcollection.day.state.option.1 = Monday +channel-type.hccrubbishcollection.day.state.option.2 = Tuesday +channel-type.hccrubbishcollection.day.state.option.3 = Wednesday +channel-type.hccrubbishcollection.day.state.option.4 = Thursday +channel-type.hccrubbishcollection.day.state.option.5 = Friday +channel-type.hccrubbishcollection.day.state.option.6 = Saturday +channel-type.hccrubbishcollection.day.state.option.7 = Sunday + +# channel types config + +channel-type.config.hccrubbishcollection.collection-event.offset.label = Offset +channel-type.config.hccrubbishcollection.collection-event.offset.description = Moves the event forward or backward (in minutes). diff --git a/bundles/org.openhab.binding.hdanywhere/src/main/resources/OH-INF/i18n/hdanywhere.properties b/bundles/org.openhab.binding.hdanywhere/src/main/resources/OH-INF/i18n/hdanywhere.properties new file mode 100644 index 0000000000000..fea59bb178ffc --- /dev/null +++ b/bundles/org.openhab.binding.hdanywhere/src/main/resources/OH-INF/i18n/hdanywhere.properties @@ -0,0 +1,31 @@ +# binding + +binding.hdanywhere.name = openHAB HDanywhere Binding +binding.hdanywhere.description = This is the binding for HDanywhere HDMI Matrices + +# thing types + +thing-type.hdanywhere.mhub4k431.label = HDanywhere MHUB4K431 HDMI Matrix +thing-type.hdanywhere.mhub4k431.description = Thing for the HDanywhere MHUB4K431 HDMI Matrix +thing-type.hdanywhere.multiroomplus.label = HDanywhere Multiroom+ HDMI Matrix +thing-type.hdanywhere.multiroomplus.description = Thing for the HDanywhere Multiroom+ HDMI Matrix + +# thing types config + +thing-type.config.hdanywhere.mhub4k431.interval.label = Polling Interval +thing-type.config.hdanywhere.mhub4k431.interval.description = Interval in seconds to poll the actual state of the Matrix +thing-type.config.hdanywhere.mhub4k431.ipAddress.label = Network Address +thing-type.config.hdanywhere.mhub4k431.ipAddress.description = Network address of the Matrix +thing-type.config.hdanywhere.multiroomplus.interval.label = Polling Interval +thing-type.config.hdanywhere.multiroomplus.interval.description = Interval in seconds to poll the actual state of the Matrix +thing-type.config.hdanywhere.multiroomplus.ipAddress.label = Network Address +thing-type.config.hdanywhere.multiroomplus.ipAddress.description = Network address of the Matrix +thing-type.config.hdanywhere.multiroomplus.ports.label = Number of Ports +thing-type.config.hdanywhere.multiroomplus.ports.description = Specifies the number of input/output ports on the Matrix, e.g. 4 or 8 if 4x4 or 8x8 version of the Matrix + +# channel types + +channel-type.hdanywhere.port.label = Output Port +channel-type.hdanywhere.port.description = The port channel allows to set or read the number of the input port that is connected to the output port. Valid values are 1 to 8 depending on the nature of the Matrix, e.g 4x4 8x8 etc +channel-type.hdanywhere.port.label = Output Port +channel-type.hdanywhere.port.description = The port channel allows to set or read the number of the input port that is connected to the output port. Valid values are 1 to 4 diff --git a/bundles/org.openhab.binding.helios/src/main/resources/OH-INF/i18n/helios.properties b/bundles/org.openhab.binding.helios/src/main/resources/OH-INF/i18n/helios.properties new file mode 100644 index 0000000000000..d3f5803b3db73 --- /dev/null +++ b/bundles/org.openhab.binding.helios/src/main/resources/OH-INF/i18n/helios.properties @@ -0,0 +1,93 @@ +# binding + +binding.helios.name = Helios Binding +binding.helios.description = This is the binding for Helios IP (Vario/...) class of intercom/(video)doorstations. + +# thing types + +thing-type.helios.ipvario221.label = Helios IP Vario +thing-type.helios.ipvario221.description = Helios IP Vario Door Station / Intercom with Firmware v2.21 +thing-type.helios.ipvario27.label = Helios IP Vario +thing-type.helios.ipvario27.description = Helios IP Vario Door Station / Intercom with Firmware v2.7 + +# thing types config + +thing-type.config.helios.ipvario221.ipAddress.label = Network Address +thing-type.config.helios.ipvario221.ipAddress.description = Network address of the Helios IP device +thing-type.config.helios.ipvario221.password.label = Password +thing-type.config.helios.ipvario221.password.description = Password to access REST services on the Helios IP device +thing-type.config.helios.ipvario221.username.label = Username +thing-type.config.helios.ipvario221.username.description = Username to access REST services on the Helios IP device +thing-type.config.helios.ipvario27.ipAddress.label = Network Address +thing-type.config.helios.ipvario27.ipAddress.description = Network address of the Helios IP device +thing-type.config.helios.ipvario27.openHABipAddress.label = Network Address +thing-type.config.helios.ipvario27.openHABipAddress.description = Network address of the openHAB host +thing-type.config.helios.ipvario27.openHABportNumber.label = Port Number +thing-type.config.helios.ipvario27.openHABportNumber.description = TCP port number the notification web service will be registered on + +# channel types + +channel-type.helios.audiolooptest.label = Audio Loop Test +channel-type.helios.audiolooptest.description = Audio loop test result +channel-type.helios.audioloopteststamp.label = Audio Loop Test Time +channel-type.helios.audioloopteststamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.calldirection.label = Call Direction +channel-type.helios.calldirection.description = Direction of the current call +channel-type.helios.calldirection.state.option.incoming = Incoming +channel-type.helios.calldirection.state.option.outgoing = Outgoing +channel-type.helios.callstate.label = Call State +channel-type.helios.callstate.description = State of the current call +channel-type.helios.callstate.state.option.ringing = Ringing +channel-type.helios.callstate.state.option.connected = Connected +channel-type.helios.callstate.state.option.terminated = Terminated +channel-type.helios.callstatestamp.label = Call State Time +channel-type.helios.callstatestamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.card.label = Card ID +channel-type.helios.card.description = Detected card identification with a 24-64-bit number in the hexadecimal format +channel-type.helios.cardstamp.label = Card Detection Time +channel-type.helios.cardstamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.cardvalid.label = Card Valid +channel-type.helios.cardvalid.description = If the detected card is valid, the parameter value is ON. If not, the parameter is set to OFF +channel-type.helios.code.label = Code Entered +channel-type.helios.code.description = Numerical code entered, e.g. 1234. +channel-type.helios.codestamp.label = Code Entered Time +channel-type.helios.codestamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.codevalid.label = Code Valid +channel-type.helios.codevalid.description = If the entered code is valid, the parameter value is ON. If not, the parameter is set to OFF +channel-type.helios.devicestate.label = Device State +channel-type.helios.devicestate.description = State of the Helios device +channel-type.helios.devicestate.state.option.startup = Startup +channel-type.helios.devicestatestamp.label = Device State Time +channel-type.helios.devicestatestamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.io.label = IO +channel-type.helios.io.description = Enable or disable the output of an I/O port of the Helios device +channel-type.helios.keypressed.label = Key Pressed +channel-type.helios.keypressed.description = The key pressed, 0, 1, …, 9, *, # for keypad buttons and %1..%54 for call buttons +channel-type.helios.keypressedstamp.label = Key Press Time +channel-type.helios.keypressedstamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.keyreleased.label = Key Released +channel-type.helios.keyreleased.description = The key released, 0, 1, …, 9, *, # for keypad buttons and %1..%54 for call buttons +channel-type.helios.keyreleasedstamp.label = Key Released Time +channel-type.helios.keyreleasedstamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.motion.label = Motion +channel-type.helios.motion.description = Motion detection indicator +channel-type.helios.motionstamp.label = Motion Detection Time +channel-type.helios.motionstamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.noise.label = Noise +channel-type.helios.noise.description = Noise detection indicator +channel-type.helios.noisestamp.label = Noise Detection Time +channel-type.helios.noisestamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.switchenabler.label = Switch Enabler +channel-type.helios.switchenabler.description = Enable or disable a switch +channel-type.helios.switchstate.label = Switch State +channel-type.helios.switchstate.description = ON when a switch switched on, OFF when a switch switched off +channel-type.helios.switchstateoriginator.label = Switch State Originator +channel-type.helios.switchstateoriginator.description = Originator that switched the switch +channel-type.helios.switchstateoriginator.state.option.DTMF = DTMF +channel-type.helios.switchstateoriginator.state.option.API = API +channel-type.helios.switchstatestamp.label = Switch Switch Time +channel-type.helios.switchstatestamp.description = Event date and time in CCYY-MM-DDThh:mm:ss format +channel-type.helios.switchstateswitch.label = Switch Number +channel-type.helios.switchstateswitch.description = Number of the switch that switched, e.g. 1 to 4 +channel-type.helios.switchtrigger.label = Switch Trigger +channel-type.helios.switchtrigger.description = Switch a switch diff --git a/bundles/org.openhab.binding.heliosventilation/src/main/resources/OH-INF/i18n/heliosventilation.properties b/bundles/org.openhab.binding.heliosventilation/src/main/resources/OH-INF/i18n/heliosventilation.properties new file mode 100644 index 0000000000000..f08d990bc583f --- /dev/null +++ b/bundles/org.openhab.binding.heliosventilation/src/main/resources/OH-INF/i18n/heliosventilation.properties @@ -0,0 +1,62 @@ +# binding + +binding.heliosventilation.name = HeliosVentilation Binding +binding.heliosventilation.description = This is the binding for Helios Ventilation Systems KWL EC 200/300/500 Pro. It requires a connection to the RS485 bus used by the original remote controls KWL-FB (9417). + +# thing types + +thing-type.heliosventilation.ventilation.label = HeliosVentilation (KWL) +thing-type.heliosventilation.ventilation.description = A domestic ventilation system (KWL) from Helios. + +# thing types config + +thing-type.config.heliosventilation.ventilation.pollPeriod.label = Poll Period +thing-type.config.heliosventilation.ventilation.pollPeriod.description = The poll period in seconds use 0 for no polling. +thing-type.config.heliosventilation.ventilation.serialPort.label = RS485 Interface Serial Port +thing-type.config.heliosventilation.ventilation.serialPort.description = The serial port name for the RS485 interfaces. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux. + +# channel types + +channel-type.heliosventilation.adjust_interval.label = Adjust Interval +channel-type.heliosventilation.bypass_temperature.label = Cell Bypass Temperature +channel-type.heliosventilation.bypass_temperature.description = Bypass temperature to disable the bypass function if outside temperature is below this threshold even if ventilation system is in summer mode. +channel-type.heliosventilation.cascade_mode.label = Cascaded ventilation system +channel-type.heliosventilation.co2_state.label = CO2 Control +channel-type.heliosventilation.co2_state.description = Control the ventilation system by CO2 sensor. +channel-type.heliosventilation.dc_fan_extract.label = Extract Fan +channel-type.heliosventilation.dc_fan_extract.description = Speed of the extract air fan (outgoing air). +channel-type.heliosventilation.dc_fan_supply.label = Supply Fan +channel-type.heliosventilation.dc_fan_supply.description = Speed of the supply air fan (incoming air). +channel-type.heliosventilation.extract_temperature.label = Extract Temperature +channel-type.heliosventilation.extract_temperature.description = Temperature measured in the extract (indoor, room temperature) air flow. +channel-type.heliosventilation.fanspeed.label = Fanspeed +channel-type.heliosventilation.hysteresis.label = Hysteresis +channel-type.heliosventilation.hysteresis.description = Hysteresis on defroster temperature. +channel-type.heliosventilation.maintenance_interval.label = Maintenance Interval +channel-type.heliosventilation.max_fanspeed.label = Maximum Fanspeed +channel-type.heliosventilation.min_fanspeed.label = Minimal Fanspeed +channel-type.heliosventilation.outgoing_temperature.label = Outgoing Temperature +channel-type.heliosventilation.outgoing_temperature.description = Temperature measured in the outgoing air flow. +channel-type.heliosventilation.outside_temperature.label = Outside Temperature +channel-type.heliosventilation.outside_temperature.description = Temperature measured in the outdoor air flow. +channel-type.heliosventilation.power_state.label = Power +channel-type.heliosventilation.power_state.description = State of the ventilation system. +channel-type.heliosventilation.preheat_temperature.label = Preheat Temperature +channel-type.heliosventilation.preheat_temperature.description = Set temperature for preheater. +channel-type.heliosventilation.radiator_type.label = Water radiator +channel-type.heliosventilation.radiator_type.description = Ventilation system with water radiator (ON) or electric radiator (OFF). +channel-type.heliosventilation.rh_level_auto.label = Auto Humidity level +channel-type.heliosventilation.rh_limit.label = RH Limit +channel-type.heliosventilation.rh_limit.description = Limit for relative humidity sensor. +channel-type.heliosventilation.rh_state.label = Humidity Control +channel-type.heliosventilation.rh_state.description = Control the ventilation system by humidity sensor. +channel-type.heliosventilation.set_temperature.label = Temperature +channel-type.heliosventilation.set_temperature.description = Set temperature for the supply air. Not used in all ventilation systems. +channel-type.heliosventilation.supply_stop_temperature.label = Supply Stop Temperature +channel-type.heliosventilation.supply_stop_temperature.description = Stop the supply fan if outside temperature is below this threshold. +channel-type.heliosventilation.supply_temperature.label = Supply Temperature +channel-type.heliosventilation.supply_temperature.description = Temperature measured in the supply (incoming) air flow. +channel-type.heliosventilation.switch_type.label = Boost switch +channel-type.heliosventilation.switch_type.description = External switch is used for boost (ON) or fireplace (OFF). +channel-type.heliosventilation.winter_state.label = Winter Mode +channel-type.heliosventilation.winter_state.description = Ventilation system is in winter mode and will not use bypass for cooling. If OFF, the bypass function will be used for cooling if the outside temperature is above the Cell Bypass Temperature. diff --git a/bundles/org.openhab.binding.heos/src/main/resources/OH-INF/i18n/heos.properties b/bundles/org.openhab.binding.heos/src/main/resources/OH-INF/i18n/heos.properties new file mode 100644 index 0000000000000..01665d79b4a7b --- /dev/null +++ b/bundles/org.openhab.binding.heos/src/main/resources/OH-INF/i18n/heos.properties @@ -0,0 +1,60 @@ +# binding + +binding.heos.name = HEOS Binding +binding.heos.description = Binding for the Denon HEOS system. + +# thing types + +thing-type.heos.bridge.label = HEOS Bridge +thing-type.heos.bridge.description = The HEOS System Bridge +thing-type.heos.group.label = HEOS Group +thing-type.heos.group.description = A group of HEOS Player +thing-type.heos.player.label = HEOS Player +thing-type.heos.player.description = A HEOS Player of the HEOS Network + +# thing types config + +thing-type.config.heos.bridge.heartbeat.label = Heartbeat +thing-type.config.heos.bridge.heartbeat.description = The time in seconds for the HEOS Heartbeat (default = 60 s) +thing-type.config.heos.bridge.ipAddress.label = Network Address +thing-type.config.heos.bridge.ipAddress.description = Network address of the HEOS bridge. +thing-type.config.heos.bridge.password.label = Password +thing-type.config.heos.bridge.password.description = Password for login to the HEOS account +thing-type.config.heos.bridge.username.label = Username +thing-type.config.heos.bridge.username.description = Username for login to the HEOS account. +thing-type.config.heos.group.members.label = The Group Member Player IDs +thing-type.config.heos.group.members.description = Shows the player IDs of the members of this group +thing-type.config.heos.player.pid.label = Player ID +thing-type.config.heos.player.pid.description = The internal Player ID + +# channel types + +channel-type.heos.album.label = Album +channel-type.heos.buildGroup.label = Make Group +channel-type.heos.clearQueue.label = Clear Queue +channel-type.heos.cover.label = Cover +channel-type.heos.currentPosition.label = Track Position +channel-type.heos.currentPosition.description = The current track position +channel-type.heos.duration.label = Track Duration +channel-type.heos.duration.description = The overall duration of the track +channel-type.heos.favorites.label = Favorites +channel-type.heos.input.label = External Inputs +channel-type.heos.playUrl.label = Play URL +channel-type.heos.playUrl.description = Plays a media file from URL +channel-type.heos.playlists.label = Playlists +channel-type.heos.queue.label = Queue +channel-type.heos.rawCommand.label = Send RAW Command +channel-type.heos.rawCommand.description = Sending a HEOS command as specified within the HEOS CLI protocol +channel-type.heos.reboot.label = Reboot +channel-type.heos.repeatMode.label = Repeat Mode +channel-type.heos.repeatMode.description = Set the repeat mode +channel-type.heos.repeatMode.state.option.One = One +channel-type.heos.repeatMode.state.option.All = All +channel-type.heos.repeatMode.state.option.Off = Off +channel-type.heos.shuffleMode.label = Shuffle +channel-type.heos.shuffleMode.description = Sets the shuffle mode +channel-type.heos.station.label = Station +channel-type.heos.station.description = The name of the station currently played +channel-type.heos.type.label = Type +channel-type.heos.type.description = The media currently played type (station, song, ...) +channel-type.heos.ungroup.label = Group diff --git a/bundles/org.openhab.binding.homeconnect/src/main/resources/OH-INF/i18n/homeconnect.properties b/bundles/org.openhab.binding.homeconnect/src/main/resources/OH-INF/i18n/homeconnect.properties new file mode 100644 index 0000000000000..8028880dbaef7 --- /dev/null +++ b/bundles/org.openhab.binding.homeconnect/src/main/resources/OH-INF/i18n/homeconnect.properties @@ -0,0 +1,287 @@ +# binding + +binding.homeconnect.name = Home Connect Binding +binding.homeconnect.description = The binding integrates the Home Connect (https://www.home-connect.com/) system into openHAB. It connects to household devices from brands like Bosch and Siemens. + +# thing types + +thing-type.homeconnect.api_bridge.label = Home Connect API +thing-type.homeconnect.api_bridge.description = This bridge represents the gateway to the Home Connect API. +thing-type.homeconnect.coffeemaker.label = Coffee Machine +thing-type.homeconnect.coffeemaker.description = Home Connect connected coffee machine (e.g. Bosch or Siemens). +thing-type.homeconnect.dishwasher.label = Dishwasher +thing-type.homeconnect.dishwasher.description = Home Connect connected dishwasher (e.g. Bosch or Siemens). +thing-type.homeconnect.dryer.label = Dryer +thing-type.homeconnect.dryer.description = Home Connect connected dryer (e.g. Bosch or Siemens). +thing-type.homeconnect.fridgefreezer.label = Refrigerator / Freezer +thing-type.homeconnect.fridgefreezer.description = Home Connect connected refrigerator/freezer (e.g. Bosch or Siemens). +thing-type.homeconnect.hob.label = Cooktop +thing-type.homeconnect.hob.description = Home Connect connected kitchen cooktop (hob). +thing-type.homeconnect.hood.label = Hood +thing-type.homeconnect.hood.description = Home Connect connected kitchen hood. +thing-type.homeconnect.oven.label = Oven +thing-type.homeconnect.oven.description = Home Connect connected oven (e.g. Bosch or Siemens). +thing-type.homeconnect.washer.label = Washer +thing-type.homeconnect.washer.description = Home Connect connected washing machine (e.g. Bosch or Siemens). +thing-type.homeconnect.washerdryer.label = Washer Dryer Combination +thing-type.homeconnect.washerdryer.description = Home Connect connected combined washer dryer appliance. + +# thing types config + +thing-type.config.homeconnect.api_bridge.clientId.label = Client Id +thing-type.config.homeconnect.api_bridge.clientId.description = Application client id +thing-type.config.homeconnect.api_bridge.clientSecret.label = Client Secret +thing-type.config.homeconnect.api_bridge.clientSecret.description = Application client secret +thing-type.config.homeconnect.api_bridge.simulator.label = Use Simulator Environment +thing-type.config.homeconnect.api_bridge.simulator.description = Use simulated environment at https://developer.home-connect.com/simulator/ +thing-type.config.homeconnect.coffeemaker.haId.label = haId +thing-type.config.homeconnect.coffeemaker.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.dishwasher.haId.label = haId +thing-type.config.homeconnect.dishwasher.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.dryer.haId.label = haId +thing-type.config.homeconnect.dryer.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.fridgefreezer.haId.label = haId +thing-type.config.homeconnect.fridgefreezer.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.hob.haId.label = haId +thing-type.config.homeconnect.hob.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.hood.haId.label = haId +thing-type.config.homeconnect.hood.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.oven.haId.label = haId +thing-type.config.homeconnect.oven.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.washer.haId.label = haId +thing-type.config.homeconnect.washer.haId.description = Unique identifier representing a specific home appliance. +thing-type.config.homeconnect.washerdryer.haId.label = haId +thing-type.config.homeconnect.washerdryer.haId.description = Unique identifier representing a specific home appliance. + +# channel types + +channel-type.homeconnect.active_program_state.label = Active Program +channel-type.homeconnect.active_program_state.description = This status describes the active program of the home appliance. +channel-type.homeconnect.ambient_light_color_state.label = Ambient Light Color +channel-type.homeconnect.ambient_light_color_state.description = This setting describes the color state of the ambient light. +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.CustomColor = Custom Color +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color1 = Color 1 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color2 = Color 2 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color3 = Color 3 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color4 = Color 4 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color5 = Color 5 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color6 = Color 6 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color7 = Color 7 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color8 = Color 8 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color9 = Color 9 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color10 = Color 10 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color11 = Color 11 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color12 = Color 12 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color13 = Color 13 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color14 = Color 14 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color15 = Color 15 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color16 = Color 16 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color17 = Color 17 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color18 = Color 18 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color19 = Color 19 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color20 = Color 20 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color21 = Color 21 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color22 = Color 22 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color23 = Color 23 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color24 = Color 24 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color25 = Color 25 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color26 = Color 26 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color27 = Color 27 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color28 = Color 28 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color29 = Color 29 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color30 = Color 30 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color31 = Color 31 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color32 = Color 32 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color33 = Color 33 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color34 = Color 34 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color35 = Color 35 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color36 = Color 36 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color37 = Color 37 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color38 = Color 38 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color39 = Color 39 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color40 = Color 40 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color41 = Color 41 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color42 = Color 42 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color43 = Color 43 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color44 = Color 44 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color45 = Color 45 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color46 = Color 46 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color47 = Color 47 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color48 = Color 48 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color49 = Color 49 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color50 = Color 50 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color51 = Color 51 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color52 = Color 52 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color53 = Color 53 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color54 = Color 54 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color55 = Color 55 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color56 = Color 56 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color57 = Color 57 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color58 = Color 58 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color59 = Color 59 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color60 = Color 60 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color61 = Color 61 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color62 = Color 62 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color63 = Color 63 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color64 = Color 64 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color65 = Color 65 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color66 = Color 66 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color67 = Color 67 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color68 = Color 68 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color69 = Color 69 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color70 = Color 70 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color71 = Color 71 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color72 = Color 72 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color73 = Color 73 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color74 = Color 74 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color75 = Color 75 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color76 = Color 76 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color77 = Color 77 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color78 = Color 78 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color79 = Color 79 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color80 = Color 80 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color81 = Color 81 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color82 = Color 82 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color83 = Color 83 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color84 = Color 84 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color85 = Color 85 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color86 = Color 86 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color87 = Color 87 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color88 = Color 88 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color89 = Color 89 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color90 = Color 90 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color91 = Color 91 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color92 = Color 92 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color93 = Color 93 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color94 = Color 94 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color95 = Color 95 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color96 = Color 96 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color97 = Color 97 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color98 = Color 98 +channel-type.homeconnect.ambient_light_color_state.state.option.BSH.Common.EnumType.AmbientLightColor.Color99 = Color 99 +channel-type.homeconnect.ambient_light_custom_color_state.label = Ambient Light (Custom) +channel-type.homeconnect.ambient_light_custom_color_state.description = This setting describes the custom color state of the ambient light. +channel-type.homeconnect.ambient_light_state.label = Ambient Light State +channel-type.homeconnect.ambient_light_state.description = This setting describes the current ambient light state of the home appliance. +channel-type.homeconnect.basic_actions_state.label = Program Actions +channel-type.homeconnect.basic_actions_state.state.option.start = Start program +channel-type.homeconnect.basic_actions_state.state.option.stop = Stop program +channel-type.homeconnect.coffeemaker_bean_container_empty_state.label = Bean Container Empty +channel-type.homeconnect.coffeemaker_bean_container_empty_state.description = Is coffee maker bean container is empty? +channel-type.homeconnect.coffeemaker_drip_tray_full_state.label = Drip Tray Full +channel-type.homeconnect.coffeemaker_drip_tray_full_state.description = Is coffee maker drip tray full? +channel-type.homeconnect.coffeemaker_water_tank_empty_state.label = Water Tank Empty +channel-type.homeconnect.coffeemaker_water_tank_empty_state.description = Is coffee maker water tank empty? +channel-type.homeconnect.door_state.label = Door State +channel-type.homeconnect.door_state.description = This status describes the door state of a home appliance. A status change is either triggered by the user operating the home appliance locally (i.e. opening/closing door) or automatically by the home appliance (i.e. locking the door). +channel-type.homeconnect.dryer_drying_target.label = Drying Target +channel-type.homeconnect.dryer_drying_target.description = Specifies the desired dryness setting. +channel-type.homeconnect.duration.label = Selected Duration +channel-type.homeconnect.duration.description = This status describes the duration of the program of the home appliance. +channel-type.homeconnect.elapsed_program_time.label = Elapsed Program Time +channel-type.homeconnect.elapsed_program_time.description = This status describes the elapsed program time of the home appliance. +channel-type.homeconnect.functional_light_state.label = Functional Light State +channel-type.homeconnect.functional_light_state.description = This setting describes the current functional light state of the home appliance. +channel-type.homeconnect.hood_intensive_level.label = Intensive level +channel-type.homeconnect.hood_intensive_level.description = Current venting intensive level of the hood. +channel-type.homeconnect.hood_program_state.label = Program Actions +channel-type.homeconnect.hood_program_state.description = Start hood program. +channel-type.homeconnect.hood_venting_level.label = Venting Level +channel-type.homeconnect.hood_venting_level.description = Current venting level of the hood. +channel-type.homeconnect.laundry_care_washer_idos1.label = i-Dos 1 +channel-type.homeconnect.laundry_care_washer_idos1.description = This status indicates whether i-Dos 1 is activated for a washer program of the home appliance. (If appliance supports i-Dos) +channel-type.homeconnect.laundry_care_washer_idos1_level.label = i-Dos 1 Dosing Level +channel-type.homeconnect.laundry_care_washer_idos1_level.description = This status defines the i-Dos dosing level of a washer program of the home appliance. (If appliance supports i-Dos) +channel-type.homeconnect.laundry_care_washer_idos1_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Off = Off +channel-type.homeconnect.laundry_care_washer_idos1_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Light = Light +channel-type.homeconnect.laundry_care_washer_idos1_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Normal = Normal +channel-type.homeconnect.laundry_care_washer_idos1_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Strong = Strong +channel-type.homeconnect.laundry_care_washer_idos2.label = i-Dos 2 +channel-type.homeconnect.laundry_care_washer_idos2.description = This status indicates whether i-Dos 2 is activated for a washer program of the home appliance. (If appliance supports i-Dos) +channel-type.homeconnect.laundry_care_washer_idos2_level.label = i-Dos 2 Dosing Level +channel-type.homeconnect.laundry_care_washer_idos2_level.description = This status defines the i-Dos dosing level of a washer program of the home appliance. (If appliance supports i-Dos) +channel-type.homeconnect.laundry_care_washer_idos2_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Off = Off +channel-type.homeconnect.laundry_care_washer_idos2_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Light = Light +channel-type.homeconnect.laundry_care_washer_idos2_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Normal = Normal +channel-type.homeconnect.laundry_care_washer_idos2_level.state.option.LaundryCare.Washer.EnumType.IDosingLevel.Strong = Strong +channel-type.homeconnect.laundry_care_washer_less_ironing.label = Less Ironing +channel-type.homeconnect.laundry_care_washer_less_ironing.description = This status indicates whether less ironing is activated for a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_load_recommendation.label = Load Recommendation +channel-type.homeconnect.laundry_care_washer_load_recommendation.description = This channel indicates the maximum laundry load recommended for a program of the home appliance. +channel-type.homeconnect.laundry_care_washer_pre_wash.label = Pre-Wash +channel-type.homeconnect.laundry_care_washer_pre_wash.description = This status indicates whether the pre-wash is activated for a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_rinse_hold.label = Rinse Hold +channel-type.homeconnect.laundry_care_washer_rinse_hold.description = This status indicates whether the spin function is deactivated for a washer program of the home appliance (washing will remain in the water after the last rinse cycle). +channel-type.homeconnect.laundry_care_washer_rinse_plus.label = Rinse Plus +channel-type.homeconnect.laundry_care_washer_rinse_plus.description = This status defines the number of additional rinses of a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_rinse_plus.state.option.LaundryCare.Washer.EnumType.RinsePlus.Off = None +channel-type.homeconnect.laundry_care_washer_rinse_plus.state.option.LaundryCare.Washer.EnumType.RinsePlus.Plus1 = +1 +channel-type.homeconnect.laundry_care_washer_rinse_plus.state.option.LaundryCare.Washer.EnumType.RinsePlus.Plus2 = +2 +channel-type.homeconnect.laundry_care_washer_rinse_plus.state.option.LaundryCare.Washer.EnumType.RinsePlus.Plus3 = +3 +channel-type.homeconnect.laundry_care_washer_soak.label = Soaking +channel-type.homeconnect.laundry_care_washer_soak.description = This status indicates whether the soaking is activated for a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_spin_speed.label = Spin Speed +channel-type.homeconnect.laundry_care_washer_spin_speed.description = This status defines the spin speed of a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.Off = No spinning +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM400 = 400 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM600 = 600 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM800 = 800 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM1000 = 1000 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM1200 = 1200 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM1400 = 1400 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.RPM1600 = 1600 rpm +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.Auto = Auto +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.UlNo = No spinning (US/CA) +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.UlLow = Low (US/CA) +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.UlMedium = Medium (US/CA) +channel-type.homeconnect.laundry_care_washer_spin_speed.state.option.LaundryCare.Washer.EnumType.SpinSpeed.UlHigh = High (US/CA) +channel-type.homeconnect.laundry_care_washer_temperature.label = Washing Program Temperature +channel-type.homeconnect.laundry_care_washer_temperature.description = This status describes the temperature of the washing program of the home appliance. +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.Cold = Cold water +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC20 = 20 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC30 = 30 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC40 = 40 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC50 = 50 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC60 = 60 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC70 = 70 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC80 = 80 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.GC90 = 90 °C +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.Auto = Auto +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.UlCold = Cold (US/CA) +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.UlWarm = Warm (US/CA) +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.UlHot = Hot (US/CA) +channel-type.homeconnect.laundry_care_washer_temperature.state.option.LaundryCare.Washer.EnumType.Temperature.UlExtraHot = Extra hot (US/CA) +channel-type.homeconnect.laundry_care_washer_vario_perfect.label = Vario Perfect +channel-type.homeconnect.laundry_care_washer_vario_perfect.description = This status defines the vario perfect mode of a washer program of the home appliance. +channel-type.homeconnect.laundry_care_washer_vario_perfect.state.option.LaundryCare.Common.EnumType.VarioPerfect.Off = Off +channel-type.homeconnect.laundry_care_washer_vario_perfect.state.option.LaundryCare.Common.EnumType.VarioPerfect.SpeedPerfect = Vario Speed +channel-type.homeconnect.local_control_active_state.label = Local Control State +channel-type.homeconnect.local_control_active_state.description = This status indicates whether the home appliance is currently manually controlled by the user operating the home appliance, e.g. opening the door or pressing a button. +channel-type.homeconnect.operation_state.label = Operation State +channel-type.homeconnect.operation_state.description = This status describes the operation state of the home appliance. +channel-type.homeconnect.oven_current_cavity_temperature.label = Cavity Temperature +channel-type.homeconnect.oven_current_cavity_temperature.description = This status describes the oven cavity temperature of the home appliance. +channel-type.homeconnect.program_energy.label = Program Energy +channel-type.homeconnect.program_energy.description = This channel provides the estimated energy required in percentage for a program of the home appliance. +channel-type.homeconnect.program_progress_state.label = Progress State +channel-type.homeconnect.program_progress_state.description = This status describes the program progress of the home appliance. +channel-type.homeconnect.program_water.label = Program Water +channel-type.homeconnect.program_water.description = This channel provides the estimated water required in percentage for a program of the home appliance. +channel-type.homeconnect.remaining_program_time_state.label = Remaining Program Time +channel-type.homeconnect.remaining_program_time_state.description = This status indicates the remaining program time of the home appliance. +channel-type.homeconnect.remote_control_active_state.label = Remote Control Activation State +channel-type.homeconnect.remote_control_active_state.description = This status indicates whether the allowance for remote controlling is enabled. +channel-type.homeconnect.remote_start_allowance_state.label = Remote Start Allowance State +channel-type.homeconnect.remote_start_allowance_state.description = This status indicates whether the remote program start is enabled. This can happen due to a programmatic change (only disabling), or manually by the user changing the flag locally on the home appliance, or automatically after a certain duration - usually 24 hours. +channel-type.homeconnect.selected_program_state.label = Selected Program +channel-type.homeconnect.selected_program_state.description = This state describes the selected program of the home appliance. +channel-type.homeconnect.setpoint_temperature.label = Setpoint Temperature +channel-type.homeconnect.setpoint_temperature.description = This status describes the intended cooking compartment temperature of the home appliance. +channel-type.homeconnect.setpoint_temperature_freezer.label = Freezer temperature +channel-type.homeconnect.setpoint_temperature_freezer.description = Target temperature of the freezer compartment (Range depends on appliance - common range -16 to -24°C). +channel-type.homeconnect.setpoint_temperature_refrigerator.label = Refrigerator Temperature +channel-type.homeconnect.setpoint_temperature_refrigerator.description = Target temperature of the refrigerator compartment (Range depends on appliance - common range 2 to 8°C). +channel-type.homeconnect.super_mode_freezer.label = Freezer Super Mode +channel-type.homeconnect.super_mode_freezer.description = This setting has no impact on setpoint temperatures but will make the freezer compartment cool to the lowest possible temperature until it is disabled manually by the customer or by the home appliance because of a timeout. +channel-type.homeconnect.super_mode_refrigerator.label = Refrigerator Super Mode +channel-type.homeconnect.super_mode_refrigerator.description = The setting has no impact on setpoint temperatures but will make the fridge compartment cool to the lowest possible temperature until it is disabled manually by the customer or by the HA because of a timeout. diff --git a/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/i18n/homematic.properties b/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/i18n/homematic.properties new file mode 100644 index 0000000000000..4a1d9f0812a1b --- /dev/null +++ b/bundles/org.openhab.binding.homematic/src/main/resources/OH-INF/i18n/homematic.properties @@ -0,0 +1,56 @@ +# binding + +binding.homematic.name = Homematic Binding +binding.homematic.description = This is the binding for Homematic gateways + +# thing types + +thing-type.homematic.bridge.label = Homematic Bridge +thing-type.homematic.bridge.description = The Homematic bridge represents a Homematic gateway + +# thing types config + +thing-type.config.homematic.bridge.binCallbackPort.label = BIN-RPC Callback Port +thing-type.config.homematic.bridge.binCallbackPort.description = Callback port of the binding's BIN-RPC server. If no value is specified, xmlCallbackPort starts with 9126 and counts up +thing-type.config.homematic.bridge.bufferSize.label = Buffer Size +thing-type.config.homematic.bridge.bufferSize.description = Size of the response buffer retrieved from the gateway (default 2048 kB) +thing-type.config.homematic.bridge.callbackHost.label = Callback Network Address +thing-type.config.homematic.bridge.callbackHost.description = Callback network address of the runtime, default is auto-discovery +thing-type.config.homematic.bridge.callbackRegTimeout.label = Callback Reg. Timeout +thing-type.config.homematic.bridge.callbackRegTimeout.description = Maximum time in seconds for callback registration in the Homematic gateway. +thing-type.config.homematic.bridge.cuxdPort.label = CUxD Port +thing-type.config.homematic.bridge.cuxdPort.description = The port number of the CUxD daemon +thing-type.config.homematic.bridge.discoveryTimeToLive.label = Discovery Time to Live +thing-type.config.homematic.bridge.discoveryTimeToLive.description = The time to live for discovery results of a Homematic gateway in seconds. (default = -1 -> infinite) +thing-type.config.homematic.bridge.factoryResetOnDeletion.label = Factory Reset Devices On Deletion +thing-type.config.homematic.bridge.factoryResetOnDeletion.description = If set to true, devices are factory reset when their corresponding things are removed. Due to the factory reset, the device will also be unpaired from the gateway, even if "unpairOnDeletion" is set to false! +thing-type.config.homematic.bridge.gatewayAddress.label = Gateway Address +thing-type.config.homematic.bridge.gatewayAddress.description = Network address of the Homematic gateway +thing-type.config.homematic.bridge.gatewayType.label = Gateway Type +thing-type.config.homematic.bridge.gatewayType.description = Hint for the binding to identify the gateway type +thing-type.config.homematic.bridge.gatewayType.option.auto = Auto +thing-type.config.homematic.bridge.gatewayType.option.ccu = CCU +thing-type.config.homematic.bridge.gatewayType.option.noccu = NoCCU +thing-type.config.homematic.bridge.groupPort.label = Group Port +thing-type.config.homematic.bridge.groupPort.description = The port number of the Group daemon +thing-type.config.homematic.bridge.hmIpPort.label = HMIP Port +thing-type.config.homematic.bridge.hmIpPort.description = The port number of the Homematic IP daemon +thing-type.config.homematic.bridge.installModeDuration.label = Install Mode Duration +thing-type.config.homematic.bridge.installModeDuration.description = Time in seconds that the controller will be in install mode when a device discovery is initiated +thing-type.config.homematic.bridge.rfPort.label = RF Port +thing-type.config.homematic.bridge.rfPort.description = The port number of the RF daemon +thing-type.config.homematic.bridge.socketMaxAlive.label = Socket MaxAlive +thing-type.config.homematic.bridge.socketMaxAlive.description = The maximum lifetime of a socket connection to and from a Homematic gateway in seconds (default = 900) +thing-type.config.homematic.bridge.timeout.label = Timeout +thing-type.config.homematic.bridge.timeout.description = The timeout in seconds for connections to a Homematic gateway +thing-type.config.homematic.bridge.unpairOnDeletion.label = Unpair Devices On Deletion +thing-type.config.homematic.bridge.unpairOnDeletion.description = If set to true, devices are unpaired from the gateway when their corresponding things are removed. The option "factoryResetOnDeletion" also unpairs a device, so in order to avoid unpairing on deletion, both options need to be set to false! +thing-type.config.homematic.bridge.wiredPort.label = Wired Port +thing-type.config.homematic.bridge.wiredPort.description = The port number of the HS485 daemon +thing-type.config.homematic.bridge.xmlCallbackPort.label = XML-RPC Callback Port +thing-type.config.homematic.bridge.xmlCallbackPort.description = Callback port of the binding's XML-RPC server. If no value is specified, xmlCallbackPort starts with 9125 and counts up + +# channel types + +channel-type.homematic.DUTY_CYCLE_RATIO.label = Duty Cycle +channel-type.homematic.DUTY_CYCLE_RATIO.description = Current duty cycle usage diff --git a/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties new file mode 100644 index 0000000000000..446dedfeb3658 --- /dev/null +++ b/bundles/org.openhab.binding.homewizard/src/main/resources/OH-INF/i18n/homewizard.properties @@ -0,0 +1,39 @@ +# binding + +binding.homewizard.name = HomeWizard Binding +binding.homewizard.description = This binding provides access to the data provided by the HomeWizard Wi-Fi P1 meter on it's local HTTP interface. + +# thing types + +thing-type.homewizard.p1_wifi_meter.label = HomeWizard Wi-Fi P1 Meter +thing-type.homewizard.p1_wifi_meter.description = This thing provides the measurement data that is available through the http interface of the HomeWizard Wi-Fi P1 Meter. + +# thing types config + +thing-type.config.homewizard.p1_wifi_meter.ipAddress.label = Network Address +thing-type.config.homewizard.p1_wifi_meter.ipAddress.description = The IP or host name of the P1 Meter. +thing-type.config.homewizard.p1_wifi_meter.refreshDelay.label = Refresh Interval +thing-type.config.homewizard.p1_wifi_meter.refreshDelay.description = The refresh interval in seconds for polling the P1 Meter. + +# channel types + +channel-type.homewizard.active_power.label = Current Total Net Power +channel-type.homewizard.active_power.description = This channel provides the current net total power in W. It will be below 0 if power is currently being exported. +channel-type.homewizard.active_power_l1.label = Current Phase 1 Net Power +channel-type.homewizard.active_power_l1.description = This channel provides the current net phase 1 power in W. It will be below 0 if power is currently being exported. +channel-type.homewizard.active_power_l2.label = Current Phase 2 Net Power +channel-type.homewizard.active_power_l2.description = This channel provides the current net phase 2 power in W. It will be below 0 if power is currently being exported. It will be 0 for single phase systems. +channel-type.homewizard.active_power_l3.label = Current Phase 3 Net Power +channel-type.homewizard.active_power_l3.description = This channel provides the current net phase 3 power in W. It will be below 0 if power is currently being exported. It will be 0 for single phase systems. +channel-type.homewizard.gas_timestamp.label = Gas Update Time Stamp +channel-type.homewizard.gas_timestamp.description = This channel provides the time stamp of the total_gas measurement. +channel-type.homewizard.total_energy_export_t1.label = Total Exported Energy Counter 1 +channel-type.homewizard.total_energy_export_t1.description = This channel provides the most recently reported total exported energy in kWh by counter 1, most commonly used for export during the night or weekend. +channel-type.homewizard.total_energy_export_t2.label = Total Exported Energy Counter 2 +channel-type.homewizard.total_energy_export_t2.description = This channel provides the most recently reported total exported energy in kWh by counter 2, most commonly used for export during the day. +channel-type.homewizard.total_energy_import_t1.label = Total Imported Energy Counter 1 +channel-type.homewizard.total_energy_import_t1.description = This channel provides the most recently reported total imported energy in kWh by counter 1, most commonly used for import during the night or weekend. +channel-type.homewizard.total_energy_import_t2.label = Total Imported Energy Counter 2 +channel-type.homewizard.total_energy_import_t2.description = This channel provides the most recently reported total imported energy in kWh by counter 2, most commonly used for import during the day. +channel-type.homewizard.total_gas.label = Total Imported Gas +channel-type.homewizard.total_gas.description = This channel provides the most recently reported total imported gas in m^3. It does not get updated as frequently as the data in the other channels, the gas_timestamp channel provides the time stamp of the most recent update. diff --git a/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/i18n/hpprinter.properties b/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/i18n/hpprinter.properties new file mode 100644 index 0000000000000..1ebf0fa13d310 --- /dev/null +++ b/bundles/org.openhab.binding.hpprinter/src/main/resources/OH-INF/i18n/hpprinter.properties @@ -0,0 +1,60 @@ +# binding + +binding.hpprinter.name = HP Printer Binding +binding.hpprinter.description = Binding for HP Printers with Embedded Web Servers + +# thing types + +thing-type.hpprinter.printer.label = HP Printer +thing-type.hpprinter.printer.description = An HP Printer. + +# thing types config + +thing-type.config.hpprinter.config.ipAddress.label = Network Address +thing-type.config.hpprinter.config.ipAddress.description = The IP or host name of the HP Printer +thing-type.config.hpprinter.config.statusInterval.label = Status Interval +thing-type.config.hpprinter.config.statusInterval.description = The refresh interval in seconds for polling status information +thing-type.config.hpprinter.config.usageInterval.label = Usage Interval +thing-type.config.hpprinter.config.usageInterval.description = The refresh interval in seconds for polling the printer usage information + +# channel group types + +channel-group-type.hpprinter.app.label = Application +channel-group-type.hpprinter.app.description = Application Usage by Device or Operating System +channel-group-type.hpprinter.copy.label = Copy +channel-group-type.hpprinter.copy.description = Copy Application Usage Information +channel-group-type.hpprinter.ink.label = Ink/Toner Levels +channel-group-type.hpprinter.ink.description = Ink/Toner amounts for each cartridge. +channel-group-type.hpprinter.other.label = Other +channel-group-type.hpprinter.other.description = Other Usage or Details +channel-group-type.hpprinter.printerStatus.label = Status +channel-group-type.hpprinter.printerStatus.description = Printer Statuses +channel-group-type.hpprinter.scan.label = Scan +channel-group-type.hpprinter.scan.description = Scan Application Usage Information +channel-group-type.hpprinter.scanner.label = Scanner +channel-group-type.hpprinter.scanner.description = Scanner Engine Usage Information +channel-group-type.hpprinter.usageInfo.label = Printer +channel-group-type.hpprinter.usageInfo.description = Print Engine Usage Information + +# channel types + +channel-type.hpprinter.cumlMarkingUsed.label = Cumulative Marking Used +channel-type.hpprinter.cumlMarkingUsed.description = Shows the amount of Ink/Toner used +channel-type.hpprinter.inkLevel.label = Ink Level +channel-type.hpprinter.inkLevel.description = Shows the amount of Ink/Toner remaining +channel-type.hpprinter.readonlyswitch.label = Read Only Switch Item +channel-type.hpprinter.status.label = Status +channel-type.hpprinter.status.description = Printer Status +channel-type.hpprinter.status.state.option.ready = Idle +channel-type.hpprinter.status.state.option.processing = Printing +channel-type.hpprinter.status.state.option.scanProcessing = Scanning +channel-type.hpprinter.status.state.option.inPowerSave = Power Save +channel-type.hpprinter.status.state.option.initializing = Initializing +channel-type.hpprinter.status.state.option.closeDoorOrCover = Door/Cover +channel-type.hpprinter.status.state.option.inkSystemInitializing = Loading Ink +channel-type.hpprinter.status.state.option.shuttingDown = Shutting Down +channel-type.hpprinter.status.state.option.replaceCartridgeOut = Cartridge Depleted +channel-type.hpprinter.totals.label = Totals +channel-type.hpprinter.totals.description = Amount of pages. +channel-type.hpprinter.totalsAdv.label = Totals +channel-type.hpprinter.totalsAdv.description = Amount of pages. diff --git a/bundles/org.openhab.binding.http/src/main/resources/OH-INF/i18n/http.properties b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/i18n/http.properties new file mode 100644 index 0000000000000..b55c127de56f2 --- /dev/null +++ b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/i18n/http.properties @@ -0,0 +1,240 @@ +# binding + +binding.http.name = HTTP Binding +binding.http.description = This is the binding for retrieving and processing HTTP resources. + +# thing types + +thing-type.http.url.label = HTTP URL Thing +thing-type.http.url.description = Represents a base URL and all associated requests. + +# thing types config + +thing-type.config.http.url.authMode.label = Authentication Mode +thing-type.config.http.url.authMode.option.BASIC = Basic Authentication +thing-type.config.http.url.authMode.option.BASIC_PREEMPTIVE = Preemptive Basic Authentication +thing-type.config.http.url.authMode.option.DIGEST = Digest Authentication +thing-type.config.http.url.baseURL.label = Base URL +thing-type.config.http.url.baseURL.description = The URL set here can be extended in the channel configuration. +thing-type.config.http.url.bufferSize.label = Buffer Size +thing-type.config.http.url.bufferSize.description = Size of the response buffer (default 2048 kB) +thing-type.config.http.url.commandMethod.label = Command Method +thing-type.config.http.url.commandMethod.description = HTTP method (GET,POST, PUT) for sending commands. +thing-type.config.http.url.commandMethod.option.GET = GET +thing-type.config.http.url.commandMethod.option.POST = POST +thing-type.config.http.url.commandMethod.option.PUT = PUT +thing-type.config.http.url.contentType.label = Content Type +thing-type.config.http.url.contentType.description = The MIME content type. Only used for `POST` and `PUT`. +thing-type.config.http.url.contentType.option.application/json = application/json +thing-type.config.http.url.contentType.option.application/xml = application/xml +thing-type.config.http.url.contentType.option.text/html = text/html +thing-type.config.http.url.contentType.option.text/plain = text/plain +thing-type.config.http.url.contentType.option.text/xml = text/xml +thing-type.config.http.url.delay.label = Delay +thing-type.config.http.url.delay.description = Delay between to requests +thing-type.config.http.url.encoding.label = Fallback Encoding +thing-type.config.http.url.encoding.description = Fallback Encoding text received by this thing's channels. +thing-type.config.http.url.headers.label = Headers +thing-type.config.http.url.headers.description = Additional headers send along with the request +thing-type.config.http.url.ignoreSSLErrors.label = Ignore SSL Errors +thing-type.config.http.url.ignoreSSLErrors.description = If set to true ignores invalid SSL certificate errors. This is potentially dangerous. +thing-type.config.http.url.password.label = Password +thing-type.config.http.url.password.description = Basic Authentication password +thing-type.config.http.url.refresh.label = Refresh Time +thing-type.config.http.url.refresh.description = Time between two refreshes of all channels +thing-type.config.http.url.stateMethod.label = State Method +thing-type.config.http.url.stateMethod.description = HTTP method (GET,POST, PUT) for retrieving a status. +thing-type.config.http.url.stateMethod.option.GET = GET +thing-type.config.http.url.stateMethod.option.POST = POST +thing-type.config.http.url.stateMethod.option.PUT = PUT +thing-type.config.http.url.timeout.label = Timeout +thing-type.config.http.url.timeout.description = The timeout in ms for each request +thing-type.config.http.url.username.label = Username +thing-type.config.http.url.username.description = Basic Authentication username + +# channel types + +channel-type.http.color.label = Color Channel +channel-type.http.contact.label = Contact Channel +channel-type.http.datetime.label = DateTime Channel +channel-type.http.dimmer.label = Dimmer Channel +channel-type.http.image.label = Image Channel +channel-type.http.location.label = Location Channel +channel-type.http.number.label = Number Channel +channel-type.http.player.label = Player Channel +channel-type.http.rollershutter.label = Rollershutter Channel +channel-type.http.string.label = String Channel +channel-type.http.switch.label = Switch Channel + +# channel types config + +channel-type.config.http.channel-config-color.colorMode.label = Color Mode +channel-type.config.http.channel-config-color.colorMode.description = Color mode for parsing incoming and sending outgoing values +channel-type.config.http.channel-config-color.colorMode.option.HSB = HSB +channel-type.config.http.channel-config-color.colorMode.option.RGB = RGB +channel-type.config.http.channel-config-color.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-color.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-color.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-color.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-color.decreaseValue.label = Decrease Value +channel-type.config.http.channel-config-color.decreaseValue.description = The value that represents DECREASE +channel-type.config.http.channel-config-color.increaseValue.label = Increase Value +channel-type.config.http.channel-config-color.increaseValue.description = The value that represents INCREASE +channel-type.config.http.channel-config-color.mode.label = Read/Write Mode +channel-type.config.http.channel-config-color.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-color.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-color.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-color.offValue.label = Off Value +channel-type.config.http.channel-config-color.offValue.description = The value that represents OFF +channel-type.config.http.channel-config-color.onValue.label = On Value +channel-type.config.http.channel-config-color.onValue.description = The value that represents ON +channel-type.config.http.channel-config-color.stateContent.label = State Content +channel-type.config.http.channel-config-color.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-color.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-color.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-color.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-color.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-color.step.label = Increase/Decrease Step +channel-type.config.http.channel-config-color.step.description = The value by which the current brightness is increased/decreased if the corresponding command is received +channel-type.config.http.channel-config-contact.closedValue.label = Closed Value +channel-type.config.http.channel-config-contact.closedValue.description = The value that represents CLOSED +channel-type.config.http.channel-config-contact.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-contact.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-contact.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-contact.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-contact.mode.label = Read/Write Mode +channel-type.config.http.channel-config-contact.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-contact.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-contact.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-contact.openValue.label = Open Value +channel-type.config.http.channel-config-contact.openValue.description = The value that represents OPEN +channel-type.config.http.channel-config-contact.stateContent.label = State Content +channel-type.config.http.channel-config-contact.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-contact.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-contact.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-contact.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-contact.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-dimmer.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-dimmer.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-dimmer.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-dimmer.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-dimmer.decreaseValue.label = Decrease Value +channel-type.config.http.channel-config-dimmer.decreaseValue.description = The value that represents DECREASE +channel-type.config.http.channel-config-dimmer.increaseValue.label = Increase Value +channel-type.config.http.channel-config-dimmer.increaseValue.description = The value that represents INCREASE +channel-type.config.http.channel-config-dimmer.mode.label = Read/Write Mode +channel-type.config.http.channel-config-dimmer.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-dimmer.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-dimmer.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-dimmer.offValue.label = Off Value +channel-type.config.http.channel-config-dimmer.offValue.description = The value that represents OFF +channel-type.config.http.channel-config-dimmer.onValue.label = On Value +channel-type.config.http.channel-config-dimmer.onValue.description = The value that represents ON +channel-type.config.http.channel-config-dimmer.stateContent.label = State Content +channel-type.config.http.channel-config-dimmer.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-dimmer.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-dimmer.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-dimmer.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-dimmer.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-dimmer.step.label = Increase/Decrease Step +channel-type.config.http.channel-config-dimmer.step.description = The value by which the current brightness is increased/decreased if the corresponding command is received +channel-type.config.http.channel-config-image.stateContent.label = State Content +channel-type.config.http.channel-config-image.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-image.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-image.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-number.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-number.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-number.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-number.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-number.mode.label = Read/Write Mode +channel-type.config.http.channel-config-number.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-number.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-number.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-number.stateContent.label = State Content +channel-type.config.http.channel-config-number.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-number.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-number.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-number.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-number.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-number.unit.label = Unit +channel-type.config.http.channel-config-number.unit.description = Unit to append to the (transformed) value. +channel-type.config.http.channel-config-player.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-player.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-player.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-player.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-player.fastforwardValue.label = Fast Forward Value +channel-type.config.http.channel-config-player.fastforwardValue.description = The value that represents FASTFORWARD +channel-type.config.http.channel-config-player.mode.label = Read/Write Mode +channel-type.config.http.channel-config-player.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-player.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-player.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-player.nextValue.label = Next Value +channel-type.config.http.channel-config-player.nextValue.description = The value that represents NEXT +channel-type.config.http.channel-config-player.pauseValue.label = Pause Value +channel-type.config.http.channel-config-player.pauseValue.description = The value that represents PAUSE +channel-type.config.http.channel-config-player.playValue.label = Play Value +channel-type.config.http.channel-config-player.playValue.description = The value that represents PLAY +channel-type.config.http.channel-config-player.previousValue.label = Previous Value +channel-type.config.http.channel-config-player.previousValue.description = The value that represents PREVIOUS +channel-type.config.http.channel-config-player.rewindValue.label = Rewind Value +channel-type.config.http.channel-config-player.rewindValue.description = The value that represents REWIND +channel-type.config.http.channel-config-player.stateContent.label = State Content +channel-type.config.http.channel-config-player.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-player.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-player.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-player.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-player.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-rollershutter.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-rollershutter.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-rollershutter.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-rollershutter.commandTransformation.description = Transformation pattern used when sending values Chain multiple transformations with the mathematical intersection character "∩".. +channel-type.config.http.channel-config-rollershutter.downValue.label = Down Value +channel-type.config.http.channel-config-rollershutter.downValue.description = The value that represents DOWN +channel-type.config.http.channel-config-rollershutter.mode.label = Read/Write Mode +channel-type.config.http.channel-config-rollershutter.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-rollershutter.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-rollershutter.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-rollershutter.moveValue.label = Move Value +channel-type.config.http.channel-config-rollershutter.moveValue.description = The value that represents MOVE +channel-type.config.http.channel-config-rollershutter.stateContent.label = State Content +channel-type.config.http.channel-config-rollershutter.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-rollershutter.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-rollershutter.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-rollershutter.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-rollershutter.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-rollershutter.stopValue.label = Stop Value +channel-type.config.http.channel-config-rollershutter.stopValue.description = The value that represents STOP +channel-type.config.http.channel-config-rollershutter.upValue.label = Up Value +channel-type.config.http.channel-config-rollershutter.upValue.description = The value that represents UP +channel-type.config.http.channel-config-switch.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config-switch.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config-switch.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config-switch.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config-switch.mode.label = Read/Write Mode +channel-type.config.http.channel-config-switch.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config-switch.mode.option.READONLY = Read Only +channel-type.config.http.channel-config-switch.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config-switch.offValue.label = Off Value +channel-type.config.http.channel-config-switch.offValue.description = The value that represents OFF +channel-type.config.http.channel-config-switch.onValue.label = On Value +channel-type.config.http.channel-config-switch.onValue.description = The value that represents ON +channel-type.config.http.channel-config-switch.stateContent.label = State Content +channel-type.config.http.channel-config-switch.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config-switch.stateExtension.label = State URL Extension +channel-type.config.http.channel-config-switch.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config-switch.stateTransformation.label = State Transformation +channel-type.config.http.channel-config-switch.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config.commandExtension.label = Command URL Extension +channel-type.config.http.channel-config.commandExtension.description = This value is added to the base URL configured in the thing for sending values. +channel-type.config.http.channel-config.commandTransformation.label = Command Transformation +channel-type.config.http.channel-config.commandTransformation.description = Transformation pattern used when sending values. Chain multiple transformations with the mathematical intersection character "∩". +channel-type.config.http.channel-config.mode.label = Read/Write Mode +channel-type.config.http.channel-config.mode.option.READWRITE = Read/Write +channel-type.config.http.channel-config.mode.option.READONLY = Read Only +channel-type.config.http.channel-config.mode.option.WRITEONLY = Write Only +channel-type.config.http.channel-config.stateContent.label = State Content +channel-type.config.http.channel-config.stateContent.description = Content for state request (only used if method is POST/PUT) +channel-type.config.http.channel-config.stateExtension.label = State URL Extension +channel-type.config.http.channel-config.stateExtension.description = This value is added to the base URL configured in the thing for retrieving values. +channel-type.config.http.channel-config.stateTransformation.label = State Transformation +channel-type.config.http.channel-config.stateTransformation.description = Transformation pattern used when receiving values. Chain multiple transformations with the mathematical intersection character "∩". diff --git a/bundles/org.openhab.binding.hydrawise/src/main/resources/OH-INF/i18n/hydrawise.properties b/bundles/org.openhab.binding.hydrawise/src/main/resources/OH-INF/i18n/hydrawise.properties new file mode 100644 index 0000000000000..3b7f23409e7ff --- /dev/null +++ b/bundles/org.openhab.binding.hydrawise/src/main/resources/OH-INF/i18n/hydrawise.properties @@ -0,0 +1,270 @@ +# binding + +binding.hydrawise.name = Hydrawise Binding +binding.hydrawise.description = This is the binding for Hydrawise irrigation systems. + +# thing types + +thing-type.hydrawise.account.label = Hydrawise Account Thing +thing-type.hydrawise.account.description = Hydrawise account +thing-type.hydrawise.controller.label = Hydrawise Controller Thing +thing-type.hydrawise.controller.description = Hydrawise connected irrigation controller +thing-type.hydrawise.controller.group.forecast1.label = Today's Weather +thing-type.hydrawise.controller.group.forecast1.description = Today's weather forecast +thing-type.hydrawise.controller.group.forecast2.label = Day 2 Weather +thing-type.hydrawise.controller.group.forecast2.description = Day 2 weather forecast +thing-type.hydrawise.controller.group.forecast3.label = Day 3 Weather +thing-type.hydrawise.controller.group.forecast3.description = Day 3 weather forecast +thing-type.hydrawise.controller.group.sensor1.label = Sensor 1 +thing-type.hydrawise.controller.group.sensor1.description = Sensor 1 +thing-type.hydrawise.controller.group.sensor2.label = Sensor 2 +thing-type.hydrawise.controller.group.sensor2.description = Sensor 2 +thing-type.hydrawise.controller.group.sensor3.label = Sensor 3 +thing-type.hydrawise.controller.group.sensor3.description = Sensor 3 +thing-type.hydrawise.controller.group.sensor4.label = Sensor 4 +thing-type.hydrawise.controller.group.sensor4.description = Sensor 4 +thing-type.hydrawise.controller.group.zone1.label = Zone 1 +thing-type.hydrawise.controller.group.zone1.description = Sprinkler Zone 1 +thing-type.hydrawise.controller.group.zone2.label = Zone 2 +thing-type.hydrawise.controller.group.zone2.description = Sprinkler Zone 2 +thing-type.hydrawise.controller.group.zone3.label = Zone 3 +thing-type.hydrawise.controller.group.zone3.description = Sprinkler Zone 3 +thing-type.hydrawise.controller.group.zone4.label = Zone 4 +thing-type.hydrawise.controller.group.zone4.description = Sprinkler Zone 4 +thing-type.hydrawise.controller.group.zone5.label = Zone 5 +thing-type.hydrawise.controller.group.zone5.description = Sprinkler Zone 5 +thing-type.hydrawise.controller.group.zone6.label = Zone 6 +thing-type.hydrawise.controller.group.zone6.description = Sprinkler Zone 6 +thing-type.hydrawise.controller.group.zone7.label = Zone 7 +thing-type.hydrawise.controller.group.zone7.description = Sprinkler Zone 7 +thing-type.hydrawise.controller.group.zone8.label = Zone 8 +thing-type.hydrawise.controller.group.zone8.description = Sprinkler Zone 8 +thing-type.hydrawise.controller.group.zone9.label = Zone 9 +thing-type.hydrawise.controller.group.zone9.description = Sprinkler Zone 9 +thing-type.hydrawise.controller.group.zone10.label = Zone 10 +thing-type.hydrawise.controller.group.zone10.description = Sprinkler Zone 10 +thing-type.hydrawise.controller.group.zone11.label = Zone 11 +thing-type.hydrawise.controller.group.zone11.description = Sprinkler Zone 11 +thing-type.hydrawise.controller.group.zone12.label = Zone 12 +thing-type.hydrawise.controller.group.zone12.description = Sprinkler Zone 12 +thing-type.hydrawise.controller.group.zone13.label = Zone 13 +thing-type.hydrawise.controller.group.zone13.description = Sprinkler Zone 13 +thing-type.hydrawise.controller.group.zone14.label = Zone 14 +thing-type.hydrawise.controller.group.zone14.description = Sprinkler Zone 14 +thing-type.hydrawise.controller.group.zone15.label = Zone 15 +thing-type.hydrawise.controller.group.zone15.description = Sprinkler Zone 15 +thing-type.hydrawise.controller.group.zone16.label = Zone 16 +thing-type.hydrawise.controller.group.zone16.description = Sprinkler Zone 16 +thing-type.hydrawise.controller.group.zone17.label = Zone 17 +thing-type.hydrawise.controller.group.zone17.description = Sprinkler Zone 17 +thing-type.hydrawise.controller.group.zone18.label = Zone 18 +thing-type.hydrawise.controller.group.zone18.description = Sprinkler Zone 18 +thing-type.hydrawise.controller.group.zone19.label = Zone 19 +thing-type.hydrawise.controller.group.zone19.description = Sprinkler Zone 19 +thing-type.hydrawise.controller.group.zone20.label = Zone 20 +thing-type.hydrawise.controller.group.zone20.description = Sprinkler Zone 20 +thing-type.hydrawise.controller.group.zone21.label = Zone 21 +thing-type.hydrawise.controller.group.zone21.description = Sprinkler Zone 21 +thing-type.hydrawise.controller.group.zone22.label = Zone 22 +thing-type.hydrawise.controller.group.zone22.description = Sprinkler Zone 22 +thing-type.hydrawise.controller.group.zone23.label = Zone 23 +thing-type.hydrawise.controller.group.zone23.description = Sprinkler Zone 23 +thing-type.hydrawise.controller.group.zone24.label = Zone 24 +thing-type.hydrawise.controller.group.zone24.description = Sprinkler Zone 24 +thing-type.hydrawise.controller.group.zone25.label = Zone 25 +thing-type.hydrawise.controller.group.zone25.description = Sprinkler Zone 25 +thing-type.hydrawise.controller.group.zone26.label = Zone 26 +thing-type.hydrawise.controller.group.zone26.description = Sprinkler Zone 26 +thing-type.hydrawise.controller.group.zone27.label = Zone 27 +thing-type.hydrawise.controller.group.zone27.description = Sprinkler Zone 27 +thing-type.hydrawise.controller.group.zone28.label = Zone 28 +thing-type.hydrawise.controller.group.zone28.description = Sprinkler Zone 28 +thing-type.hydrawise.controller.group.zone29.label = Zone 29 +thing-type.hydrawise.controller.group.zone29.description = Sprinkler Zone 29 +thing-type.hydrawise.controller.group.zone30.label = Zone 30 +thing-type.hydrawise.controller.group.zone30.description = Sprinkler Zone 30 +thing-type.hydrawise.controller.group.zone31.label = Zone 31 +thing-type.hydrawise.controller.group.zone31.description = Sprinkler Zone 31 +thing-type.hydrawise.controller.group.zone32.label = Zone 32 +thing-type.hydrawise.controller.group.zone32.description = Sprinkler Zone 32 +thing-type.hydrawise.controller.group.zone33.label = Zone 33 +thing-type.hydrawise.controller.group.zone33.description = Sprinkler Zone 33 +thing-type.hydrawise.controller.group.zone34.label = Zone 34 +thing-type.hydrawise.controller.group.zone34.description = Sprinkler Zone 34 +thing-type.hydrawise.controller.group.zone35.label = Zone 35 +thing-type.hydrawise.controller.group.zone35.description = Sprinkler Zone 35 +thing-type.hydrawise.controller.group.zone36.label = Zone 36 +thing-type.hydrawise.controller.group.zone36.description = Sprinkler Zone 36 +thing-type.hydrawise.local.label = Hydrawise Local Thing +thing-type.hydrawise.local.description = Hydrawise local connected irrigation controller +thing-type.hydrawise.local.group.zone1.label = Zone 1 +thing-type.hydrawise.local.group.zone1.description = Sprinkler Zone 1 +thing-type.hydrawise.local.group.zone2.label = Zone 2 +thing-type.hydrawise.local.group.zone2.description = Sprinkler Zone 2 +thing-type.hydrawise.local.group.zone3.label = Zone 3 +thing-type.hydrawise.local.group.zone3.description = Sprinkler Zone 3 +thing-type.hydrawise.local.group.zone4.label = Zone 4 +thing-type.hydrawise.local.group.zone4.description = Sprinkler Zone 4 +thing-type.hydrawise.local.group.zone5.label = Zone 5 +thing-type.hydrawise.local.group.zone5.description = Sprinkler Zone 5 +thing-type.hydrawise.local.group.zone6.label = Zone 6 +thing-type.hydrawise.local.group.zone6.description = Sprinkler Zone 6 +thing-type.hydrawise.local.group.zone7.label = Zone 7 +thing-type.hydrawise.local.group.zone7.description = Sprinkler Zone 7 +thing-type.hydrawise.local.group.zone8.label = Zone 8 +thing-type.hydrawise.local.group.zone8.description = Sprinkler Zone 8 +thing-type.hydrawise.local.group.zone9.label = Zone 9 +thing-type.hydrawise.local.group.zone9.description = Sprinkler Zone 9 +thing-type.hydrawise.local.group.zone10.label = Zone 10 +thing-type.hydrawise.local.group.zone10.description = Sprinkler Zone 10 +thing-type.hydrawise.local.group.zone11.label = Zone 11 +thing-type.hydrawise.local.group.zone11.description = Sprinkler Zone 11 +thing-type.hydrawise.local.group.zone12.label = Zone 12 +thing-type.hydrawise.local.group.zone12.description = Sprinkler Zone 12 +thing-type.hydrawise.local.group.zone13.label = Zone 13 +thing-type.hydrawise.local.group.zone13.description = Sprinkler Zone 13 +thing-type.hydrawise.local.group.zone14.label = Zone 14 +thing-type.hydrawise.local.group.zone14.description = Sprinkler Zone 14 +thing-type.hydrawise.local.group.zone15.label = Zone 15 +thing-type.hydrawise.local.group.zone15.description = Sprinkler Zone 15 +thing-type.hydrawise.local.group.zone16.label = Zone 16 +thing-type.hydrawise.local.group.zone16.description = Sprinkler Zone 16 +thing-type.hydrawise.local.group.zone17.label = Zone 17 +thing-type.hydrawise.local.group.zone17.description = Sprinkler Zone 17 +thing-type.hydrawise.local.group.zone18.label = Zone 18 +thing-type.hydrawise.local.group.zone18.description = Sprinkler Zone 18 +thing-type.hydrawise.local.group.zone19.label = Zone 19 +thing-type.hydrawise.local.group.zone19.description = Sprinkler Zone 19 +thing-type.hydrawise.local.group.zone20.label = Zone 20 +thing-type.hydrawise.local.group.zone20.description = Sprinkler Zone 20 +thing-type.hydrawise.local.group.zone21.label = Zone 21 +thing-type.hydrawise.local.group.zone21.description = Sprinkler Zone 21 +thing-type.hydrawise.local.group.zone22.label = Zone 22 +thing-type.hydrawise.local.group.zone22.description = Sprinkler Zone 22 +thing-type.hydrawise.local.group.zone23.label = Zone 23 +thing-type.hydrawise.local.group.zone23.description = Sprinkler Zone 23 +thing-type.hydrawise.local.group.zone24.label = Zone 24 +thing-type.hydrawise.local.group.zone24.description = Sprinkler Zone 24 +thing-type.hydrawise.local.group.zone25.label = Zone 25 +thing-type.hydrawise.local.group.zone25.description = Sprinkler Zone 25 +thing-type.hydrawise.local.group.zone26.label = Zone 26 +thing-type.hydrawise.local.group.zone26.description = Sprinkler Zone 26 +thing-type.hydrawise.local.group.zone27.label = Zone 27 +thing-type.hydrawise.local.group.zone27.description = Sprinkler Zone 27 +thing-type.hydrawise.local.group.zone28.label = Zone 28 +thing-type.hydrawise.local.group.zone28.description = Sprinkler Zone 28 +thing-type.hydrawise.local.group.zone29.label = Zone 29 +thing-type.hydrawise.local.group.zone29.description = Sprinkler Zone 29 +thing-type.hydrawise.local.group.zone30.label = Zone 30 +thing-type.hydrawise.local.group.zone30.description = Sprinkler Zone 30 +thing-type.hydrawise.local.group.zone31.label = Zone 31 +thing-type.hydrawise.local.group.zone31.description = Sprinkler Zone 31 +thing-type.hydrawise.local.group.zone32.label = Zone 32 +thing-type.hydrawise.local.group.zone32.description = Sprinkler Zone 32 +thing-type.hydrawise.local.group.zone33.label = Zone 33 +thing-type.hydrawise.local.group.zone33.description = Sprinkler Zone 33 +thing-type.hydrawise.local.group.zone34.label = Zone 34 +thing-type.hydrawise.local.group.zone34.description = Sprinkler Zone 34 +thing-type.hydrawise.local.group.zone35.label = Zone 35 +thing-type.hydrawise.local.group.zone35.description = Sprinkler Zone 35 +thing-type.hydrawise.local.group.zone36.label = Zone 36 +thing-type.hydrawise.local.group.zone36.description = Sprinkler Zone 36 + +# thing types config + +thing-type.config.hydrawise.account.password.label = Password +thing-type.config.hydrawise.account.password.description = Your Hydrawise account password, for security this will not be saved after the first login attempt unless the "Save Password" option is enabled +thing-type.config.hydrawise.account.refresh.label = Refresh interval +thing-type.config.hydrawise.account.refresh.description = Specifies the refresh interval in seconds +thing-type.config.hydrawise.account.savePassword.label = Save Password +thing-type.config.hydrawise.account.savePassword.description = By default, the password will not be persisted after the first login attempt unless this is enabled +thing-type.config.hydrawise.account.userName.label = User Name +thing-type.config.hydrawise.account.userName.description = Your Hydrawise account user name +thing-type.config.hydrawise.controller.controllerId.label = Controller ID +thing-type.config.hydrawise.controller.controllerId.description = The ID of a cloud connected irrigation controller +thing-type.config.hydrawise.local.host.label = Host +thing-type.config.hydrawise.local.host.description = Host or IP address of local controller +thing-type.config.hydrawise.local.password.label = password +thing-type.config.hydrawise.local.password.description = Password for local controller, found in the settings menu on the controller itself. +thing-type.config.hydrawise.local.refresh.label = Refresh interval +thing-type.config.hydrawise.local.refresh.description = Specifies the refresh interval in seconds +thing-type.config.hydrawise.local.username.label = User Name +thing-type.config.hydrawise.local.username.description = User name for controller, usually "admin" + +# channel group types + +channel-group-type.hydrawise.allzones.label = All Zones +channel-group-type.hydrawise.allzones.description = Commands that control all Hydrawise zones +channel-group-type.hydrawise.forecast.label = Weather Forecast +channel-group-type.hydrawise.forecast.description = Hydrawise weather forecast +channel-group-type.hydrawise.sensor.label = Sensor +channel-group-type.hydrawise.sensor.description = Hydrawise sensor +channel-group-type.hydrawise.system.label = System +channel-group-type.hydrawise.system.description = Controller system data +channel-group-type.hydrawise.zone.label = Zone +channel-group-type.hydrawise.zone.description = Hydrawise zone + +# channel types + +channel-type.hydrawise.active.label = Active +channel-type.hydrawise.active.description = Sensor active +channel-type.hydrawise.conditions.label = Conditions +channel-type.hydrawise.conditions.description = Weather conditions +channel-type.hydrawise.conditions.label = Conditions +channel-type.hydrawise.conditions.description = Weather conditions +channel-type.hydrawise.delay.label = Delay +channel-type.hydrawise.delay.description = Sensor delay +channel-type.hydrawise.duration.label = Duration +channel-type.hydrawise.duration.description = Next start duration +channel-type.hydrawise.evapotranspiration.label = Evapotranspiration +channel-type.hydrawise.evapotranspiration.description = Evapotranspiration amount +channel-type.hydrawise.humidity.label = Humidity +channel-type.hydrawise.humidity.description = Humidity percentage +channel-type.hydrawise.icon.label = Icon URL +channel-type.hydrawise.icon.description = Icon URL for this zone +channel-type.hydrawise.input.label = Input +channel-type.hydrawise.input.description = Sensor input +channel-type.hydrawise.lastcontacttime.label = Last Contact Time +channel-type.hydrawise.lastcontacttime.description = Last contact time of a controller +channel-type.hydrawise.name.label = Name +channel-type.hydrawise.name.description = Name +channel-type.hydrawise.name.label = Name +channel-type.hydrawise.name.description = Sensor name +channel-type.hydrawise.nextruntime.label = Next Run Time +channel-type.hydrawise.nextruntime.description = The next time this zone is scheduled to run +channel-type.hydrawise.offlevel.label = Off Level +channel-type.hydrawise.offlevel.description = Sensor off level +channel-type.hydrawise.offtimer.label = Off Timer +channel-type.hydrawise.offtimer.description = Sensor off timer +channel-type.hydrawise.precipitation.label = Precipitation +channel-type.hydrawise.precipitation.description = Precipitation amount +channel-type.hydrawise.probabilityofprecipitation.label = Probability Of Precipitation +channel-type.hydrawise.probabilityofprecipitation.description = Probability of precipitation percentage +channel-type.hydrawise.run.label = Run Zones +channel-type.hydrawise.run.description = Run or stop zones for the default time. +channel-type.hydrawise.runcustom.label = Run Zones With Custom Duration +channel-type.hydrawise.runcustom.description = Run zones now for a custom duration +channel-type.hydrawise.starttime.label = Start Time +channel-type.hydrawise.starttime.description = Next zone start time +channel-type.hydrawise.summary.label = Status Summary +channel-type.hydrawise.summary.description = Status summary +channel-type.hydrawise.suspend.label = Suspend Zones +channel-type.hydrawise.suspend.description = Suspends or resumes zones +channel-type.hydrawise.suspenduntil.label = Suspend Zones +channel-type.hydrawise.suspenduntil.description = Suspends zones until this date +channel-type.hydrawise.temperaturehigh.label = High temperature +channel-type.hydrawise.temperaturehigh.description = High temperature +channel-type.hydrawise.temperaturelow.label = Low Temperature +channel-type.hydrawise.temperaturelow.description = Low Temperature +channel-type.hydrawise.time.label = Forecast Time +channel-type.hydrawise.time.description = Forecast date and time +channel-type.hydrawise.timeleft.label = Time Left Seconds +channel-type.hydrawise.timeleft.description = Time left that zone will run for +channel-type.hydrawise.type.label = Type +channel-type.hydrawise.type.description = Zone Type +channel-type.hydrawise.type.label = Type +channel-type.hydrawise.type.description = Sensor type +channel-type.hydrawise.waterflow.label = Water Flow +channel-type.hydrawise.waterflow.description = Sensor water flow +channel-type.hydrawise.wind.label = Wind Speed +channel-type.hydrawise.wind.description = Wind speed diff --git a/bundles/org.openhab.binding.hyperion/src/main/resources/OH-INF/i18n/hyperion.properties b/bundles/org.openhab.binding.hyperion/src/main/resources/OH-INF/i18n/hyperion.properties new file mode 100644 index 0000000000000..56c524a75cef0 --- /dev/null +++ b/bundles/org.openhab.binding.hyperion/src/main/resources/OH-INF/i18n/hyperion.properties @@ -0,0 +1,63 @@ +# binding + +binding.hyperion.name = Hyperion Binding +binding.hyperion.description = This binding integrates openHAB with the Hyperion ambient lighting software. + +# thing types + +thing-type.hyperion.serverNG.label = Hyperion.ng Server +thing-type.hyperion.serverNG.description = This is a Hyperion.ng server +thing-type.hyperion.serverV1.label = Hyperion Server +thing-type.hyperion.serverV1.description = This is a Hyperion server + +# thing types config + +thing-type.config.hyperion.serverNG.host.label = Host Address +thing-type.config.hyperion.serverNG.host.description = The host address of the Hyperion server JSON API. +thing-type.config.hyperion.serverNG.origin.label = Origin +thing-type.config.hyperion.serverNG.origin.description = The origin used on color and effect commands. +thing-type.config.hyperion.serverNG.poll_frequency.label = Polling Frequency +thing-type.config.hyperion.serverNG.poll_frequency.description = How often (in seconds) to poll the Hyperion server for value changes. +thing-type.config.hyperion.serverNG.port.label = Port +thing-type.config.hyperion.serverNG.port.description = The port of the Hyperion server JSON API. +thing-type.config.hyperion.serverNG.priority.label = Priority +thing-type.config.hyperion.serverNG.priority.description = The priority associated with updates sent to the Hyperion server. +thing-type.config.hyperion.serverV1.host.label = Host Address +thing-type.config.hyperion.serverV1.host.description = The host address of the Hyperion server JSON API. +thing-type.config.hyperion.serverV1.poll_frequency.label = Polling Frequency +thing-type.config.hyperion.serverV1.poll_frequency.description = How often (in seconds) to poll the Hyperion server for value changes. +thing-type.config.hyperion.serverV1.port.label = Port +thing-type.config.hyperion.serverV1.port.description = The port of the Hyperion server JSON API. +thing-type.config.hyperion.serverV1.priority.label = Priority +thing-type.config.hyperion.serverV1.priority.description = The priority associated with updates sent to the Hyperion server. + +# channel types + +channel-type.hyperion.blackborder.label = Black Border +channel-type.hyperion.blackborder.description = Shows the current state of the black border component and allows the black border component to be enabled or disabled +channel-type.hyperion.boblightserver.label = UDP Listener +channel-type.hyperion.boblightserver.description = Shows the current state of the Boblight server component and allows the Boblight server component to be enabled or disabled +channel-type.hyperion.brightness.label = Brightness +channel-type.hyperion.brightness.description = Sets the brightness of the LEDs +channel-type.hyperion.clear.label = Clear Priority +channel-type.hyperion.clear.description = Clears the given Hyperion priority +channel-type.hyperion.color.label = Color +channel-type.hyperion.color.description = Sets the color effect of the LEDs +channel-type.hyperion.effect.label = Effect +channel-type.hyperion.effect.description = Sets the effect of the LEDs +channel-type.hyperion.enabled.label = Enabled +channel-type.hyperion.enabled.description = Shows whether Hyperion is currently enabled or not and allows enabling or disabling of Hyperion +channel-type.hyperion.forwarder.label = Forwarder +channel-type.hyperion.forwarder.description = Shows the current state of the forwarder component and allows the forwarder component to be enabled or disabled +channel-type.hyperion.grabber.label = Grabber +channel-type.hyperion.grabber.description = Shows the current state of the grabber component and allows the grabber component to be enabled or disabled +channel-type.hyperion.kodichecker.label = Kodi Checker +channel-type.hyperion.kodichecker.description = Shows the current state of the Kodi checker component and allows the Kodi checker component to be enabled or disabled +channel-type.hyperion.leddevice.label = LED Device +channel-type.hyperion.leddevice.description = Shows the current state of the LED component and allows the LED component to be enabled or disabled +channel-type.hyperion.smoothing.label = Smoothing +channel-type.hyperion.smoothing.description = Shows the current state of the smoothing component and allows the smoothing component to be enabled or disabled +channel-type.hyperion.udplistener.label = UDP Listener +channel-type.hyperion.udplistener.description = Shows the current state of the UDP listener component and allows the UDP listener component to be enabled or disabled +channel-type.hyperion.v4l.label = V4L Device +channel-type.hyperion.v4l.description = Shows the current state of the v4l component and allows the v4l component to be enabled or disabled diff --git a/bundles/org.openhab.binding.iammeter/src/main/resources/OH-INF/i18n/iammeter.properties b/bundles/org.openhab.binding.iammeter/src/main/resources/OH-INF/i18n/iammeter.properties new file mode 100644 index 0000000000000..6040047234065 --- /dev/null +++ b/bundles/org.openhab.binding.iammeter/src/main/resources/OH-INF/i18n/iammeter.properties @@ -0,0 +1,60 @@ +# binding + +binding.iammeter.name = Iammeter Binding +binding.iammeter.description = The Iammeter binding pull your Iammeter power meter data from LAN. + +# thing types + +thing-type.iammeter.powermeter.label = Iammeter Power Meter 3162/3080 +thing-type.iammeter.powermeter.description = Single phase PowerMeter for Iammeter Binding +thing-type.iammeter.powermeter3080T.label = Iammeter Power Meter 3080T +thing-type.iammeter.powermeter3080T.description = 3 phases PowerMeter for Iammeter 3080T Binding +thing-type.iammeter.powermeter3080T.group.powerPhaseA.label = Power Phase A +thing-type.iammeter.powermeter3080T.group.powerPhaseA.description = Power phase 1 for Iammeter device +thing-type.iammeter.powermeter3080T.group.powerPhaseB.label = Power Phase B +thing-type.iammeter.powermeter3080T.group.powerPhaseB.description = Power phase 2 for Iammeter device +thing-type.iammeter.powermeter3080T.group.powerPhaseC.label = Power Phase C +thing-type.iammeter.powermeter3080T.group.powerPhaseC.description = Power phase 3 for Iammeter device + +# thing types config + +thing-type.config.iammeter.powermeter.host.label = Device's IP Address +thing-type.config.iammeter.powermeter.host.description = IP address for your device +thing-type.config.iammeter.powermeter.password.label = Password +thing-type.config.iammeter.powermeter.password.description = password to access device +thing-type.config.iammeter.powermeter.port.label = Device's Port +thing-type.config.iammeter.powermeter.port.description = Port +thing-type.config.iammeter.powermeter.refreshInterval.label = Refresh interval in seconds +thing-type.config.iammeter.powermeter.username.label = User Name +thing-type.config.iammeter.powermeter.username.description = User name to access device + +# channel group types + +channel-group-type.iammeter.powerPhaseGroup.label = Power Phase + +# channel types + +channel-type.iammeter.current.label = Current +channel-type.iammeter.current.description = current for phase A +channel-type.iammeter.current.label = Current +channel-type.iammeter.current.description = current for phase A +channel-type.iammeter.exportgrid.label = Exportgrid +channel-type.iammeter.exportgrid.description = exportgrid for phase A +channel-type.iammeter.exportgrid.label = Exportgrid +channel-type.iammeter.exportgrid.description = exportgrid for phase A +channel-type.iammeter.frequency.label = Frequency +channel-type.iammeter.frequency.description = frequency for phase A +channel-type.iammeter.importenergy.label = ImportEnergy +channel-type.iammeter.importenergy.description = importenergy for phase A +channel-type.iammeter.importenergy.label = ImportEnergy +channel-type.iammeter.importenergy.description = importenergy for phase A +channel-type.iammeter.pf.label = Power Factor +channel-type.iammeter.pf.description = power factor for phase A +channel-type.iammeter.power.label = Power +channel-type.iammeter.power.description = power for phase A +channel-type.iammeter.power.label = Power +channel-type.iammeter.power.description = power for phase A +channel-type.iammeter.voltage.label = Voltage +channel-type.iammeter.voltage.description = voltage for phase A +channel-type.iammeter.voltage.label = Voltage +channel-type.iammeter.voltage.description = voltage for phase A diff --git a/bundles/org.openhab.binding.iaqualink/src/main/resources/OH-INF/i18n/iaqualink.properties b/bundles/org.openhab.binding.iaqualink/src/main/resources/OH-INF/i18n/iaqualink.properties new file mode 100644 index 0000000000000..dde18c81210ca --- /dev/null +++ b/bundles/org.openhab.binding.iaqualink/src/main/resources/OH-INF/i18n/iaqualink.properties @@ -0,0 +1,165 @@ +# binding + +binding.iaqualink.name = iAquaLink Binding +binding.iaqualink.description = This is the binding for a iAquaLink pool controller. + +# thing types + +thing-type.iaqualink.controller.label = iAquaLink Pool Controller +thing-type.iaqualink.controller.description = A iAquaLink pool control thing represents a iAquaLink pool controller for Jandy/Zodiac systems +thing-type.iaqualink.controller.channel.air_temp.label = Air Temperature +thing-type.iaqualink.controller.channel.air_temp.description = The current outside temperature +thing-type.iaqualink.controller.channel.cover_pool.label = Cover Pool +thing-type.iaqualink.controller.channel.cover_pool.description = Pool covering +thing-type.iaqualink.controller.channel.freeze_protection.label = Freeze Protection +thing-type.iaqualink.controller.channel.freeze_protection.description = Freeze protection +thing-type.iaqualink.controller.channel.orp.label = Orp +thing-type.iaqualink.controller.channel.orp.description = Orp +thing-type.iaqualink.controller.channel.ph.label = PH +thing-type.iaqualink.controller.channel.ph.description = PH +thing-type.iaqualink.controller.channel.pool_heater.label = Pool Heater Switch +thing-type.iaqualink.controller.channel.pool_heater.description = Pool heater Switch +thing-type.iaqualink.controller.channel.pool_heater_status.label = Pool Heater Status +thing-type.iaqualink.controller.channel.pool_heater_status.description = Pool heater status +thing-type.iaqualink.controller.channel.pool_pump.label = Pool Pump +thing-type.iaqualink.controller.channel.pool_pump.description = Pool pump +thing-type.iaqualink.controller.channel.pool_salinity.label = Pool Salinity +thing-type.iaqualink.controller.channel.pool_salinity.description = Pool Salinity +thing-type.iaqualink.controller.channel.pool_set_point.label = Pool Setpoint +thing-type.iaqualink.controller.channel.pool_set_point.description = The pool setpoint +thing-type.iaqualink.controller.channel.pool_temp.label = Pool Temperature +thing-type.iaqualink.controller.channel.pool_temp.description = The current temperature of the pool +thing-type.iaqualink.controller.channel.solar_heater.label = Solar Heater Switch +thing-type.iaqualink.controller.channel.solar_heater.description = Solar heater switch +thing-type.iaqualink.controller.channel.solar_heater_status.label = Solar Heater Status +thing-type.iaqualink.controller.channel.solar_heater_status.description = Solar heater status +thing-type.iaqualink.controller.channel.spa_heater.label = Spa Heater Switch +thing-type.iaqualink.controller.channel.spa_heater.description = Spa heater switch +thing-type.iaqualink.controller.channel.spa_heater_status.label = Spa Heater Status +thing-type.iaqualink.controller.channel.spa_heater_status.description = Spa heater status +thing-type.iaqualink.controller.channel.spa_pump.label = Spa Pump +thing-type.iaqualink.controller.channel.spa_pump.description = Spa pump +thing-type.iaqualink.controller.channel.spa_salinity.label = Spa Salinity +thing-type.iaqualink.controller.channel.spa_salinity.description = Spa Salinity +thing-type.iaqualink.controller.channel.spa_set_point.label = Spa Setpoint +thing-type.iaqualink.controller.channel.spa_set_point.description = The spa setpoint +thing-type.iaqualink.controller.channel.spa_temp.label = Spa Temperature +thing-type.iaqualink.controller.channel.spa_temp.description = The current temperature of the spa + +# thing types config + +thing-type.config.iaqualink.controller.apiKey.label = API Key +thing-type.config.iaqualink.controller.apiKey.description = Optionally specify the API key used for access. This is only useful for debugging or if the API key is changed by the vendor +thing-type.config.iaqualink.controller.password.label = Password +thing-type.config.iaqualink.controller.password.description = The password to use when connecting to a iAqualink Account +thing-type.config.iaqualink.controller.refresh.label = Refresh Interval +thing-type.config.iaqualink.controller.refresh.description = Specifies the refresh interval in seconds +thing-type.config.iaqualink.controller.serialId.label = Serial Number +thing-type.config.iaqualink.controller.serialId.description = Optionally specify the serial number of the controller which can be found on the iAquaLink Owner's Center. This is only useful if you have more then one controller (pool) associated with your account. Leave blank to have the first controller used. +thing-type.config.iaqualink.controller.userName.label = User Name +thing-type.config.iaqualink.controller.userName.description = The user name to use when connecting to a iAqualink Account + +# channel types + +channel-type.iaqualink.aux-dimmer.label = Auxiliary Dimmer +channel-type.iaqualink.aux-dimmer.description = The current state of auxiliary channel +channel-type.iaqualink.aux-hayward.label = Hayward Universal Lighting +channel-type.iaqualink.aux-hayward.description = Hayward Universal Lighting Channel +channel-type.iaqualink.aux-hayward.state.option.off = Off +channel-type.iaqualink.aux-hayward.state.option.on = On +channel-type.iaqualink.aux-hayward.state.option.1 = Voodoo Lounge +channel-type.iaqualink.aux-hayward.state.option.2 = Deep Blue Sea +channel-type.iaqualink.aux-hayward.state.option.3 = Afternoon Skies +channel-type.iaqualink.aux-hayward.state.option.4 = Emerald +channel-type.iaqualink.aux-hayward.state.option.5 = Sangria +channel-type.iaqualink.aux-hayward.state.option.6 = Cloud White +channel-type.iaqualink.aux-hayward.state.option.7 = Twilight +channel-type.iaqualink.aux-hayward.state.option.8 = Tranquility +channel-type.iaqualink.aux-hayward.state.option.9 = Gemstone +channel-type.iaqualink.aux-hayward.state.option.10 = USA! +channel-type.iaqualink.aux-hayward.state.option.11 = Mardi Gras +channel-type.iaqualink.aux-hayward.state.option.12 = Cool Caberet +channel-type.iaqualink.aux-jandycolor.label = Jandy Color Lighting +channel-type.iaqualink.aux-jandycolor.description = Jandy Color Lighting Channel +channel-type.iaqualink.aux-jandycolor.state.option.off = Off +channel-type.iaqualink.aux-jandycolor.state.option.on = On +channel-type.iaqualink.aux-jandycolor.state.option.1 = Alpine White +channel-type.iaqualink.aux-jandycolor.state.option.2 = Sky Blue +channel-type.iaqualink.aux-jandycolor.state.option.3 = Cobalt Blue +channel-type.iaqualink.aux-jandycolor.state.option.4 = Caribbean Blue +channel-type.iaqualink.aux-jandycolor.state.option.5 = Spring Green +channel-type.iaqualink.aux-jandycolor.state.option.6 = Emerald Green +channel-type.iaqualink.aux-jandycolor.state.option.7 = Emerald Rose +channel-type.iaqualink.aux-jandycolor.state.option.8 = Magenta +channel-type.iaqualink.aux-jandycolor.state.option.9 = Garnet Red +channel-type.iaqualink.aux-jandycolor.state.option.10 = Violet +channel-type.iaqualink.aux-jandycolor.state.option.11 = Color Splash +channel-type.iaqualink.aux-jandyled.label = Jandy Led Water Colors Lighting +channel-type.iaqualink.aux-jandyled.description = Jandy Led Water Colors Lighting Channel +channel-type.iaqualink.aux-jandyled.state.option.off = Off +channel-type.iaqualink.aux-jandyled.state.option.on = On +channel-type.iaqualink.aux-jandyled.state.option.1 = Alpine White +channel-type.iaqualink.aux-jandyled.state.option.2 = Sky Blue +channel-type.iaqualink.aux-jandyled.state.option.3 = Cobalt Blue +channel-type.iaqualink.aux-jandyled.state.option.4 = Caribbean Blue +channel-type.iaqualink.aux-jandyled.state.option.5 = Spring Green +channel-type.iaqualink.aux-jandyled.state.option.6 = Emerald Green +channel-type.iaqualink.aux-jandyled.state.option.7 = Emerald Rose +channel-type.iaqualink.aux-jandyled.state.option.8 = Magenta +channel-type.iaqualink.aux-jandyled.state.option.9 = Violet +channel-type.iaqualink.aux-jandyled.state.option.10 = Slow Splash +channel-type.iaqualink.aux-jandyled.state.option.11 = Fast Splash +channel-type.iaqualink.aux-jandyled.state.option.12 = USA!!! +channel-type.iaqualink.aux-jandyled.state.option.13 = Fat Tuesday +channel-type.iaqualink.aux-jandyled.state.option.14 = Disco Tech +channel-type.iaqualink.aux-pentairib.label = Pentair intelliBrite Lighting +channel-type.iaqualink.aux-pentairib.description = Pentair intelliBrite Lighting Channel +channel-type.iaqualink.aux-pentairib.state.option.off = Off +channel-type.iaqualink.aux-pentairib.state.option.on = On +channel-type.iaqualink.aux-pentairib.state.option.1 = SAM +channel-type.iaqualink.aux-pentairib.state.option.2 = Party +channel-type.iaqualink.aux-pentairib.state.option.3 = Romance +channel-type.iaqualink.aux-pentairib.state.option.4 = Caribbean +channel-type.iaqualink.aux-pentairib.state.option.5 = American +channel-type.iaqualink.aux-pentairib.state.option.6 = Cal Sunset +channel-type.iaqualink.aux-pentairib.state.option.7 = Royal +channel-type.iaqualink.aux-pentairib.state.option.8 = Blue +channel-type.iaqualink.aux-pentairib.state.option.9 = Green +channel-type.iaqualink.aux-pentairib.state.option.10 = Red +channel-type.iaqualink.aux-pentairib.state.option.11 = White +channel-type.iaqualink.aux-pentairib.state.option.12 = Magenta +channel-type.iaqualink.aux-pentairib.state.option.13 = Hold +channel-type.iaqualink.aux-pentairib.state.option.14 = Recall +channel-type.iaqualink.aux-pentairsam.label = Pentair SAm/SAL Lighting +channel-type.iaqualink.aux-pentairsam.description = Pentair SAm/SAL Lighting Channel +channel-type.iaqualink.aux-pentairsam.state.option.off = Off +channel-type.iaqualink.aux-pentairsam.state.option.on = On +channel-type.iaqualink.aux-pentairsam.state.option.1 = White +channel-type.iaqualink.aux-pentairsam.state.option.2 = Light Green +channel-type.iaqualink.aux-pentairsam.state.option.3 = Green +channel-type.iaqualink.aux-pentairsam.state.option.4 = Cyan +channel-type.iaqualink.aux-pentairsam.state.option.5 = Blue +channel-type.iaqualink.aux-pentairsam.state.option.6 = Lavender +channel-type.iaqualink.aux-pentairsam.state.option.7 = Magenta +channel-type.iaqualink.aux-pentairsam.state.option.8 = Light Magenta +channel-type.iaqualink.aux-pentairsam.state.option.9 = Color Splash +channel-type.iaqualink.aux-switch.label = Auxiliary Switch +channel-type.iaqualink.aux-switch.description = The current state of auxiliary channel +channel-type.iaqualink.chemical.label = Chemical +channel-type.iaqualink.equipment-heater.label = Heater +channel-type.iaqualink.equipment-heater.description = The current state of the heater +channel-type.iaqualink.equipment-heater.state.option.off = Off +channel-type.iaqualink.equipment-heater.state.option.heating = Heating +channel-type.iaqualink.equipment-heater.state.option.enabled = Enabled +channel-type.iaqualink.equipment-switch.label = Equipment Switch +channel-type.iaqualink.equipment-switch.description = The current state of a equipment switch +channel-type.iaqualink.onetouch.label = OneTouch +channel-type.iaqualink.onetouch.description = OneTouch commands +channel-type.iaqualink.setpoint.label = Setpoint +channel-type.iaqualink.status.label = Status +channel-type.iaqualink.status.description = The status of the iAqualink connection +channel-type.iaqualink.system_type.label = System Type +channel-type.iaqualink.system_type.description = System Type +channel-type.iaqualink.temperature.label = Temperature +channel-type.iaqualink.temperature_scale.label = Temperature Units +channel-type.iaqualink.temperature_scale.description = The selected units for temperature (C or F) diff --git a/bundles/org.openhab.binding.ihc/src/main/resources/OH-INF/i18n/ihc.properties b/bundles/org.openhab.binding.ihc/src/main/resources/OH-INF/i18n/ihc.properties new file mode 100644 index 0000000000000..2aaf86f5dd794 --- /dev/null +++ b/bundles/org.openhab.binding.ihc/src/main/resources/OH-INF/i18n/ihc.properties @@ -0,0 +1,138 @@ +# binding + +binding.ihc.name = IHC / ELKO Binding +binding.ihc.description = Binding to communicate IHC / ELKO controller + +# thing types + +thing-type.ihc.controller.label = IHC / ELKO Controller + +# thing types config + +thing-type.config.ihc.controller.createChannelsAutomatically.label = Create Channels Automatically +thing-type.config.ihc.controller.createChannelsAutomatically.description = Create channels automatically from project file. Project file loading parameter should be enabled as well. +thing-type.config.ihc.controller.hostname.label = Network Address +thing-type.config.ihc.controller.hostname.description = Network/IP address of the IHC / ELKO controller without https prefix, but can contain TCP port if default port is not used +thing-type.config.ihc.controller.loadProjectFile.label = Load Project File +thing-type.config.ihc.controller.loadProjectFile.description = Load project file from controller. +thing-type.config.ihc.controller.password.label = Password +thing-type.config.ihc.controller.password.description = Password to login to the IHC / ELKO controller. +thing-type.config.ihc.controller.timeout.label = Timeout +thing-type.config.ihc.controller.timeout.description = Timeout to communicate to IHC / ELKO controller. +thing-type.config.ihc.controller.tlsVersion.label = TLS version +thing-type.config.ihc.controller.tlsVersion.description = TLS version used for controller communication. Choose TLSv1 for older firmware versions and TLSv1.2 for never versions (since fall 2021). Auto mode try to recognize correct version. +thing-type.config.ihc.controller.tlsVersion.option.TLSv1 = TLSv1 +thing-type.config.ihc.controller.tlsVersion.option.TLSv1.2 = TLSv1.2 +thing-type.config.ihc.controller.tlsVersion.option.AUTO = Auto +thing-type.config.ihc.controller.username.label = User Name +thing-type.config.ihc.controller.username.description = User name to login to the IHC / ELKO controller. + +# channel types + +channel-type.ihc.contact.label = Generic Contact +channel-type.ihc.contact.description = Generic contact channel +channel-type.ihc.controller-state.label = Controller State +channel-type.ihc.controller-state.description = Displays IHC / ELKO controller state +channel-type.ihc.controller-time.label = Controller Date and Time +channel-type.ihc.controller-time.description = Displays IHC / ELKO controller date and time +channel-type.ihc.controller-uptime.label = Controller Uptime +channel-type.ihc.controller-uptime.description = Displays IHC / ELKO controller uptime in seconds +channel-type.ihc.datetime.label = Generic Datetime +channel-type.ihc.datetime.description = Generic datetime channel +channel-type.ihc.dimmer.label = Generic Dimmer +channel-type.ihc.dimmer.description = Generic dimmer channel +channel-type.ihc.number.label = Generic Number +channel-type.ihc.number.description = Generic number channel +channel-type.ihc.push-button-trigger.label = Push Button Trigger Channel +channel-type.ihc.rf-device-low-battery.label = RF Device Low Battery Warning +channel-type.ihc.rf-device-low-battery.description = RF device low battery warning. +channel-type.ihc.rf-device-signal-strength.label = RF Device Signal Strength +channel-type.ihc.rf-device-signal-strength.description = RF device signal strength. +channel-type.ihc.rf-device-signal-strength.state.option.0 = No signal +channel-type.ihc.rf-device-signal-strength.state.option.1 = Weak +channel-type.ihc.rf-device-signal-strength.state.option.2 = Average +channel-type.ihc.rf-device-signal-strength.state.option.3 = Good +channel-type.ihc.rf-device-signal-strength.state.option.4 = Excellent +channel-type.ihc.rollershutter.label = Generic Roller Shutter +channel-type.ihc.rollershutter.description = Generic roller shutter channel +channel-type.ihc.string.label = Generic String +channel-type.ihc.string.description = Generic string channel +channel-type.ihc.switch.label = Generic Switch +channel-type.ihc.switch.description = Generic switch channel + +# channel types config + +channel-type.config.ihc.contact.inverted.label = Inverted Signal +channel-type.config.ihc.contact.inverted.description = openHAB state is inverted compared to IHC output/input signal +channel-type.config.ihc.contact.resourceId.label = Resource Id +channel-type.config.ihc.datetime.commandToReact.label = Command to React +channel-type.config.ihc.datetime.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.datetime.direction.label = Channel Direction +channel-type.config.ihc.datetime.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.datetime.direction.option.ReadWrite = Read Write +channel-type.config.ihc.datetime.direction.option.WriteOnly = Write only +channel-type.config.ihc.datetime.direction.option.ReadOnly = Read only +channel-type.config.ihc.datetime.pulseWidth.label = Pulse Width +channel-type.config.ihc.datetime.pulseWidth.description = If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.datetime.resourceId.label = Resource Id +channel-type.config.ihc.dimmer.commandToReact.label = Command to React +channel-type.config.ihc.dimmer.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.dimmer.direction.label = Channel Direction +channel-type.config.ihc.dimmer.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.dimmer.direction.option.ReadWrite = Read Write +channel-type.config.ihc.dimmer.direction.option.WriteOnly = Write only +channel-type.config.ihc.dimmer.direction.option.ReadOnly = Read only +channel-type.config.ihc.dimmer.onLevel.label = ON Command Level +channel-type.config.ihc.dimmer.onLevel.description = If defined, binding use this level when ON command is received rather than resource maximum value. Level is anyhow limited to resource maximum value. +channel-type.config.ihc.dimmer.pulseWidth.label = Pulse Width +channel-type.config.ihc.dimmer.pulseWidth.description = If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.dimmer.resourceId.label = Resource Id +channel-type.config.ihc.number.commandToReact.label = Command to React +channel-type.config.ihc.number.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.number.direction.label = Channel Direction +channel-type.config.ihc.number.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.number.direction.option.ReadWrite = Read Write +channel-type.config.ihc.number.direction.option.WriteOnly = Write only +channel-type.config.ihc.number.direction.option.ReadOnly = Read only +channel-type.config.ihc.number.pulseWidth.label = Pulse Width +channel-type.config.ihc.number.pulseWidth.description = If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.number.resourceId.label = Resource Id +channel-type.config.ihc.push-button-trigger.longPressTime.label = Long Press Time +channel-type.config.ihc.push-button-trigger.longPressTime.description = Long press time in milliseconds. +channel-type.config.ihc.push-button-trigger.resourceId.label = Resource Id +channel-type.config.ihc.rf-device-low-battery.serialNumber.label = RF Device Serial Number +channel-type.config.ihc.rf-device-low-battery.serialNumber.description = Serial Number of RF device in decimal format. +channel-type.config.ihc.rf-device-signal-strength.serialNumber.label = RF Device Serial Number +channel-type.config.ihc.rf-device-signal-strength.serialNumber.description = Serial number of RF device in decimal format. +channel-type.config.ihc.rollershutter.commandToReact.label = Command to React +channel-type.config.ihc.rollershutter.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.rollershutter.direction.label = Channel Direction +channel-type.config.ihc.rollershutter.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.rollershutter.direction.option.ReadWrite = Read Write +channel-type.config.ihc.rollershutter.direction.option.WriteOnly = Write only +channel-type.config.ihc.rollershutter.direction.option.ReadOnly = Read only +channel-type.config.ihc.rollershutter.pulseWidth.label = Pulse Width +channel-type.config.ihc.rollershutter.pulseWidth.description = If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.rollershutter.resourceId.label = Resource Id +channel-type.config.ihc.string.commandToReact.label = Command to React +channel-type.config.ihc.string.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.string.direction.label = Channel Direction +channel-type.config.ihc.string.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.string.direction.option.ReadWrite = Read Write +channel-type.config.ihc.string.direction.option.WriteOnly = Write only +channel-type.config.ihc.string.direction.option.ReadOnly = Read only +channel-type.config.ihc.string.pulseWidth.label = Pulse Width +channel-type.config.ihc.string.pulseWidth.description = If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.string.resourceId.label = Resource Id +channel-type.config.ihc.switch.commandToReact.label = Command to React +channel-type.config.ihc.switch.commandToReact.description = Command to react. If not defined, channel react to all commands. +channel-type.config.ihc.switch.direction.label = Channel Direction +channel-type.config.ihc.switch.direction.description = Direction of the channel. By default, channel is synchronized in both directions. +channel-type.config.ihc.switch.direction.option.ReadWrite = Read Write +channel-type.config.ihc.switch.direction.option.WriteOnly = Write only +channel-type.config.ihc.switch.direction.option.ReadOnly = Read only +channel-type.config.ihc.switch.inverted.label = Inverted Signal +channel-type.config.ihc.switch.inverted.description = openHAB state is inverted compared to IHC output/input signal +channel-type.config.ihc.switch.pulseWidth.label = Pulse Width +channel-type.config.ihc.switch.pulseWidth.description = Pulse width in milliseconds. If defined, binding send pulse rather than command value to IHC controller. +channel-type.config.ihc.switch.resourceId.label = Resource Id diff --git a/bundles/org.openhab.binding.innogysmarthome/src/main/resources/OH-INF/i18n/innogysmarthome.properties b/bundles/org.openhab.binding.innogysmarthome/src/main/resources/OH-INF/i18n/innogysmarthome.properties new file mode 100644 index 0000000000000..1f5a197da8ab7 --- /dev/null +++ b/bundles/org.openhab.binding.innogysmarthome/src/main/resources/OH-INF/i18n/innogysmarthome.properties @@ -0,0 +1,157 @@ +# binding + +binding.innogysmarthome.name = innogy SmartHome Binding +binding.innogysmarthome.description = The innogy SmartHome binding integrates your innogy SmartHome system. + +# thing types + +thing-type.innogysmarthome.AnalogMeter.label = Analog Meter +thing-type.innogysmarthome.AnalogMeter.description = The Analog Meter from the innogy EnergyControl product. +thing-type.innogysmarthome.BRC8.label = Basic Remote Controller (BRC8) +thing-type.innogysmarthome.BRC8.description = A battery powered remote controller with eight push buttons. +thing-type.innogysmarthome.BT-PSS.label = Bluetooth Pluggable Smart Switch (BT-PSS) +thing-type.innogysmarthome.BT-PSS.description = A pluggable switch that can be switched on and off and which can measure the current energy consumption. +thing-type.innogysmarthome.GenerationMeter.label = Generation Meter +thing-type.innogysmarthome.GenerationMeter.description = The Generation Meter from the innogy PowerControlSolar product, that measures the generated energy. +thing-type.innogysmarthome.ISC2.label = In Wall Smart Controller (ISC2) +thing-type.innogysmarthome.ISC2.description = A smart controller with two push buttons. +thing-type.innogysmarthome.ISD2.label = In Wall Smart Dimmer (ISD2) +thing-type.innogysmarthome.ISD2.description = An in wall dimmer with push buttons. +thing-type.innogysmarthome.ISR2.label = In Wall Smart Roller Shutter (ISR2) +thing-type.innogysmarthome.ISR2.description = An in wall rollershutter with two push buttons. +thing-type.innogysmarthome.ISS2.label = In Wall Smart Switch (ISS2) +thing-type.innogysmarthome.ISS2.description = An in wall switch with push buttons that can be switched on and off. +thing-type.innogysmarthome.PSD.label = Pluggable Smart Dimmer (PSD) +thing-type.innogysmarthome.PSD.description = A pluggable dimmer. +thing-type.innogysmarthome.PSS.label = Pluggable Smart Switch (PSS) +thing-type.innogysmarthome.PSS.description = A pluggable switch that can be switched on and off. +thing-type.innogysmarthome.PSSO.label = Pluggable Smart Switch Outdoor (PSSO) +thing-type.innogysmarthome.PSSO.description = A pluggable outdoor switch that can be switched on and off. +thing-type.innogysmarthome.RST.label = Radiator Mounted Smart Thermostat (RST) +thing-type.innogysmarthome.RST.description = A thermostat, that supports setting the temperature and measuring the current temperature and humidity. +thing-type.innogysmarthome.RST2.label = Radiator Mounted Smart Thermostat (RST2) +thing-type.innogysmarthome.RST2.description = A thermostat, that supports setting the temperature and measuring the current temperature and humidity (2 battery version since 2018) +thing-type.innogysmarthome.SmartMeter.label = Smart Meter +thing-type.innogysmarthome.SmartMeter.description = The Smart Meter from the innogy PowerControl product. +thing-type.innogysmarthome.TwoWayMeter.label = Two-Way-Meter +thing-type.innogysmarthome.TwoWayMeter.description = The Two-Way-Meter from the innogy PowerControlSolar product. +thing-type.innogysmarthome.VariableActuator.label = Variable Actuator +thing-type.innogysmarthome.VariableActuator.description = A variable from the innogy SmartHome System that can be switched on and off. +thing-type.innogysmarthome.WDS.label = Wall Mounted Door/Window Sensor (WDS) +thing-type.innogysmarthome.WDS.description = A window/door sensor, that provides the open/close state. +thing-type.innogysmarthome.WMD.label = Wall Mounted Motion Detector Indoor (WMD) +thing-type.innogysmarthome.WMD.description = A battery powered motion detector, that also measures luminance. +thing-type.innogysmarthome.WMDO.label = Wall Mounted Motion Detector Outdoor (WMDO) +thing-type.innogysmarthome.WMDO.description = A battery powered motion detector for outdoors, that also measures luminance. +thing-type.innogysmarthome.WRT.label = Wall Mounted Room Thermostat (WRT) +thing-type.innogysmarthome.WRT.description = A wall thermostat, that supports setting the temperature and measuring the current temperature and humidity. +thing-type.innogysmarthome.WSC2.label = Wall Mounted Smart Controller (WSC2) +thing-type.innogysmarthome.WSC2.description = A battery powered smart controller with two push buttons. +thing-type.innogysmarthome.WSD.label = Wall Mounted Smoke Detector (WSD) +thing-type.innogysmarthome.WSD.description = A battery powered smoke detector sensor with integrated alarm (first version). +thing-type.innogysmarthome.WSD2.label = Wall Mounted Smoke Detector (WSD2) +thing-type.innogysmarthome.WSD2.description = A battery powered smoke detector sensor with integrated alarm (2nd version with long-life battery). +thing-type.innogysmarthome.bridge.label = innogy SmartHome Controller +thing-type.innogysmarthome.bridge.description = The innogy SmartHome Controller (SHC) is the bridge for the innogy SmartHome System. + +# thing types config + +thing-type.config.innogysmarthome.bridge.authcode.label = Authorization Code +thing-type.config.innogysmarthome.bridge.authcode.description = The auth-code is a one-time code needed to retrieve the necessary access-codes from innogy SmartHome Service. Please go - depending on your brand - to...
  • innogy SmartHome Portal: https://auth.services-smarthome.de/AUTH/authorize?response_type=code&client_id=24635748&redirect_uri=https%3A%2F%2Fwww.openhab.org%2Foauth%2Finnogy%2Finnogy-smarthome.html&scope&lang=de-DE
... to generate an auth-code and paste it here. After initial authorization, this code is not needed anymore. +thing-type.config.innogysmarthome.bridge.brand.label = Brand +thing-type.config.innogysmarthome.bridge.brand.description = Choose the brand of your innogy SmartHome based solution. +thing-type.config.innogysmarthome.bridge.brand.option.innogy_smarthome = innogy SmartHome +thing-type.config.innogysmarthome.bridge.group.advanced.label = Advanced Configuration +thing-type.config.innogysmarthome.bridge.group.advanced.description = Advanced parameters, for special tweaking only. +thing-type.config.innogysmarthome.bridge.group.connection.label = Connection +thing-type.config.innogysmarthome.bridge.group.connection.description = Parameters for connecting to innogy SmartHome Controller (SHC) +thing-type.config.innogysmarthome.bridge.websocketidletimeout.label = WebSocket Idle Timeout in Seconds +thing-type.config.innogysmarthome.bridge.websocketidletimeout.description = The WebSocket is the connection to the innogy service that listens to status updates. If no data is received over the websocket connection for the given time, the websocket will reconnect. 0 will disable the idle timeout. Default is 900 seconds (15 minutes). +thing-type.config.innogysmarthome.config.id.label = ID +thing-type.config.innogysmarthome.config.id.description = The identifier uniquely identifies this device. + +# channel types + +channel-type.innogysmarthome.AbsoluteEnergyConsumption.label = Total Consumption +channel-type.innogysmarthome.AbsoluteEnergyConsumption.description = The absolute Energy consumption +channel-type.innogysmarthome.AlarmActuator.label = Alarm +channel-type.innogysmarthome.AlarmActuator.description = Switches the alarm on/off +channel-type.innogysmarthome.BooleanStateActuator.label = Switch +channel-type.innogysmarthome.BooleanStateActuator.description = Switches the state on/off +channel-type.innogysmarthome.CPUUsage.label = CPU Usage +channel-type.innogysmarthome.CPUUsage.description = The CPU usage of SHC-A, updated every 5 minutes +channel-type.innogysmarthome.DimmerActuator.label = Dimmer +channel-type.innogysmarthome.DimmerActuator.description = Dimms the connected light +channel-type.innogysmarthome.DiskUsage.label = Disk Usage +channel-type.innogysmarthome.DiskUsage.description = The disk usage of SHC-A, updated every 5 minutes +channel-type.innogysmarthome.EnergyConsumptionDayEuro.label = Consumption Costs (day) +channel-type.innogysmarthome.EnergyConsumptionDayEuro.description = The energy consumption per day in Euro +channel-type.innogysmarthome.EnergyConsumptionDayKWh.label = Consumption (day) +channel-type.innogysmarthome.EnergyConsumptionDayKWh.description = The energy consumption per day in kWh +channel-type.innogysmarthome.EnergyConsumptionMonthEuro.label = Consumption Costs (month) +channel-type.innogysmarthome.EnergyConsumptionMonthEuro.description = The energy consumption per month in Euro +channel-type.innogysmarthome.EnergyConsumptionMonthKWh.label = Consumption (month) +channel-type.innogysmarthome.EnergyConsumptionMonthKWh.description = The energy consumption per month in kWh +channel-type.innogysmarthome.EnergyFeedDayEuro.label = Feed Income (day) +channel-type.innogysmarthome.EnergyFeedDayEuro.description = The energy feed per day in Euro +channel-type.innogysmarthome.EnergyFeedDayKWh.label = Feed (day) +channel-type.innogysmarthome.EnergyFeedDayKWh.description = The energy feed per day in kWh +channel-type.innogysmarthome.EnergyFeedMonthEuro.label = Feed Income (month) +channel-type.innogysmarthome.EnergyFeedMonthEuro.description = The energy feed per month in Euro +channel-type.innogysmarthome.EnergyFeedMonthKWh.label = Feed (month) +channel-type.innogysmarthome.EnergyFeedMonthKWh.description = The energy feed per month in kWh +channel-type.innogysmarthome.EnergyGenerationDayEuro.label = Generation Value (day) +channel-type.innogysmarthome.EnergyGenerationDayEuro.description = The energy generation per day in Euro +channel-type.innogysmarthome.EnergyGenerationDayKWh.label = Generation (day) +channel-type.innogysmarthome.EnergyGenerationDayKWh.description = The energy generation per day in kWh +channel-type.innogysmarthome.EnergyGenerationMonthEuro.label = Generation Value (month) +channel-type.innogysmarthome.EnergyGenerationMonthEuro.description = The energy generation per month in Euro +channel-type.innogysmarthome.EnergyGenerationMonthKWh.label = Generation (month) +channel-type.innogysmarthome.EnergyGenerationMonthKWh.description = The energy generation per month in kWh +channel-type.innogysmarthome.HumiditySensor_Humidity.label = Actual Humidity +channel-type.innogysmarthome.HumiditySensor_Humidity.description = Actual measured room humidity +channel-type.innogysmarthome.HumiditySensor_MoldWarning.label = Mold Warning +channel-type.innogysmarthome.HumiditySensor_MoldWarning.description = Active, if humidity is over a threshold (configured in innogy app) +channel-type.innogysmarthome.LuminanceSensor.label = Luminance +channel-type.innogysmarthome.LuminanceSensor.description = Shows the detected luminance in percent +channel-type.innogysmarthome.MemoryUsage.label = Memory Usage +channel-type.innogysmarthome.MemoryUsage.description = The memory usage of SHC-A, updated every 5 minutes +channel-type.innogysmarthome.MotionDetectionSensor.label = Motion Count +channel-type.innogysmarthome.MotionDetectionSensor.description = The count of detected motions +channel-type.innogysmarthome.PowerConsumptionWatt.label = Current Power Consumption +channel-type.innogysmarthome.PowerConsumptionWatt.description = The current power consumption in Watt +channel-type.innogysmarthome.PowerGenerationWatt.label = Current Power Generation +channel-type.innogysmarthome.PowerGenerationWatt.description = The current power generation in Watt +channel-type.innogysmarthome.PushButtonCounter.label = Button Pushed Count +channel-type.innogysmarthome.PushButtonCounter.description = The count of button pushes. +channel-type.innogysmarthome.RollerShutterActuator.label = Blinds Position +channel-type.innogysmarthome.RollerShutterActuator.description = Controls the blinds +channel-type.innogysmarthome.SmokeDetectorSensor.label = Smoke +channel-type.innogysmarthome.SmokeDetectorSensor.description = Shows if smoke was detected +channel-type.innogysmarthome.SwitchActuator.label = Switch +channel-type.innogysmarthome.SwitchActuator.description = Switches the current on/off +channel-type.innogysmarthome.TemperatureSensor_FrostWarning.label = Frost Warning +channel-type.innogysmarthome.TemperatureSensor_FrostWarning.description = Warns, if temperature drop below a threshold (configured in innogy app) +channel-type.innogysmarthome.TemperatureSensor_Temperature.label = Actual Temperature +channel-type.innogysmarthome.TemperatureSensor_Temperature.description = Actual measured room temperature +channel-type.innogysmarthome.ThermostatActuator_OperationMode.label = Operation Mode +channel-type.innogysmarthome.ThermostatActuator_OperationMode.description = Thermostat operation mode (manual/auto) +channel-type.innogysmarthome.ThermostatActuator_OperationMode.state.option.Auto = auto +channel-type.innogysmarthome.ThermostatActuator_OperationMode.state.option.Manu = manual +channel-type.innogysmarthome.ThermostatActuator_PointTemperature.label = Target Temperature +channel-type.innogysmarthome.ThermostatActuator_PointTemperature.description = Thermostat target temperature +channel-type.innogysmarthome.ThermostatActuator_WindowReductionActive.label = Window Reduction Active +channel-type.innogysmarthome.ThermostatActuator_WindowReductionActive.description = Thermostat temperature reduced, if window is open. +channel-type.innogysmarthome.TotalEnergyConsumption.label = Total Consumption +channel-type.innogysmarthome.TotalEnergyConsumption.description = The total Energy consumption +channel-type.innogysmarthome.TotalEnergyFed.label = Total Fed +channel-type.innogysmarthome.TotalEnergyFed.description = The total Energy fed +channel-type.innogysmarthome.TotalEnergyGeneration.label = Total Generation +channel-type.innogysmarthome.TotalEnergyGeneration.description = The total Energy generation +channel-type.innogysmarthome.WindowDoorSensor.label = Contact +channel-type.innogysmarthome.WindowDoorSensor.description = Shows the open/close state + +# channel types config + +channel-type.config.innogysmarthome.RollerShutterActuator.invert.label = Invert Position +channel-type.config.innogysmarthome.RollerShutterActuator.invert.description = When invert is true than 0 on innogy is UP and 100 is DOWN diff --git a/bundles/org.openhab.binding.insteon/src/main/resources/OH-INF/i18n/insteon.properties b/bundles/org.openhab.binding.insteon/src/main/resources/OH-INF/i18n/insteon.properties new file mode 100644 index 0000000000000..bfb72cc112b9d --- /dev/null +++ b/bundles/org.openhab.binding.insteon/src/main/resources/OH-INF/i18n/insteon.properties @@ -0,0 +1,177 @@ +# binding + +binding.insteon.name = Insteon Binding +binding.insteon.description = This is the binding for Insteon. + +# thing types + +thing-type.insteon.device.label = Insteon Device +thing-type.insteon.device.description = Insteon devices such as switches, dimmers, keypads, sensors, etc. +thing-type.insteon.network.label = Insteon Network +thing-type.insteon.network.description = An Insteon PLM or hub that is used to communicate with the Insteon devices. + +# thing types config + +thing-type.config.insteon.device.address.label = Address +thing-type.config.insteon.device.address.description = Insteon address of the device. Example: 12.34.56 +thing-type.config.insteon.device.deviceConfig.label = Device Configuration +thing-type.config.insteon.device.deviceConfig.description = Optional JSON object with device specific configuration. +thing-type.config.insteon.device.productKey.label = Product Key +thing-type.config.insteon.device.productKey.description = Insteon binding product key that is used to identify the model of the device. +thing-type.config.insteon.device.productKey.option.F00.00.01 = 2477D SwitchLinc Dimmer - F00.00.01 +thing-type.config.insteon.device.productKey.option.F00.00.02 = 2477S SwitchLinc Switch - F00.00.02 +thing-type.config.insteon.device.productKey.option.F00.00.03 = 2845-222 Hidden Door Sensor - F00.00.03 +thing-type.config.insteon.device.productKey.option.F00.00.04 = 2876S ICON Switch - F00.00.04 +thing-type.config.insteon.device.productKey.option.F00.00.05 = 2456D3 LampLinc V2 - F00.00.05 +thing-type.config.insteon.device.productKey.option.F00.00.06 = 2442-222 Micro Dimmer - F00.00.06 +thing-type.config.insteon.device.productKey.option.F00.00.07 = 2453-222 DIN Rail On/Off - F00.00.07 +thing-type.config.insteon.device.productKey.option.F00.00.08 = 2452-222 DIN Rail Dimmer - F00.00.08 +thing-type.config.insteon.device.productKey.option.F00.00.09 = 2458-A1 MorningLinc RF Lock Controller - F00.00.09 +thing-type.config.insteon.device.productKey.option.F00.00.0A = 2852-222 Leak Sensor - F00.00.0A +thing-type.config.insteon.device.productKey.option.F00.00.0B = 2672-422 LED Dimmer - F00.00.0B +thing-type.config.insteon.device.productKey.option.F00.00.0C = 2476D SwitchLinc Dimmer - F00.00.0C +thing-type.config.insteon.device.productKey.option.F00.00.0D = 2634-222 On/Off Dual-Band Outdoor Module - F00.00.0D +thing-type.config.insteon.device.productKey.option.F00.00.10 = 2342-2 Mini Remote - F00.00.10 +thing-type.config.insteon.device.productKey.option.F00.00.11 = 2466D ToggleLinc Dimmer - F00.00.11 +thing-type.config.insteon.device.productKey.option.F00.00.12 = 2466S ToggleLinc Switch - F00.00.12 +thing-type.config.insteon.device.productKey.option.F00.00.13 = 2672-222 LED Bulb - F00.00.13 +thing-type.config.insteon.device.productKey.option.F00.00.14 = 2487S KeypadLinc On/Off 6-Button - F00.00.14 +thing-type.config.insteon.device.productKey.option.F00.00.15 = 2334-232 KeypadLink Dimmer 6-Button - F00.00.15 +thing-type.config.insteon.device.productKey.option.F00.00.16 = 2334-232 KeypadLink Dimmer 8-Button - F00.00.16 +thing-type.config.insteon.device.productKey.option.F00.00.17 = 2423A1 iMeter Solo Power Meter - F00.00.17 +thing-type.config.insteon.device.productKey.option.F00.00.18 = 2423A1 Thermostat 2441TH - F00.00.18 +thing-type.config.insteon.device.productKey.option.F00.00.19 = 2457D2 LampLinc Dimmer - F00.00.19 +thing-type.config.insteon.device.productKey.option.F00.00.1A = 2475SDB In-LineLinc Relay - F00.00.1A +thing-type.config.insteon.device.productKey.option.F00.00.1B = 2635-222 On/Off Module - F00.00.1B +thing-type.config.insteon.device.productKey.option.F00.00.1C = 2475F FanLinc Module - F00.00.1C +thing-type.config.insteon.device.productKey.option.F00.00.1D = 2456S3 ApplianceLinc - F00.00.1D +thing-type.config.insteon.device.productKey.option.F00.00.1E = 2674-222 LED Bulb (Recessed) - F00.00.1E +thing-type.config.insteon.device.productKey.option.F00.00.1F = 2477SA1 220V 30-amp Load Controller N/O - F00.00.1F +thing-type.config.insteon.device.productKey.option.F00.00.20 = 2342-222 Mini Remote (8-Button) - F00.00.20 +thing-type.config.insteon.device.productKey.option.F00.00.21 = 2441V Insteon Thermostat Adaptor for Venstar - F00.00.21 +thing-type.config.insteon.device.productKey.option.F00.00.22 = 2982-222 Insteon Smoke Bridge - F00.00.22 +thing-type.config.insteon.device.productKey.option.F00.00.23 = 2487S KeypadLinc On/Off 8-Button - F00.00.23 +thing-type.config.insteon.device.productKey.option.F00.00.24 = Motion Sensor II - F00.00.24 +thing-type.config.insteon.device.productKey.option.0x00001A = 2450 IO Link - 0x00001A +thing-type.config.insteon.device.productKey.option.0x000037 = 2486D KeypadLinc Dimmer - 0x000037 +thing-type.config.insteon.device.productKey.option.0x000039 = 2663-222 On/Off Outlet - 0x000039 +thing-type.config.insteon.device.productKey.option.0x000041 = 2484DWH8 KeypadLinc Countdown Timer - 0x000041 +thing-type.config.insteon.device.productKey.option.0x000045 = PLM or hub - 0x000045 +thing-type.config.insteon.device.productKey.option.0x000049 = 2843-222 Wireless Open/Close Sensor - 0x000049 +thing-type.config.insteon.device.productKey.option.0x00004A = 2842-222 Motion Sensor - 0x00004A +thing-type.config.insteon.device.productKey.option.0x000051 = 2486DWH8 KeypadLinc Dimmer - 0x000051 +thing-type.config.insteon.device.productKey.option.0x000068 = 2472D OutletLinc Dimmer - 0x000068 +thing-type.config.insteon.device.productKey.option.X00.00.01 = X10 switch Generic X10 switch - X00.00.01 +thing-type.config.insteon.device.productKey.option.X00.00.02 = X10 dimmer Generic X10 dimmer - X00.00.02 +thing-type.config.insteon.device.productKey.option.X00.00.03 = X10 motion Generic X10 motion sensor - X00.00.03 +thing-type.config.insteon.network.additionalDevices.label = Additional Devices +thing-type.config.insteon.network.additionalDevices.description = File with additional device types. +thing-type.config.insteon.network.additionalFeatures.label = Additional Features +thing-type.config.insteon.network.additionalFeatures.description = File with additional feature templates. +thing-type.config.insteon.network.devicePollIntervalSeconds.label = Device Poll Interval +thing-type.config.insteon.network.devicePollIntervalSeconds.description = Device poll interval in seconds. +thing-type.config.insteon.network.port.label = Port +thing-type.config.insteon.network.port.description = Configuration information that is used to connect to PLM or hub. + +# channel types + +channel-type.insteon.acDelay.label = AC Delay +channel-type.insteon.backlightDuration.label = Back Light Duration +channel-type.insteon.batteryLevel.label = Battery Level +channel-type.insteon.batteryPercent.label = Battery Percent +channel-type.insteon.batteryWatermarkLevel.label = Battery Watermark Level +channel-type.insteon.beep.label = Beep +channel-type.insteon.bottomOutlet.label = Bottom Outlet +channel-type.insteon.broadcastOnOff.label = Broadcast On/Off +channel-type.insteon.buttonA.label = Button A +channel-type.insteon.buttonB.label = Button B +channel-type.insteon.buttonC.label = Button C +channel-type.insteon.buttonD.label = Button D +channel-type.insteon.buttonE.label = Button E +channel-type.insteon.buttonF.label = Button F +channel-type.insteon.buttonG.label = Button G +channel-type.insteon.buttonH.label = Button H +channel-type.insteon.contact.label = Contact +channel-type.insteon.coolSetPoint.label = Cool Set Point +channel-type.insteon.dimmer.label = Dimmer +channel-type.insteon.fan.label = Fan +channel-type.insteon.fanMode.label = Fan Mode +channel-type.insteon.fastOnOff.label = Fast On/Off +channel-type.insteon.fastOnOffButtonA.label = Fast On/Off Button A +channel-type.insteon.fastOnOffButtonB.label = Fast On/Off Button B +channel-type.insteon.fastOnOffButtonC.label = Fast On/Off Button C +channel-type.insteon.fastOnOffButtonD.label = Fast On/Off Button D +channel-type.insteon.fastOnOffButtonE.label = Fast On/Off Button E +channel-type.insteon.fastOnOffButtonF.label = Fast On/Off Button F +channel-type.insteon.fastOnOffButtonG.label = Fast On/Off Button G +channel-type.insteon.fastOnOffButtonH.label = Fast On/Off Button H +channel-type.insteon.heatSetPoint.label = Heat Set Point +channel-type.insteon.humidity.label = Humidity +channel-type.insteon.humidityHigh.label = Humidity High +channel-type.insteon.humidityLow.label = Humidity Low +channel-type.insteon.isCooling.label = Is Cooling +channel-type.insteon.isHeating.label = Is Heating +channel-type.insteon.kWh.label = Kilowatt Hour +channel-type.insteon.keypadButtonA.label = Keypad Button A +channel-type.insteon.keypadButtonB.label = Keypad Button B +channel-type.insteon.keypadButtonC.label = Keypad Button C +channel-type.insteon.keypadButtonD.label = Keypad Button D +channel-type.insteon.keypadButtonE.label = Keypad Button E +channel-type.insteon.keypadButtonF.label = Keypad Button F +channel-type.insteon.keypadButtonG.label = Keypad Button G +channel-type.insteon.keypadButtonH.label = Keypad Button H +channel-type.insteon.lastHeardFrom.label = Last Heard From +channel-type.insteon.ledBrightness.label = LED Brightness +channel-type.insteon.ledOnOff.label = LED On/Off +channel-type.insteon.lightDimmer.label = Light Dimmer +channel-type.insteon.lightLevel.label = Light Level +channel-type.insteon.lightLevelAboveThreshold.label = Light Level Above/Below Threshold +channel-type.insteon.loadDimmer.label = Load Dimmer +channel-type.insteon.loadSwitch.label = Load Switch +channel-type.insteon.loadSwitchFastOnOff.label = Load Switch Fast On/Off +channel-type.insteon.loadSwitchManualChange.label = Load Switch Manual Change +channel-type.insteon.lowBattery.label = Low Battery +channel-type.insteon.manualChange.label = Manual Change +channel-type.insteon.manualChangeButtonA.label = Manual Change Button A +channel-type.insteon.manualChangeButtonB.label = Manual Change Button B +channel-type.insteon.manualChangeButtonC.label = Manual Change Button C +channel-type.insteon.manualChangeButtonD.label = Manual Change Button D +channel-type.insteon.manualChangeButtonE.label = Manual Change Button E +channel-type.insteon.manualChangeButtonF.label = Manual Change Button F +channel-type.insteon.manualChangeButtonG.label = Manual Change Button G +channel-type.insteon.manualChangeButtonH.label = Manual Change Button H +channel-type.insteon.notification.label = Notification +channel-type.insteon.onLevel.label = On Level +channel-type.insteon.rampDimmer.label = Ramp Dimmer +channel-type.insteon.rampRate.label = Ramp Rate +channel-type.insteon.reset.label = Reset +channel-type.insteon.stage1Duration.label = Stage 1 Duration +channel-type.insteon.switch.label = Switch +channel-type.insteon.systemMode.label = System Mode +channel-type.insteon.tamperSwitch.label = Tamper Switch +channel-type.insteon.temperature.label = Temperature +channel-type.insteon.temperatureLevel.label = Temperature Level +channel-type.insteon.topOutlet.label = Top Outlet +channel-type.insteon.update.label = Update +channel-type.insteon.watts.label = Watts + +# channel types config + +channel-type.config.insteon.button.related.label = Related Devices +channel-type.config.insteon.button.related.description = List of related Insteon devices separated by a '+' sign. +channel-type.config.insteon.contact.related.label = Related Devices +channel-type.config.insteon.contact.related.description = List of related Insteon devices separated by a '+' sign. +channel-type.config.insteon.dimmer.dimmermax.label = Maximum Brightness +channel-type.config.insteon.dimmer.dimmermax.description = Maximum brightness of the dimmer in percentage. +channel-type.config.insteon.dimmer.related.label = Related Devices +channel-type.config.insteon.dimmer.related.description = List of related Insteon devices separated by a '+' sign. +channel-type.config.insteon.keypad-button-fastonoff.group.label = Group +channel-type.config.insteon.keypad-button-fastonoff.group.description = Insteon broadcast group configured for this button. +channel-type.config.insteon.keypad-button-manualchange.group.label = Group +channel-type.config.insteon.keypad-button-manualchange.group.description = Insteon broadcast group configured for this button. +channel-type.config.insteon.keypad-button.group.label = Group +channel-type.config.insteon.keypad-button.group.description = Insteon broadcast group configured for this button. +channel-type.config.insteon.keypad-button.related.label = Related Devices +channel-type.config.insteon.keypad-button.related.description = List of related Insteon devices separated by a '+' sign. +channel-type.config.insteon.switch.related.label = Related Devices +channel-type.config.insteon.switch.related.description = List of related Insteon devices separated by a '+' sign. diff --git a/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties new file mode 100644 index 0000000000000..27edc0a73e2ec --- /dev/null +++ b/bundles/org.openhab.binding.ipcamera/src/main/resources/OH-INF/i18n/ipcamera.properties @@ -0,0 +1,694 @@ +# binding + +binding.ipcamera.name = IpCamera Binding +binding.ipcamera.description = This binding interfaces IP cameras of various vendors via open protocols. + +# thing types + +thing-type.ipcamera.amcrest.label = Amcrest Camera with API +thing-type.ipcamera.amcrest.description = Use for older Amcrest Cameras, that wont work as dahua thing type. +thing-type.ipcamera.dahua.label = Dahua Camera with API +thing-type.ipcamera.dahua.description = Use for all current Dahua cameras, as they support an API as well as ONVIF. +thing-type.ipcamera.doorbird.label = Doorbird Camera with API +thing-type.ipcamera.doorbird.description = Use for all current Doorbird Cameras, as they support an API as well as ONVIF. +thing-type.ipcamera.foscam.label = Foscam Camera with API +thing-type.ipcamera.foscam.description = Use for all current HD FOSCAM Cameras as they support an API as well as ONVIF. +thing-type.ipcamera.generic.label = RTSP/HTTP IP Camera +thing-type.ipcamera.generic.description = Use when your camera is not ONVIF compatible. +thing-type.ipcamera.group.label = Group Multiple Cameras +thing-type.ipcamera.group.description = Show multiple cameras as a single rotating feed +thing-type.ipcamera.hikvision.label = Hikvision Camera with API +thing-type.ipcamera.hikvision.description = Use for all current Hikvision Cameras as they support an API as well as ONVIF. +thing-type.ipcamera.instar.label = Instar Camera with API +thing-type.ipcamera.instar.description = Use for all current INSTAR HD Cameras, as they support an API as well as ONVIF. +thing-type.ipcamera.onvif.label = ONVIF IP Camera +thing-type.ipcamera.onvif.description = Use when the binding does not list your brand of ONVIF camera. + +# thing types config + +thing-type.config.ipcamera.amcrest.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.amcrest.alarmInputUrl.description = Leave blank to use the FFmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.amcrest.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.amcrest.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.amcrest.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.amcrest.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.amcrest.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.amcrest.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.amcrest.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.amcrest.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.amcrest.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.amcrest.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.amcrest.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.amcrest.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.amcrest.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.amcrest.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.amcrest.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.amcrest.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.amcrest.group.Settings.label = Main Settings +thing-type.config.ipcamera.amcrest.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.amcrest.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.amcrest.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.amcrest.ipAddress.label = IP Address +thing-type.config.ipcamera.amcrest.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.amcrest.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.amcrest.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.amcrest.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.amcrest.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.amcrest.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.amcrest.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.amcrest.motionOptions.label = Motion Options +thing-type.config.ipcamera.amcrest.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.amcrest.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.amcrest.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.amcrest.nvrChannel.label = NVR Input Channel +thing-type.config.ipcamera.amcrest.nvrChannel.description = Set this to 1 if it is a stand alone camera, or to the input channel number of your NVR that the camera is connected to. +thing-type.config.ipcamera.amcrest.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.amcrest.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.amcrest.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.amcrest.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.amcrest.password.label = Password +thing-type.config.ipcamera.amcrest.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.amcrest.pollTime.label = Poll Time +thing-type.config.ipcamera.amcrest.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.amcrest.port.label = Port for HTTP +thing-type.config.ipcamera.amcrest.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.amcrest.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.amcrest.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.amcrest.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.amcrest.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.amcrest.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.amcrest.snapshotUrl.description = Leave this empty to auto detect the snapshot URL. Enter a HTTP address if you wish to over-ride with a different address which also makes the camera connect quicker. +thing-type.config.ipcamera.amcrest.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.amcrest.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.amcrest.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.amcrest.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.amcrest.username.label = Username +thing-type.config.ipcamera.amcrest.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.dahua.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.dahua.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.dahua.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.dahua.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.dahua.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.dahua.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.dahua.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.dahua.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.dahua.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.dahua.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.dahua.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.dahua.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.dahua.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.dahua.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.dahua.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.dahua.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.dahua.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.dahua.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.dahua.group.Settings.label = Main Settings +thing-type.config.ipcamera.dahua.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.dahua.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.dahua.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.dahua.ipAddress.label = IP Address +thing-type.config.ipcamera.dahua.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.dahua.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.dahua.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.dahua.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.dahua.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.dahua.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.dahua.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.dahua.motionOptions.label = Motion Options +thing-type.config.ipcamera.dahua.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.dahua.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.dahua.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.dahua.nvrChannel.label = NVR Input Channel +thing-type.config.ipcamera.dahua.nvrChannel.description = Set this to 1 if it is a stand alone camera, or to the input channel number of your NVR that the camera is connected to. +thing-type.config.ipcamera.dahua.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.dahua.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.dahua.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.dahua.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.dahua.password.label = Password +thing-type.config.ipcamera.dahua.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.dahua.pollTime.label = Poll Time +thing-type.config.ipcamera.dahua.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.dahua.port.label = Port for HTTP +thing-type.config.ipcamera.dahua.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.dahua.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.dahua.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.dahua.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.dahua.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.dahua.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.dahua.snapshotUrl.description = Leave blank to use the autodetected URL for snapshots, or enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.dahua.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.dahua.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.dahua.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.dahua.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.dahua.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.dahua.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.dahua.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.dahua.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.dahua.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.dahua.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.dahua.username.label = Username +thing-type.config.ipcamera.dahua.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.doorbird.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.doorbird.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.doorbird.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.doorbird.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.doorbird.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.doorbird.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.doorbird.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.doorbird.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.doorbird.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.doorbird.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.doorbird.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.doorbird.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.doorbird.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.doorbird.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.doorbird.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.doorbird.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.doorbird.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.doorbird.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.doorbird.group.Settings.label = Main Settings +thing-type.config.ipcamera.doorbird.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.doorbird.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.doorbird.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.doorbird.ipAddress.label = IP Address +thing-type.config.ipcamera.doorbird.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.doorbird.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.doorbird.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.doorbird.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.doorbird.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.doorbird.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.doorbird.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.doorbird.motionOptions.label = Motion Options +thing-type.config.ipcamera.doorbird.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.doorbird.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.doorbird.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.doorbird.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.doorbird.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.doorbird.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.doorbird.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.doorbird.password.label = Password +thing-type.config.ipcamera.doorbird.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.doorbird.pollTime.label = Poll Time +thing-type.config.ipcamera.doorbird.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.doorbird.port.label = Port for HTTP +thing-type.config.ipcamera.doorbird.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.doorbird.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.doorbird.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.doorbird.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.doorbird.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.doorbird.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.doorbird.snapshotUrl.description = Leave this empty to auto detect the snapshot URL. Enter a HTTP address if you wish to over-ride with a different address which also makes the camera connect quicker. +thing-type.config.ipcamera.doorbird.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.doorbird.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.doorbird.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.doorbird.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.doorbird.username.label = Username +thing-type.config.ipcamera.doorbird.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.foscam.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.foscam.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.foscam.customAudioAlarmUrl.label = Create your own custom enable Audio Alarm settings by entering a custom URL +thing-type.config.ipcamera.foscam.customAudioAlarmUrl.description = Leave this empty to use the default, or create your own setting. +thing-type.config.ipcamera.foscam.customMotionAlarmUrl.label = Create your own custom enable Motion Alarm settings by entering a custom URL +thing-type.config.ipcamera.foscam.customMotionAlarmUrl.description = Leave this empty to use the default, or create your own setting. +thing-type.config.ipcamera.foscam.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.foscam.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.foscam.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.foscam.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.foscam.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.foscam.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.foscam.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.foscam.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.foscam.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.foscam.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.foscam.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.foscam.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.foscam.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.foscam.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.foscam.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.foscam.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.foscam.group.Settings.label = Main Settings +thing-type.config.ipcamera.foscam.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.foscam.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.foscam.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.foscam.ipAddress.label = IP Address +thing-type.config.ipcamera.foscam.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.foscam.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.foscam.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.foscam.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.foscam.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.foscam.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.foscam.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.foscam.motionOptions.label = Motion Options +thing-type.config.ipcamera.foscam.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.foscam.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.foscam.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.foscam.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.foscam.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.foscam.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.foscam.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.foscam.password.label = Password +thing-type.config.ipcamera.foscam.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.foscam.pollTime.label = Poll Time +thing-type.config.ipcamera.foscam.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.foscam.port.label = Port for HTTP +thing-type.config.ipcamera.foscam.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.foscam.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.foscam.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.foscam.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.foscam.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.foscam.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.foscam.snapshotUrl.description = Leave blank to use the autodetected URL for snapshots, or enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.foscam.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.foscam.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.foscam.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.foscam.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.foscam.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.foscam.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.foscam.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.foscam.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.foscam.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.foscam.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.foscam.username.label = Username +thing-type.config.ipcamera.foscam.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.generic.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.generic.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.generic.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.generic.ffmpegInput.description = Enter any HTTP or RTSP URL that FFmpeg can use as an input. Best if H.264 format is used. +thing-type.config.ipcamera.generic.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.generic.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.generic.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.generic.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. Default should work for Linux, but For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.generic.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.generic.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.generic.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.generic.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.generic.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.generic.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.generic.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.generic.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.generic.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.generic.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.generic.group.Settings.label = Main Settings +thing-type.config.ipcamera.generic.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.generic.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.generic.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.generic.ipAddress.label = IP Address +thing-type.config.ipcamera.generic.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.generic.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.generic.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.generic.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.generic.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.generic.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.generic.mjpegUrl.description = Full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.generic.motionOptions.label = Motion Options +thing-type.config.ipcamera.generic.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.generic.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.generic.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.generic.password.label = Password +thing-type.config.ipcamera.generic.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.generic.pollTime.label = Poll Time +thing-type.config.ipcamera.generic.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.generic.port.label = Port for HTTP +thing-type.config.ipcamera.generic.port.description = This port will be used for HTTP calls ie for fetching the snapshot. +thing-type.config.ipcamera.generic.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.generic.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.generic.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.generic.snapshotUrl.description = Enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.generic.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.generic.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.generic.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.generic.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.generic.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.generic.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.generic.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.generic.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.generic.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.generic.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.generic.username.label = Username +thing-type.config.ipcamera.generic.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.group.ffmpegLocation.label = FFmpeg Location +thing-type.config.ipcamera.group.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. Default should work for Linux, but For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.group.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.group.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.group.firstCamera.label = First Camera ID +thing-type.config.ipcamera.group.firstCamera.description = Enter the 'Unique ID' of the camera you wish to show first. +thing-type.config.ipcamera.group.forthCamera.label = Forth Camera ID +thing-type.config.ipcamera.group.forthCamera.description = Enter the 'Unique ID' of the camera you wish to show forth. Leave blank if the group is less than 4. +thing-type.config.ipcamera.group.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.group.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.group.group.Settings.label = Main Settings +thing-type.config.ipcamera.group.group.Settings.description = Settings required to setup a group of cameras. +thing-type.config.ipcamera.group.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.group.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.group.motionChangesOrder.label = Motion Changes Order +thing-type.config.ipcamera.group.motionChangesOrder.description = When switched ON, any motion on a camera will make it show ahead of other cameras in the rotation. +thing-type.config.ipcamera.group.pollTime.label = Time Before Rotating to Next Camera +thing-type.config.ipcamera.group.pollTime.description = Time in milliseconds of how long to display a camera before changing to the next camera in the group. +thing-type.config.ipcamera.group.secondCamera.label = Second Camera ID +thing-type.config.ipcamera.group.secondCamera.description = Enter the 'Unique ID' of the camera you wish to show second. +thing-type.config.ipcamera.group.thirdCamera.label = Third Camera ID +thing-type.config.ipcamera.group.thirdCamera.description = Enter the 'Unique ID' of the camera you wish to show third. Leave blank if the group is less than 3. +thing-type.config.ipcamera.hikvision.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.hikvision.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.hikvision.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.hikvision.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.hikvision.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.hikvision.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.hikvision.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.hikvision.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.hikvision.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.hikvision.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.hikvision.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.hikvision.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.hikvision.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.hikvision.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.hikvision.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.hikvision.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.hikvision.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.hikvision.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.hikvision.group.Settings.label = Main Settings +thing-type.config.ipcamera.hikvision.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.hikvision.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.hikvision.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.hikvision.ipAddress.label = IP Address +thing-type.config.ipcamera.hikvision.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.hikvision.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.hikvision.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.hikvision.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.hikvision.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.hikvision.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.hikvision.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.hikvision.motionOptions.label = Motion Options +thing-type.config.ipcamera.hikvision.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.hikvision.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.hikvision.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.hikvision.nvrChannel.label = NVR Input Channel +thing-type.config.ipcamera.hikvision.nvrChannel.description = Set this to 1 if it is a stand alone camera, or to the input channel number if you use a compatible NVR. +thing-type.config.ipcamera.hikvision.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.hikvision.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.hikvision.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.hikvision.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.hikvision.password.label = Password +thing-type.config.ipcamera.hikvision.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.hikvision.pollTime.label = Poll Time +thing-type.config.ipcamera.hikvision.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.hikvision.port.label = Port for HTTP +thing-type.config.ipcamera.hikvision.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.hikvision.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.hikvision.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.hikvision.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.hikvision.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.hikvision.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.hikvision.snapshotUrl.description = Leave blank to use the autodetected URL for snapshots, or enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.hikvision.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.hikvision.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.hikvision.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.hikvision.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.hikvision.username.label = Username +thing-type.config.ipcamera.hikvision.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.instar.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.instar.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.instar.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.instar.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter any URL that FFmpeg can use as an input. +thing-type.config.ipcamera.instar.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.instar.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.instar.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.instar.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.instar.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.instar.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.instar.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.instar.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.instar.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.instar.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.instar.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.instar.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.instar.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.instar.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.instar.group.Settings.label = Main Settings +thing-type.config.ipcamera.instar.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.instar.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.instar.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.instar.ipAddress.label = IP Address +thing-type.config.ipcamera.instar.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.instar.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.instar.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.instar.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.instar.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.instar.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.instar.mjpegUrl.description = Leave this blank to use the auto detected URL, or enter a full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.instar.motionOptions.label = Motion Options +thing-type.config.ipcamera.instar.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.instar.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.instar.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.instar.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.instar.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.instar.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.instar.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.instar.password.label = Password +thing-type.config.ipcamera.instar.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.instar.pollTime.label = Poll Time +thing-type.config.ipcamera.instar.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.instar.port.label = Port for HTTP +thing-type.config.ipcamera.instar.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.instar.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.instar.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.instar.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.instar.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.instar.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.instar.snapshotUrl.description = Leave blank to use the autodetected URL for snapshots, or enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.instar.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.instar.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.instar.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.instar.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.instar.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.instar.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.instar.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.instar.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.instar.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.instar.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.instar.username.label = Username +thing-type.config.ipcamera.instar.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. +thing-type.config.ipcamera.onvif.alarmInputUrl.label = Alarm Input URL +thing-type.config.ipcamera.onvif.alarmInputUrl.description = Leave blank to use the ffmpegInput as the source for detecting motion with FFmpeg, or enter any HTTP or RTSP URL. TIP: Using a low res source can save CPU usage. +thing-type.config.ipcamera.onvif.ffmpegInput.label = FFmpeg Input +thing-type.config.ipcamera.onvif.ffmpegInput.description = Leave this blank to use the auto detected RTSP address, or enter a URL for any type of stream that FFmpeg can use as an input. +thing-type.config.ipcamera.onvif.ffmpegInputOptions.label = FFmpeg Input Options +thing-type.config.ipcamera.onvif.ffmpegInputOptions.description = This gives you direct access to specify FFmpeg options before the -i. +thing-type.config.ipcamera.onvif.ffmpegLocation.label = FFmpeg Install Location +thing-type.config.ipcamera.onvif.ffmpegLocation.description = The full path including the filename for where you have installed FFmpeg. For windows use this format, c:\ffmpeg\bin\ffmpeg.exe +thing-type.config.ipcamera.onvif.ffmpegOutput.label = FFmpeg Output Folder +thing-type.config.ipcamera.onvif.ffmpegOutput.description = Leave this blank and the binding will use the openHAB userdata folder. Alternatively, a unique path for each camera that ends with a slash and has write permissions can be entered. +thing-type.config.ipcamera.onvif.gifOutOptions.label = GIF Out Options +thing-type.config.ipcamera.onvif.gifOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for animated GIF files. +thing-type.config.ipcamera.onvif.gifPreroll.label = GIF Preroll +thing-type.config.ipcamera.onvif.gifPreroll.description = Store this many snapshots from BEFORE you trigger a GIF creation. +thing-type.config.ipcamera.onvif.group.FFmpeg Setup.label = FFmpeg Settings +thing-type.config.ipcamera.onvif.group.FFmpeg Setup.description = Settings that setup or effect the video stream. +thing-type.config.ipcamera.onvif.group.Image ch Settings.label = Image channel settings +thing-type.config.ipcamera.onvif.group.Image ch Settings.description = Settings for the image channel features which is not recommended to be used. See readme for more info. +thing-type.config.ipcamera.onvif.group.Settings.label = Main Settings +thing-type.config.ipcamera.onvif.group.Settings.description = Settings required to connect to the camera. +thing-type.config.ipcamera.onvif.hlsOutOptions.label = HLS Out Options +thing-type.config.ipcamera.onvif.hlsOutOptions.description = This gives you direct access to specify your own FFmpeg options to be used. +thing-type.config.ipcamera.onvif.ipAddress.label = IP Address +thing-type.config.ipcamera.onvif.ipAddress.description = Use this format 192.168.1.2 and do not include the port number. +thing-type.config.ipcamera.onvif.ipWhitelist.label = IP Whitelist +thing-type.config.ipcamera.onvif.ipWhitelist.description = Enter any IP's inside (brackets) that you wish to allow to access the video stream. 'DISABLE' will allow all devices on your network unrestricted access. +thing-type.config.ipcamera.onvif.mjpegOptions.label = MJPEG Options +thing-type.config.ipcamera.onvif.mjpegOptions.description = This gives you direct access to specify your own FFmpeg options to be used for MJPEG streams. +thing-type.config.ipcamera.onvif.mjpegUrl.label = MJPEG URL +thing-type.config.ipcamera.onvif.mjpegUrl.description = Full HTTP address to where a MJPEG stream can be watched if entered into any browser. +thing-type.config.ipcamera.onvif.motionOptions.label = Motion Options +thing-type.config.ipcamera.onvif.motionOptions.description = This gives you direct access to specify your own FFmpeg options to be used for detecting motion. +thing-type.config.ipcamera.onvif.mp4OutOptions.label = MP4 Out Options +thing-type.config.ipcamera.onvif.mp4OutOptions.description = This gives you direct access to specify your own FFmpeg options to be used for recording MP4 files. +thing-type.config.ipcamera.onvif.onvifMediaProfile.label = ONVIF Media Profile +thing-type.config.ipcamera.onvif.onvifMediaProfile.description = Cameras can supply more than one stream at different resolutions and formats. 0 selects the main-stream and 1 or above are the sub-streams. Sometimes you need to turn on sub-streams in the cameras setup before they can be used. +thing-type.config.ipcamera.onvif.onvifPort.label = ONVIF Port +thing-type.config.ipcamera.onvif.onvifPort.description = The port your camera uses for ONVIF connections. This is needed for PTZ movement, alarm events and auto discovery of RTSP and snapshot URLs. +thing-type.config.ipcamera.onvif.password.label = Password +thing-type.config.ipcamera.onvif.password.description = Enter the password for your camera. Leave blank if your camera does not use one. +thing-type.config.ipcamera.onvif.pollTime.label = Poll Time +thing-type.config.ipcamera.onvif.pollTime.description = Most features are made on demand and not polled, but some features require a regular snapshot to work. Default is "1000" which is 1 second. +thing-type.config.ipcamera.onvif.port.label = Port for HTTP +thing-type.config.ipcamera.onvif.port.description = This port will be used for HTTP calls for fetching the snapshot and alarm states. +thing-type.config.ipcamera.onvif.ptzContinuous.label = Use Continuous PTZ +thing-type.config.ipcamera.onvif.ptzContinuous.description = Select if you want Relative (false) or Continuous (true) movements. +thing-type.config.ipcamera.onvif.snapshotOptions.label = Snapshot Options +thing-type.config.ipcamera.onvif.snapshotOptions.description = Specify your own FFmpeg options to be used when creating snapshots from RTSP. +thing-type.config.ipcamera.onvif.snapshotUrl.label = Snapshot URL +thing-type.config.ipcamera.onvif.snapshotUrl.description = Leave blank to use the autodetected URL for snapshots, or enter a HTTP URL to where a snapshot can be seen if entered into any browser. +thing-type.config.ipcamera.onvif.updateImageWhen.label = Update Image Channel When: +thing-type.config.ipcamera.onvif.updateImageWhen.description = The Image channel can be set to update in a number of ways. Recommend you set this to never updates as per the readme. +thing-type.config.ipcamera.onvif.updateImageWhen.option.0 = Image channel never updates (0) +thing-type.config.ipcamera.onvif.updateImageWhen.option.1 = Image channel follows pollImage (1) +thing-type.config.ipcamera.onvif.updateImageWhen.option.2 = Start Motion Alarm (2) +thing-type.config.ipcamera.onvif.updateImageWhen.option.3 = Start Audio Alarm (3) +thing-type.config.ipcamera.onvif.updateImageWhen.option.23 = Start of Motion and Audio Alarms (23) +thing-type.config.ipcamera.onvif.updateImageWhen.option.4 = During Motion Alarm (4) +thing-type.config.ipcamera.onvif.updateImageWhen.option.5 = During Audio Alarm (5) +thing-type.config.ipcamera.onvif.updateImageWhen.option.45 = During Motion and Audio Alarms (45) +thing-type.config.ipcamera.onvif.username.label = Username +thing-type.config.ipcamera.onvif.username.description = Enter the User name used to connect to your camera. Leave blank if your camera does not use login details. + +# channel types + +channel-type.ipcamera.activateAlarmOutput.label = Alarm Output 1 ON/OFF +channel-type.ipcamera.activateAlarmOutput.description = You can use the cameras output to trigger a device like a burglar alarm. +channel-type.ipcamera.activateAlarmOutput2.label = Alarm Output 2 ON/OFF +channel-type.ipcamera.activateAlarmOutput2.description = You can use the cameras output 2 to trigger a device like a burglar alarm. +channel-type.ipcamera.audioAlarm.label = Audio Alarm +channel-type.ipcamera.audioAlarm.description = Audio has triggered an Alarm. +channel-type.ipcamera.autoLED.label = Auto LED +channel-type.ipcamera.autoLED.description = Turn the automatic mode for the LED ON and OFF. +channel-type.ipcamera.carAlarm.label = Car Alarm +channel-type.ipcamera.carAlarm.description = A car has triggered the Vehicle Detection. +channel-type.ipcamera.cellMotionAlarm.label = Cell Motion Alarm +channel-type.ipcamera.cellMotionAlarm.description = Cell based motion has been detected. +channel-type.ipcamera.doorBell.label = Door Bell +channel-type.ipcamera.doorBell.description = The button has been pushed. +channel-type.ipcamera.enableAudioAlarm.label = Enable Audio Alarm +channel-type.ipcamera.enableAudioAlarm.description = By using this feature you can stop the camera from sending e-mails when you are having a party. +channel-type.ipcamera.enableExternalAlarmInput.label = Enable Alarm Input 1 +channel-type.ipcamera.enableExternalAlarmInput.description = Turn the External Alarm Input feature on and off. +channel-type.ipcamera.enableFieldDetectionAlarm.label = Enable Field Alarm +channel-type.ipcamera.enableFieldDetectionAlarm.description = By using this feature you can stop the camera from sending e-mails when you are actually home. +channel-type.ipcamera.enableLED.label = LED Controls +channel-type.ipcamera.enableLED.description = Turn the LED ON and OFF and if supported also 0-100% dimming. +channel-type.ipcamera.enableLineCrossingAlarm.label = Enable Line Crossing Alarm +channel-type.ipcamera.enableLineCrossingAlarm.description = By using this feature you can stop the camera from sending e-mails when you are actually home. +channel-type.ipcamera.enableMotionAlarm.label = Enable Motion Alarm +channel-type.ipcamera.enableMotionAlarm.description = By using this feature you can stop the camera from sending e-mails when you are actually home. +channel-type.ipcamera.enablePirAlarm.label = Enable PIR Alarm +channel-type.ipcamera.enablePirAlarm.description = Enable/Disable the PIR Alarm. +channel-type.ipcamera.enablePrivacyMode.label = Enable Privacy Mode +channel-type.ipcamera.enablePrivacyMode.description = Turn the Privacy Mode on and off. +channel-type.ipcamera.externalAlarmInput.label = Alarm Input 1 +channel-type.ipcamera.externalAlarmInput.description = Some cameras have alarm input wires which can be used to connect to door bells or external PIR sensors. +channel-type.ipcamera.externalAlarmInput2.label = Alarm Input 2 +channel-type.ipcamera.externalAlarmInput2.description = Some cameras have alarm input wires which can be used to connect to door bells or external PIR sensors. +channel-type.ipcamera.externalLight.label = External Light +channel-type.ipcamera.externalLight.description = Turn the relay for external lights ON and OFF. +channel-type.ipcamera.externalMotion.label = External Motion +channel-type.ipcamera.externalMotion.description = Use any external sensor like a ZWave PIR sensor to flag that the camera has motion in its field of view. +channel-type.ipcamera.faceDetected.label = Face Detected Alarm +channel-type.ipcamera.faceDetected.description = A face has been detected. +channel-type.ipcamera.ffmpegMotionAlarm.label = FFmpeg Motion Alarm +channel-type.ipcamera.ffmpegMotionAlarm.description = FFmpeg has detected motion. +channel-type.ipcamera.ffmpegMotionControl.label = Control FFmpeg Motion Alarm +channel-type.ipcamera.ffmpegMotionControl.description = Enable/Disable the motion alarm and control the sensitivity. +channel-type.ipcamera.fieldDetectionAlarm.label = Field Alarm +channel-type.ipcamera.fieldDetectionAlarm.description = Intrusion has detected movement. AKA Field Detection Alarm. +channel-type.ipcamera.gifHistory.label = GIF History +channel-type.ipcamera.gifHistory.description = A history of the last GIFs created in a CSV formatted string. +channel-type.ipcamera.gifHistoryLength.label = GIF History Length +channel-type.ipcamera.gifHistoryLength.description = How many GIFs are stored in the history. +channel-type.ipcamera.gotoPreset.label = Go To Preset +channel-type.ipcamera.gotoPreset.description = Move a P.T.Z camera to this ONVIF preset location. +channel-type.ipcamera.gotoPreset.state.option.1 = Preset 1 +channel-type.ipcamera.gotoPreset.state.option.2 = Preset 2 +channel-type.ipcamera.gotoPreset.state.option.3 = Preset 3 +channel-type.ipcamera.gotoPreset.state.option.4 = Preset 4 +channel-type.ipcamera.gotoPreset.state.option.5 = Preset 5 +channel-type.ipcamera.gotoPreset.state.option.6 = Preset 6 +channel-type.ipcamera.gotoPreset.state.option.7 = Preset 7 +channel-type.ipcamera.gotoPreset.state.option.8 = Preset 8 +channel-type.ipcamera.gotoPreset.state.option.9 = Preset 9 +channel-type.ipcamera.gotoPreset.state.option.10 = Preset 10 +channel-type.ipcamera.gotoPreset.state.option.11 = Preset 11 +channel-type.ipcamera.gotoPreset.state.option.12 = Preset 12 +channel-type.ipcamera.gotoPreset.state.option.13 = Preset 13 +channel-type.ipcamera.gotoPreset.state.option.14 = Preset 14 +channel-type.ipcamera.gotoPreset.state.option.15 = Preset 15 +channel-type.ipcamera.gotoPreset.state.option.16 = Preset 16 +channel-type.ipcamera.gotoPreset.state.option.17 = Preset 17 +channel-type.ipcamera.gotoPreset.state.option.18 = Preset 18 +channel-type.ipcamera.gotoPreset.state.option.19 = Preset 19 +channel-type.ipcamera.gotoPreset.state.option.20 = Preset 20 +channel-type.ipcamera.gotoPreset.state.option.21 = Preset 21 +channel-type.ipcamera.gotoPreset.state.option.22 = Preset 22 +channel-type.ipcamera.gotoPreset.state.option.23 = Preset 23 +channel-type.ipcamera.gotoPreset.state.option.24 = Preset 24 +channel-type.ipcamera.gotoPreset.state.option.25 = Preset 25 +channel-type.ipcamera.hlsUrl.label = HLS URL +channel-type.ipcamera.hlsUrl.description = A link you can use in openHAB to cast video feeds. +channel-type.ipcamera.humanAlarm.label = Human Alarm +channel-type.ipcamera.humanAlarm.description = A person has triggered the Human Detection. +channel-type.ipcamera.image.label = Image +channel-type.ipcamera.image.description = Low frame rate image from your camera. Recommend this is NOT used unless you have large pollTime. +channel-type.ipcamera.imageUrl.label = Image URL +channel-type.ipcamera.imageUrl.description = A link you can use to fetch a static image from the camera. +channel-type.ipcamera.itemLeft.label = Item Left Alarm +channel-type.ipcamera.itemLeft.description = An item has been left. +channel-type.ipcamera.itemTaken.label = Item Taken Alarm +channel-type.ipcamera.itemTaken.description = An item may have been stolen. +channel-type.ipcamera.lastEventData.label = Last Event Data +channel-type.ipcamera.lastEventData.description = A string that contains detailed data on the last alarm that was triggered. +channel-type.ipcamera.lastMotionType.label = Last Motion Type +channel-type.ipcamera.lastMotionType.description = A string that contains the type of motion alarm that was last triggered. +channel-type.ipcamera.lineCrossingAlarm.label = Line Crossing Alarm +channel-type.ipcamera.lineCrossingAlarm.description = Motion has been detected. +channel-type.ipcamera.mjpegUrl.label = MJPEG URL +channel-type.ipcamera.mjpegUrl.description = A link you can use in openHAB/HABpanel to fetch a MJPEG video feed from the camera. +channel-type.ipcamera.motionAlarm.label = Motion Alarm +channel-type.ipcamera.motionAlarm.description = Motion has been detected. +channel-type.ipcamera.mp4History.label = MP4 History +channel-type.ipcamera.mp4History.description = A history of the last mp4 recordings created in a CSV formatted string. +channel-type.ipcamera.mp4HistoryLength.label = MP4 History Length +channel-type.ipcamera.mp4HistoryLength.description = How many mp4 recordings are stored in the history. +channel-type.ipcamera.pan.label = Pan +channel-type.ipcamera.pan.description = Pan the camera to a new position. +channel-type.ipcamera.parkingAlarm.label = Parking Alarm +channel-type.ipcamera.parkingAlarm.description = A car has triggered the Parking Detection. +channel-type.ipcamera.pirAlarm.label = PIR Alarm +channel-type.ipcamera.pirAlarm.description = PIR motion has been detected. +channel-type.ipcamera.pollImage.label = Poll Image +channel-type.ipcamera.pollImage.description = This can be used to trigger snapshot updates when an external PIR, button or other form of sensor turns this channel ON. +channel-type.ipcamera.recordingGif.label = GIF Recording +channel-type.ipcamera.recordingGif.description = Indicates how long the recording will occur for and when the file is created, the channel will change to 0 by itself. +channel-type.ipcamera.recordingMp4.label = MP4 Recording +channel-type.ipcamera.recordingMp4.description = Indicates how long the recording will occur for and when the file is created, the channel will change to 0 by itself. +channel-type.ipcamera.rtspUrl.label = RTSP URL +channel-type.ipcamera.rtspUrl.description = A link that the camera uses for RTSP. +channel-type.ipcamera.sceneChangeAlarm.label = Scene Change Alarm +channel-type.ipcamera.sceneChangeAlarm.description = Camera may have been moved. +channel-type.ipcamera.startStream.label = Start HLS Stream +channel-type.ipcamera.startStream.description = Lower the delay to start casting the camera by creating the files non stop in case they are needed. +channel-type.ipcamera.storageAlarm.label = Storage Alarm +channel-type.ipcamera.storageAlarm.description = An issue with the cameras storage has been reported. +channel-type.ipcamera.tamperAlarm.label = Tamper Alarm +channel-type.ipcamera.tamperAlarm.description = Camera may be stolen or damaged. +channel-type.ipcamera.textOverlay.label = Text Overlay +channel-type.ipcamera.textOverlay.description = Enter some text you wish to overlay on top of the cameras snapshot and video streams. +channel-type.ipcamera.thresholdAudioAlarm.label = Audio Alarm Threshold +channel-type.ipcamera.thresholdAudioAlarm.description = By moving this control you should be able to change how sensitive the audio alarm is to soft or loud noises. +channel-type.ipcamera.tilt.label = Tilt +channel-type.ipcamera.tilt.description = Tilt the camera to a new position. +channel-type.ipcamera.tooBlurryAlarm.label = Too Blurry Alarm +channel-type.ipcamera.tooBlurryAlarm.description = Image is out of focus. +channel-type.ipcamera.tooBrightAlarm.label = Too Bright Alarm +channel-type.ipcamera.tooBrightAlarm.description = Image is too bright. +channel-type.ipcamera.tooDarkAlarm.label = Too Dark Alarm +channel-type.ipcamera.tooDarkAlarm.description = Image is too dark. +channel-type.ipcamera.triggerExternalAlarmInput.label = Alarm In 1 TRIGGER high ON/low OFF +channel-type.ipcamera.triggerExternalAlarmInput.description = Change the External Alarm Input to trigger on high or low states. +channel-type.ipcamera.zoom.label = Zoom +channel-type.ipcamera.zoom.description = Zoom the camera to a new value. diff --git a/bundles/org.openhab.binding.ipobserver/src/main/resources/OH-INF/i18n/ipobserver.properties b/bundles/org.openhab.binding.ipobserver/src/main/resources/OH-INF/i18n/ipobserver.properties new file mode 100644 index 0000000000000..d515eb12e1749 --- /dev/null +++ b/bundles/org.openhab.binding.ipobserver/src/main/resources/OH-INF/i18n/ipobserver.properties @@ -0,0 +1,57 @@ +# binding + +binding.ipobserver.name = IpObserver Binding +binding.ipobserver.description = This is the binding for weather stations marketed under many brands that come with or have an IpObserver station connected. + +# thing types + +thing-type.ipobserver.weatherstation.label = Weather Station +thing-type.ipobserver.weatherstation.description = Use for any weather station sold under multiple brands that come with an IP Observer unit. + +# thing types config + +thing-type.config.ipobserver.weatherstation.address.label = Network Address +thing-type.config.ipobserver.weatherstation.address.description = Hostname or IP for the IP Observer +thing-type.config.ipobserver.weatherstation.autoReboot.label = Auto Reboot +thing-type.config.ipobserver.weatherstation.autoReboot.description = Time in milliseconds to wait for a reply before rebooting the IP Observer. A value of 0 disables this feature allowing you to manually trigger or use a rule to handle the reboots +thing-type.config.ipobserver.weatherstation.pollTime.label = Poll Time +thing-type.config.ipobserver.weatherstation.pollTime.description = Time in seconds between each Scan of the livedata.htm from the ObserverIP + +# channel types + +channel-type.ipobserver.humidityIndoor.label = Indoor Humidity +channel-type.ipobserver.humidityIndoor.description = Current Humidity Indoors +channel-type.ipobserver.lastUpdatedTime.label = Last Updated Time +channel-type.ipobserver.lastUpdatedTime.description = Time of the last livedata scrape +channel-type.ipobserver.pressureAbsolute.label = Pressure Absolute +channel-type.ipobserver.pressureAbsolute.description = Absolute Current Pressure +channel-type.ipobserver.pressureRelative.label = Pressure Relative +channel-type.ipobserver.pressureRelative.description = Relative Current Pressure +channel-type.ipobserver.rainForMonth.label = Rain for Month +channel-type.ipobserver.rainForMonth.description = Rain since 12:00 on the 1st of this month +channel-type.ipobserver.rainForWeek.label = Rain for Week +channel-type.ipobserver.rainForWeek.description = Weekly Rain +channel-type.ipobserver.rainForYear.label = Rain for Year +channel-type.ipobserver.rainForYear.description = Total rain since 12:00 on 1st Jan +channel-type.ipobserver.rainHourlyRate.label = Rain Hourly Rate +channel-type.ipobserver.rainHourlyRate.description = How much rain will fall in an Hour if the rate continues +channel-type.ipobserver.rainToday.label = Rain Today +channel-type.ipobserver.rainToday.description = Rain since Midnight +channel-type.ipobserver.responseTime.label = Response Time +channel-type.ipobserver.responseTime.description = How many milliseconds it took to fetch the sensor readings from livedata.htm +channel-type.ipobserver.solarRadiation.label = Solar Radiation +channel-type.ipobserver.solarRadiation.description = Solar Radiation +channel-type.ipobserver.temperatureIndoor.label = Indoor Temperature +channel-type.ipobserver.temperatureIndoor.description = Current Temperature Indoors +channel-type.ipobserver.uv.label = UV +channel-type.ipobserver.uv.description = UV +channel-type.ipobserver.uvIndex.label = UV Index +channel-type.ipobserver.uvIndex.description = UV Index +channel-type.ipobserver.windAverageSpeed.label = Wind Average Speed +channel-type.ipobserver.windAverageSpeed.description = Average Wind Speed +channel-type.ipobserver.windGust.label = Wind Gust +channel-type.ipobserver.windGust.description = Wind Gust +channel-type.ipobserver.windMaxGust.label = Wind Max Gust +channel-type.ipobserver.windMaxGust.description = Max wind gust for today +channel-type.ipobserver.windSpeed.label = Wind Speed +channel-type.ipobserver.windSpeed.description = Wind Speed diff --git a/bundles/org.openhab.binding.ipp/src/main/resources/OH-INF/i18n/ipp.properties b/bundles/org.openhab.binding.ipp/src/main/resources/OH-INF/i18n/ipp.properties new file mode 100644 index 0000000000000..a118211db0c6a --- /dev/null +++ b/bundles/org.openhab.binding.ipp/src/main/resources/OH-INF/i18n/ipp.properties @@ -0,0 +1,27 @@ +# binding + +binding.ipp.name = IPP Binding +binding.ipp.description = This is the binding for the Internet Printing Protocol (IPP). You can show how many jobs are done/waiting on an IPP/CUPS Printer + +# thing types + +thing-type.ipp.printer.label = Printer +thing-type.ipp.printer.description = A IPP Printer + +# thing types config + +thing-type.config.ipp.printer.name.label = Name +thing-type.config.ipp.printer.name.description = The name of the printer +thing-type.config.ipp.printer.refresh.label = Refresh Interval +thing-type.config.ipp.printer.refresh.description = Specifies the refresh interval in seconds +thing-type.config.ipp.printer.url.label = URL +thing-type.config.ipp.printer.url.description = The URL of the printer + +# channel types + +channel-type.ipp.doneJobs.label = Done Jobs +channel-type.ipp.doneJobs.description = Number of completed print jobs on the printer +channel-type.ipp.jobs.label = Total Jobs +channel-type.ipp.jobs.description = Total number of print jobs on the printer +channel-type.ipp.waitingJobs.label = Waiting Jobs +channel-type.ipp.waitingJobs.description = Number of waiting print jobs on the printer diff --git a/bundles/org.openhab.binding.irobot/src/main/resources/OH-INF/i18n/irobot.properties b/bundles/org.openhab.binding.irobot/src/main/resources/OH-INF/i18n/irobot.properties new file mode 100644 index 0000000000000..6558b351eec54 --- /dev/null +++ b/bundles/org.openhab.binding.irobot/src/main/resources/OH-INF/i18n/irobot.properties @@ -0,0 +1,154 @@ +# binding + +binding.irobot.name = iRobot Binding +binding.irobot.description = This is the binding for iRobot vacuum robots. + +# thing types + +thing-type.irobot.roomba.label = Roomba +thing-type.irobot.roomba.description = A Roomba vacuum robot +thing-type.irobot.roomba.channel.sched_fri.label = Schedule Fri +thing-type.irobot.roomba.channel.sched_fri.description = Friday schedule active +thing-type.irobot.roomba.channel.sched_mon.label = Schedule Mon +thing-type.irobot.roomba.channel.sched_mon.description = Monday schedule active +thing-type.irobot.roomba.channel.sched_sat.label = Schedule Sat +thing-type.irobot.roomba.channel.sched_sat.description = Saturday schedule active +thing-type.irobot.roomba.channel.sched_sun.label = Schedule Sun +thing-type.irobot.roomba.channel.sched_sun.description = Sunday schedule active +thing-type.irobot.roomba.channel.sched_thu.label = Schedule Thu +thing-type.irobot.roomba.channel.sched_thu.description = Thirsday schedule active +thing-type.irobot.roomba.channel.sched_tue.label = Schedule Tue +thing-type.irobot.roomba.channel.sched_tue.description = Tuesday schedule active +thing-type.irobot.roomba.channel.sched_wed.label = Schedule Wed +thing-type.irobot.roomba.channel.sched_wed.description = Wednesday schedule active + +# thing types config + +thing-type.config.irobot.thing.blid.label = Robot ID +thing-type.config.irobot.thing.blid.description = ID of the robot +thing-type.config.irobot.thing.ipaddress.label = Network Address +thing-type.config.irobot.thing.ipaddress.description = Network address of the robot +thing-type.config.irobot.thing.password.label = Password +thing-type.config.irobot.thing.password.description = Password of the robot + +# channel types + +channel-type.irobot.always_finish.label = Always finish +channel-type.irobot.always_finish.description = Do not pause current mission if the bin is full +channel-type.irobot.battery.label = Battery +channel-type.irobot.battery.description = Battery charge percentage +channel-type.irobot.bin.label = Bin +channel-type.irobot.bin.description = Bin status +channel-type.irobot.bin.state.option.ok = OK +channel-type.irobot.bin.state.option.full = Full +channel-type.irobot.bin.state.option.removed = Removed +channel-type.irobot.clean_passes.label = Cleaning passes +channel-type.irobot.clean_passes.description = Number of cleaning passes to make +channel-type.irobot.clean_passes.state.option.auto = Automatic +channel-type.irobot.clean_passes.state.option.1 = One pass +channel-type.irobot.clean_passes.state.option.2 = Two passes +channel-type.irobot.command.label = Command +channel-type.irobot.command.description = Command to execute +channel-type.irobot.command.state.option.clean = Clean +channel-type.irobot.command.state.option.spot = Spot +channel-type.irobot.command.state.option.dock = Dock +channel-type.irobot.command.state.option.pause = Pause +channel-type.irobot.command.state.option.stop = Stop +channel-type.irobot.cycle.label = Mission +channel-type.irobot.cycle.description = Current mission +channel-type.irobot.cycle.state.option.none = None +channel-type.irobot.cycle.state.option.clean = Clean +channel-type.irobot.cycle.state.option.spot = Spot +channel-type.irobot.edge_clean.label = Edge clean +channel-type.irobot.edge_clean.description = Seek out and clean along walls and furniture legs +channel-type.irobot.error.label = Error +channel-type.irobot.error.description = Error code +channel-type.irobot.error.state.option.0 = None +channel-type.irobot.error.state.option.1 = Left wheel off floor +channel-type.irobot.error.state.option.2 = Main Brushes stuck +channel-type.irobot.error.state.option.3 = Right wheel off floor +channel-type.irobot.error.state.option.4 = Left wheel stuck +channel-type.irobot.error.state.option.5 = Right wheel stuck +channel-type.irobot.error.state.option.6 = Stuck near a cliff +channel-type.irobot.error.state.option.7 = Left wheel error +channel-type.irobot.error.state.option.8 = Bin error +channel-type.irobot.error.state.option.9 = Bumper stuck +channel-type.irobot.error.state.option.10 = Right wheel error +channel-type.irobot.error.state.option.11 = Bin error +channel-type.irobot.error.state.option.12 = Cliff sensor issue +channel-type.irobot.error.state.option.13 = Both wheels off floor +channel-type.irobot.error.state.option.14 = Bin missing +channel-type.irobot.error.state.option.15 = Reboot required +channel-type.irobot.error.state.option.16 = Bumped unexpectedly +channel-type.irobot.error.state.option.17 = Path blocked +channel-type.irobot.error.state.option.18 = Docking issue +channel-type.irobot.error.state.option.19 = Undocking issue +channel-type.irobot.error.state.option.20 = Docking issue +channel-type.irobot.error.state.option.21 = Navigation problem +channel-type.irobot.error.state.option.22 = Navigation problem +channel-type.irobot.error.state.option.23 = Battery issue +channel-type.irobot.error.state.option.24 = Navigation problem +channel-type.irobot.error.state.option.25 = Reboot required +channel-type.irobot.error.state.option.26 = Vacuum problem +channel-type.irobot.error.state.option.27 = Vacuum problem +channel-type.irobot.error.state.option.29 = Software update needed +channel-type.irobot.error.state.option.30 = Vacuum problem +channel-type.irobot.error.state.option.31 = Reboot required +channel-type.irobot.error.state.option.32 = Smart map problem +channel-type.irobot.error.state.option.33 = Path blocked +channel-type.irobot.error.state.option.34 = Reboot required +channel-type.irobot.error.state.option.35 = Unrecognized cleaning pad +channel-type.irobot.error.state.option.36 = Bin full +channel-type.irobot.error.state.option.37 = Tank needed refilling +channel-type.irobot.error.state.option.38 = Vacuum problem +channel-type.irobot.error.state.option.39 = Reboot required +channel-type.irobot.error.state.option.40 = Navigation problem +channel-type.irobot.error.state.option.41 = Timed out +channel-type.irobot.error.state.option.42 = Localization problem +channel-type.irobot.error.state.option.43 = Navigation problem +channel-type.irobot.error.state.option.44 = Pump issue +channel-type.irobot.error.state.option.45 = Lid open +channel-type.irobot.error.state.option.46 = Low battery +channel-type.irobot.error.state.option.47 = Reboot required +channel-type.irobot.error.state.option.48 = Path blocked +channel-type.irobot.error.state.option.52 = Pad required attention +channel-type.irobot.error.state.option.65 = Hardware problem detected +channel-type.irobot.error.state.option.66 = Low memory +channel-type.irobot.error.state.option.68 = Hardware problem detected +channel-type.irobot.error.state.option.73 = Pad type changed +channel-type.irobot.error.state.option.74 = Max area reached +channel-type.irobot.error.state.option.75 = Navigation problem +channel-type.irobot.error.state.option.76 = Hardware problem detected +channel-type.irobot.lastCommand.label = Last Command +channel-type.irobot.lastCommand.description = The last command which has been received by the iRobot +channel-type.irobot.map_upload.label = Map upload +channel-type.irobot.map_upload.description = Enable uploading Clean Map(tm) to cloud for reporting +channel-type.irobot.phase.label = State +channel-type.irobot.phase.description = Current state +channel-type.irobot.phase.state.option.charge = Charging +channel-type.irobot.phase.state.option.new = New Mission +channel-type.irobot.phase.state.option.run = Running +channel-type.irobot.phase.state.option.resume = Resumed +channel-type.irobot.phase.state.option.hmMidMsn = Going for recharge in mission +channel-type.irobot.phase.state.option.recharge = Recharging +channel-type.irobot.phase.state.option.stuck = Stuck +channel-type.irobot.phase.state.option.hmUsrDock = Going home +channel-type.irobot.phase.state.option.dock = Docking +channel-type.irobot.phase.state.option.dockend = Docking - End Mission +channel-type.irobot.phase.state.option.cancelled = Cancelled +channel-type.irobot.phase.state.option.stop = Stopped +channel-type.irobot.phase.state.option.pause = Paused +channel-type.irobot.phase.state.option.hmPostMsn = Going home after mission +channel-type.irobot.phase.state.option. = None +channel-type.irobot.power_boost.label = Power boost +channel-type.irobot.power_boost.description = Carpet boost mode +channel-type.irobot.power_boost.state.option.auto = Automatic +channel-type.irobot.power_boost.state.option.performance = Performance mode +channel-type.irobot.power_boost.state.option.eco = Eco mode +channel-type.irobot.rssi.label = RSSI +channel-type.irobot.rssi.description = Wi-Fi signal strength +channel-type.irobot.sched_switch.label = Schedule +channel-type.irobot.schedule.label = Schedule +channel-type.irobot.schedule.description = Schedule bitmask for use in scripts: Sun Mon Tue Wed Thu Fri Sat +channel-type.irobot.snr.label = SNR +channel-type.irobot.snr.description = Wi-Fi signal to noise ratio diff --git a/bundles/org.openhab.binding.irtrans/src/main/resources/OH-INF/i18n/irtrans.properties b/bundles/org.openhab.binding.irtrans/src/main/resources/OH-INF/i18n/irtrans.properties new file mode 100644 index 0000000000000..bca7cbed4c956 --- /dev/null +++ b/bundles/org.openhab.binding.irtrans/src/main/resources/OH-INF/i18n/irtrans.properties @@ -0,0 +1,54 @@ +# binding + +binding.irtrans.name = IRtrans Binding +binding.irtrans.description = This is the binding for IRtrans (www.irtrans.de) Transceivers + +# thing types + +thing-type.irtrans.blaster.label = Blaster +thing-type.irtrans.blaster.description = This is an infrared transmitter that can send infrared commands +thing-type.irtrans.ethernet.label = IRtrans Ethernet Bridge +thing-type.irtrans.ethernet.description = This is an Ethernet (PoE) IRtrans transceiver equipped with an on-board IRDB database + +# thing types config + +thing-type.config.irtrans.blaster.command.label = Command +thing-type.config.irtrans.blaster.command.description = The name of the command will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any command +thing-type.config.irtrans.blaster.led.label = Led +thing-type.config.irtrans.blaster.led.description = The Led on which infrared commands will be emitted +thing-type.config.irtrans.blaster.remote.label = Remote +thing-type.config.irtrans.blaster.remote.description = The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any remote +thing-type.config.irtrans.ethernet.bufferSize.label = Buffer Size +thing-type.config.irtrans.ethernet.bufferSize.description = Buffer size used by the TCP socket when sending and receiving commands to the transceiver +thing-type.config.irtrans.ethernet.ipAddress.label = Network Address +thing-type.config.irtrans.ethernet.ipAddress.description = Network address of the ethernet transceiver +thing-type.config.irtrans.ethernet.pingTimeOut.label = Ping Time Out +thing-type.config.irtrans.ethernet.pingTimeOut.description = Specifies the time milliseconds to wait for a response from the transceiver when pinging the device +thing-type.config.irtrans.ethernet.portNumber.label = Port Number +thing-type.config.irtrans.ethernet.portNumber.description = TCP port number of the transceiver service +thing-type.config.irtrans.ethernet.reconnectInterval.label = Reconnect Interval +thing-type.config.irtrans.ethernet.reconnectInterval.description = Specifies the time seconds to wait before reconnecting to a transceiver after a communication failure +thing-type.config.irtrans.ethernet.responseTimeOut.label = Response Time Out +thing-type.config.irtrans.ethernet.responseTimeOut.description = Specifies the time milliseconds to wait for a response from the transceiver when sending a command. + +# channel types + +channel-type.irtrans.blaster.label = Blaster Channel +channel-type.irtrans.blaster.description = The Blaster Channel allows to send (filtered) infrared commands over the specified blaster led of the transceiver +channel-type.irtrans.io.label = Input/Output +channel-type.irtrans.io.description = Read commands received by the blaster, or write commands to be sent by the blaster +channel-type.irtrans.receiver.label = Receiver Channel +channel-type.irtrans.receiver.description = The Receiver Channel allows to receive (filtered) infrared commands on the receiver led of the transceiver + +# channel types config + +channel-type.config.irtrans.blaster.command.label = Command +channel-type.config.irtrans.blaster.command.description = The name of the command will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any command +channel-type.config.irtrans.blaster.led.label = Led +channel-type.config.irtrans.blaster.led.description = The Led on which infrared commands will be emitted +channel-type.config.irtrans.blaster.remote.label = Remote +channel-type.config.irtrans.blaster.remote.description = The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any remote +channel-type.config.irtrans.receiver.command.label = Command +channel-type.config.irtrans.receiver.command.description = The name of the command will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any command +channel-type.config.irtrans.receiver.remote.label = Remote +channel-type.config.irtrans.receiver.remote.description = The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server database and flashed into the transceiver. Can be '*' for any remote diff --git a/bundles/org.openhab.binding.ism8/src/main/resources/OH-INF/i18n/ism8.properties b/bundles/org.openhab.binding.ism8/src/main/resources/OH-INF/i18n/ism8.properties new file mode 100644 index 0000000000000..62ee6daa3bc08 --- /dev/null +++ b/bundles/org.openhab.binding.ism8/src/main/resources/OH-INF/i18n/ism8.properties @@ -0,0 +1,60 @@ +# binding + +binding.ism8.name = ISM8 Binding +binding.ism8.description = This is the binding for the ISM8 card used for Wolf heating systems or other Wolf eBus devices. + +# thing types + +thing-type.ism8.device.label = ISM8 Device +thing-type.ism8.device.description = ISM8 Interface + +# thing types config + +thing-type.config.ism8.device.portNumber.label = Port +thing-type.config.ism8.device.portNumber.description = Port number of the object server + +# channel types + +channel-type.ism8.number-readonly.label = Value Readonly DataPoint +channel-type.ism8.number.label = Value DataPoint +channel-type.ism8.switch-readonly.label = Digital Readonly DataPoint +channel-type.ism8.switch.label = Digital DataPoint + +# channel types config + +channel-type.config.ism8.number-readonly.id.label = DP ID +channel-type.config.ism8.number-readonly.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem. +channel-type.config.ism8.number-readonly.type.label = Type +channel-type.config.ism8.number-readonly.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001) +channel-type.config.ism8.number-readonly.type.option.5.001 = DPT_Scaling +channel-type.config.ism8.number-readonly.type.option.9.001 = DPT_Value_Temp +channel-type.config.ism8.number-readonly.type.option.9.002 = DPT_Value_Tempd +channel-type.config.ism8.number-readonly.type.option.9.006 = DPT_Value_Pres +channel-type.config.ism8.number-readonly.type.option.13.002 = DPT_FlowRate +channel-type.config.ism8.number-readonly.type.option.20.102 = DPT_HVACMode +channel-type.config.ism8.number-readonly.type.option.20.103 = DPT_DHWMode +channel-type.config.ism8.number-readonly.type.option.20.105 = DPT_HVACContrMode +channel-type.config.ism8.number.id.label = DP ID +channel-type.config.ism8.number.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem. +channel-type.config.ism8.number.type.label = Type +channel-type.config.ism8.number.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Value_Temp / 9.001) +channel-type.config.ism8.number.type.option.9.001 = DPT_Value_Temp +channel-type.config.ism8.number.type.option.20.102 = DPT_HVACMode +channel-type.config.ism8.number.type.option.20.103 = DPT_DHWMode +channel-type.config.ism8.number.type.option.20.105 = DPT_HVACContrMode +channel-type.config.ism8.switch-readonly.id.label = DP ID +channel-type.config.ism8.switch-readonly.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem. +channel-type.config.ism8.switch-readonly.type.label = Type +channel-type.config.ism8.switch-readonly.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001) +channel-type.config.ism8.switch-readonly.type.option.1.001 = DPT_Switch +channel-type.config.ism8.switch-readonly.type.option.1.002 = DPT_Bool +channel-type.config.ism8.switch-readonly.type.option.1.003 = DPT_Enable +channel-type.config.ism8.switch-readonly.type.option.1.009 = DPT_OpenClose +channel-type.config.ism8.switch.id.label = DP ID +channel-type.config.ism8.switch.id.description = Put the number of the DataPoint ID to be mapped from the heating sytem. +channel-type.config.ism8.switch.type.label = Type +channel-type.config.ism8.switch.type.description = Put the KNX-type of the DataPoint (e.g. DPT_Switch / 1.001) +channel-type.config.ism8.switch.type.option.1.001 = DPT_Switch +channel-type.config.ism8.switch.type.option.1.002 = DPT_Bool +channel-type.config.ism8.switch.type.option.1.003 = DPT_Enable +channel-type.config.ism8.switch.type.option.1.009 = DPT_OpenClose diff --git a/bundles/org.openhab.binding.jablotron/src/main/resources/OH-INF/i18n/jablotron.properties b/bundles/org.openhab.binding.jablotron/src/main/resources/OH-INF/i18n/jablotron.properties new file mode 100644 index 0000000000000..9ef0a7a9fa4c5 --- /dev/null +++ b/bundles/org.openhab.binding.jablotron/src/main/resources/OH-INF/i18n/jablotron.properties @@ -0,0 +1,106 @@ +# binding + +binding.jablotron.name = Jablotron Binding +binding.jablotron.description = This is the binding for Jablotron Alarm Systems. + +# thing types + +thing-type.jablotron.bridge.label = Jablonet Bridge +thing-type.jablotron.bridge.description = A bridge to the Jablonet cloud service. +thing-type.jablotron.ja100.label = JA100 Alarm +thing-type.jablotron.ja100.description = A Jablotron JA100 alarm device. +thing-type.jablotron.ja100f.label = JA100F Alarm +thing-type.jablotron.ja100f.description = A Jablotron JA100F alarm device. +thing-type.jablotron.oasis.label = Oasis Alarm +thing-type.jablotron.oasis.description = A Jablotron Oasis alarm device. + +# thing types config + +bridge-type.config.jablotron.bridge.lang.label = Language +bridge-type.config.jablotron.bridge.lang.description = Language for Jablonet portal +bridge-type.config.jablotron.bridge.lang.option.cs = Česky +bridge-type.config.jablotron.bridge.lang.option.da = Dansk +bridge-type.config.jablotron.bridge.lang.option.de = Deutsch +bridge-type.config.jablotron.bridge.lang.option.en = English +bridge-type.config.jablotron.bridge.lang.option.es = Español +bridge-type.config.jablotron.bridge.lang.option.fr = Français +bridge-type.config.jablotron.bridge.lang.option.hr = Hrvatski +bridge-type.config.jablotron.bridge.lang.option.it = Italiano +bridge-type.config.jablotron.bridge.lang.option.hu = Magyar +bridge-type.config.jablotron.bridge.lang.option.nl = Nederlands +bridge-type.config.jablotron.bridge.lang.option.vi = Người việt nam +bridge-type.config.jablotron.bridge.lang.option.no = Norsk +bridge-type.config.jablotron.bridge.lang.option.pl = Polski +bridge-type.config.jablotron.bridge.lang.option.pt = Portugues +bridge-type.config.jablotron.bridge.lang.option.ro = Română +bridge-type.config.jablotron.bridge.lang.option.sl = Slovenski +bridge-type.config.jablotron.bridge.lang.option.sk = Slovensky +bridge-type.config.jablotron.bridge.lang.option.sr = Srpski +bridge-type.config.jablotron.bridge.lang.option.fi = Suomi +bridge-type.config.jablotron.bridge.lang.option.sv = Svenska +bridge-type.config.jablotron.bridge.lang.option.tr = Türkçe +bridge-type.config.jablotron.bridge.login.label = Login +bridge-type.config.jablotron.bridge.login.description = Login for Jablonet portal +bridge-type.config.jablotron.bridge.password.label = Password +bridge-type.config.jablotron.bridge.password.description = Password for Jablonet portal +bridge-type.config.jablotron.bridge.refresh.label = Refresh +bridge-type.config.jablotron.bridge.refresh.description = Specifies the refresh time for all alarm warnings (alarm, service mode, ...) +thing-type.config.jablotron.device.refresh.label = Refresh +thing-type.config.jablotron.device.refresh.description = Specifies the refresh time of thing channels in seconds +thing-type.config.jablotron.device.serviceId.label = Alarm Service ID +thing-type.config.jablotron.device.serviceId.description = The service ID of the Oasis alarm +thing-type.config.jablotron.ja100device.code.label = Code +thing-type.config.jablotron.ja100device.code.description = Master code for the JA100 alarm +thing-type.config.jablotron.ja100device.refresh.label = Refresh +thing-type.config.jablotron.ja100device.refresh.description = Specifies the refresh time of thing channels in seconds +thing-type.config.jablotron.ja100device.serviceId.label = Alarm Service ID +thing-type.config.jablotron.ja100device.serviceId.description = The service ID of the JA100 alarm + +# channel types + +channel-type.jablotron.alarm.label = Alarm +channel-type.jablotron.alarm.description = Status of the alarm of your alarm +channel-type.jablotron.alarm_state.label = Alarm State +channel-type.jablotron.alarm_state.description = A channel used for controlling the alarm state +channel-type.jablotron.alarm_state.state.option.set = ARMED +channel-type.jablotron.alarm_state.state.option.partialSet = PARTIAL +channel-type.jablotron.alarm_state.state.option.unset = DISARMED +channel-type.jablotron.command.label = Alarm Command +channel-type.jablotron.command.description = Channel for sending commands to your alarm +channel-type.jablotron.ja100f_alarm_state.label = Alarm State +channel-type.jablotron.ja100f_alarm_state.description = A channel used for controlling the alarm state +channel-type.jablotron.ja100f_alarm_state.state.option.ARM = ARMED +channel-type.jablotron.ja100f_alarm_state.state.option.PARTIAL_ARM = PARTIAL +channel-type.jablotron.ja100f_alarm_state.state.option.DISARM = DISARMED +channel-type.jablotron.lastCheckTime.label = Alarm Last Check Time +channel-type.jablotron.lastCheckTime.description = Date and time of last status check of your alarm +channel-type.jablotron.lastEvent.label = Alarm Last Event Text Description +channel-type.jablotron.lastEvent.description = Text description of the last event of your alarm +channel-type.jablotron.lastEventClass.label = Alarm Last Event Class +channel-type.jablotron.lastEventClass.description = Class of the last event of your alarm (arm, disarm, ...) +channel-type.jablotron.lastEventInvoker.label = Alarm Last Event Invoker +channel-type.jablotron.lastEventInvoker.description = The last event invoker +channel-type.jablotron.lastEventSection.label = Alarm Last Event Section +channel-type.jablotron.lastEventSection.description = The last event section of your alarm +channel-type.jablotron.lastEventTime.label = Alarm Last Event Time +channel-type.jablotron.lastEventTime.description = Date and time of the last event of your alarm +channel-type.jablotron.pgm_state.label = Programmable Gate State +channel-type.jablotron.pgm_state.description = A channel used for controlling the PGM state +channel-type.jablotron.status.label = Alarm Section Status +channel-type.jablotron.status.description = Status of the section of your alarm +channel-type.jablotron.statusA.label = Alarm Zone A Status +channel-type.jablotron.statusA.description = Status of the A zone of your alarm +channel-type.jablotron.statusABC.label = Alarm Zone ABC Status +channel-type.jablotron.statusABC.description = Status of the ABC zone of your alarm +channel-type.jablotron.statusB.label = Alarm B Status +channel-type.jablotron.statusB.description = Status of the B zone of your alarm +channel-type.jablotron.statusPGM.label = JA-100 PGM Status +channel-type.jablotron.statusPGM.description = Status of the PGM switch of your JA-100 alarm +channel-type.jablotron.statusPGX.label = OASIS PGX Status +channel-type.jablotron.statusPGX.description = Status of the PGX switch of your OASIS alarm +channel-type.jablotron.statusPGY.label = OASIS PGY Status +channel-type.jablotron.statusPGY.description = Status of the PGY switch of your OASIS alarm +channel-type.jablotron.temperature.label = Sensor Temperature +channel-type.jablotron.temperature.description = The current temperature reported by the sensor +channel-type.jablotron.thermostat.label = Thermostat Temperature +channel-type.jablotron.thermostat.description = The current temperature reported by the thermostat diff --git a/bundles/org.openhab.binding.kaleidescape/src/main/resources/OH-INF/i18n/kaleidescape.properties b/bundles/org.openhab.binding.kaleidescape/src/main/resources/OH-INF/i18n/kaleidescape.properties new file mode 100644 index 0000000000000..77bcbbcac88b9 --- /dev/null +++ b/bundles/org.openhab.binding.kaleidescape/src/main/resources/OH-INF/i18n/kaleidescape.properties @@ -0,0 +1,206 @@ +# binding + +binding.kaleidescape.name = Kaleidescape System Binding +binding.kaleidescape.description = Controls a Kaleidescape System Movie Player + +# thing types + +thing-type.kaleidescape.alto.label = Kaleidescape Alto +thing-type.kaleidescape.alto.description = A Kaleidescape Alto Player +thing-type.kaleidescape.alto.group.detail.label = Content Details +thing-type.kaleidescape.alto.group.detail.description = Contains Metadata About a Selected Item +thing-type.kaleidescape.alto.group.ui.label = User Interface +thing-type.kaleidescape.alto.group.ui.description = Controls and Information for the Alto's On Screen Interface +thing-type.kaleidescape.cinemaone.label = Kaleidescape Cinema One (2nd Generation) +thing-type.kaleidescape.cinemaone.description = A Kaleidescape Cinema One (2nd Generation) Player +thing-type.kaleidescape.cinemaone.group.detail.label = Content Details +thing-type.kaleidescape.cinemaone.group.detail.description = Contains Metadata About a Selected Item +thing-type.kaleidescape.cinemaone.group.music.label = Music Zone +thing-type.kaleidescape.cinemaone.group.music.description = Controls and Information for the Cinema One's Music Zone +thing-type.kaleidescape.cinemaone.group.ui.label = User Interface +thing-type.kaleidescape.cinemaone.group.ui.description = Controls and Information for the Cinema One's On Screen Interface +thing-type.kaleidescape.player.label = Kaleidescape Player +thing-type.kaleidescape.player.description = A Kaleidescape Movie Player (KPlayer, M Class [M300, M500, M700] or Cinema One 1st Gen) +thing-type.kaleidescape.player.group.detail.label = Content Details +thing-type.kaleidescape.player.group.detail.description = Contains Metadata About a Selected Item +thing-type.kaleidescape.player.group.music.label = Music Zone +thing-type.kaleidescape.player.group.music.description = Controls and Information for the Player's Music Zone +thing-type.kaleidescape.player.group.ui.label = User Interface +thing-type.kaleidescape.player.group.ui.description = Controls and Information for the Player's On Screen Interface +thing-type.kaleidescape.strato.label = Kaleidescape Strato +thing-type.kaleidescape.strato.description = A Kaleidescape Strato Player +thing-type.kaleidescape.strato.group.detail.label = Content Details +thing-type.kaleidescape.strato.group.detail.description = Contains Metadata About a Selected Item +thing-type.kaleidescape.strato.group.ui.label = User Interface +thing-type.kaleidescape.strato.group.ui.description = Controls and Information for the Strato's On Screen Interface + +# thing types config + +thing-type.config.kaleidescape.kaleidescapedevice.host.label = Address +thing-type.config.kaleidescape.kaleidescapedevice.host.description = Host Name or IP Address of the Kaleidescape component. +thing-type.config.kaleidescape.kaleidescapedevice.initialVolume.label = Initial Volume Setting +thing-type.config.kaleidescape.kaleidescapedevice.initialVolume.description = When the binding starts up, set the Inital Volume level to this value (Default 25). +thing-type.config.kaleidescape.kaleidescapedevice.loadAlbumDetails.label = Load Album Details +thing-type.config.kaleidescape.kaleidescapedevice.loadAlbumDetails.description = When enabled the binding will automatically load the metadata channels for the currently playing Album. Not applicable for Alto and Strato components. +thing-type.config.kaleidescape.kaleidescapedevice.loadHighlightedDetails.label = Load Highlighted Details +thing-type.config.kaleidescape.kaleidescapedevice.loadHighlightedDetails.description = When enabled the binding will automatically load the metadata channels when the selected item in the UI (Movie or Album) changes. +thing-type.config.kaleidescape.kaleidescapedevice.port.label = Port +thing-type.config.kaleidescape.kaleidescapedevice.port.description = Communication Port for IP Connection to the Kaleidescape component. +thing-type.config.kaleidescape.kaleidescapedevice.serialPort.label = Serial Port +thing-type.config.kaleidescape.kaleidescapedevice.serialPort.description = (Optional) Serial Port to use for connecting directly to an individual Kaleidescape component. +thing-type.config.kaleidescape.kaleidescapedevice.updatePeriod.label = Update Period +thing-type.config.kaleidescape.kaleidescapedevice.updatePeriod.description = Tells the component how often time status updates should be sent; Values greater than 1 are not yet implmented by the protocol. Setting to 1 may impact openHAB system performance due to constant updates while content playing. +thing-type.config.kaleidescape.kaleidescapedevice.volumeEnabled.label = Volume Control Enabled +thing-type.config.kaleidescape.kaleidescapedevice.volumeEnabled.description = Enable the Volume and Mute controls in the Kaleidescape iPad & Phone apps and track their status in the binding. Disabled by default to prevent conflicts with other control systems that may already be controlling volume on this zone. + +# channel group types + +channel-group-type.kaleidescape.alto-strato_detail.label = Content Details +channel-group-type.kaleidescape.alto-strato_detail.description = Contains metadata about a selected item +channel-group-type.kaleidescape.c1-alto_ui.label = User Interface +channel-group-type.kaleidescape.c1-alto_ui.description = Controls and information for the player's on screen interface +channel-group-type.kaleidescape.detail.label = Content Details +channel-group-type.kaleidescape.detail.description = Contains metadata about a selected item +channel-group-type.kaleidescape.music.label = Music Zone +channel-group-type.kaleidescape.music.description = Controls and information for the player's music zone +channel-group-type.kaleidescape.strato_ui.label = User Interface +channel-group-type.kaleidescape.strato_ui.description = Controls and information for the player's on screen interface +channel-group-type.kaleidescape.ui.label = User Interface +channel-group-type.kaleidescape.ui.description = Controls and information for the player's on screen interface + +# channel types + +channel-type.kaleidescape.actors.label = Actors +channel-type.kaleidescape.actors.description = A list of actors appearing in the selected Movie +channel-type.kaleidescape.album.label = Album +channel-type.kaleidescape.album.description = The name of the currently playing album +channel-type.kaleidescape.album_handle.label = Album Handle +channel-type.kaleidescape.album_handle.description = The handle of the currently playing album +channel-type.kaleidescape.album_title.label = Album Title +channel-type.kaleidescape.album_title.description = The title of the selected Album +channel-type.kaleidescape.artist.label = Artist +channel-type.kaleidescape.artist.description = The name of the currently playing artist +channel-type.kaleidescape.artist.label = Artist +channel-type.kaleidescape.artist.description = The artist of the selected Album +channel-type.kaleidescape.aspect_ratio.label = Aspect Ratio +channel-type.kaleidescape.aspect_ratio.description = Identifies the aspect ratio of the movie +channel-type.kaleidescape.aspect_ratio.label = Aspect Ratio +channel-type.kaleidescape.aspect_ratio.description = The aspect ratio of the selected Movie +channel-type.kaleidescape.chapter_length.label = Chapter Length +channel-type.kaleidescape.chapter_length.description = The total running time of the current chapter +channel-type.kaleidescape.chapter_loc.label = Chapter Location +channel-type.kaleidescape.chapter_loc.description = The running time elapsed of the current chapter +channel-type.kaleidescape.chapter_num.label = Chapter Number +channel-type.kaleidescape.chapter_num.description = The current chapter number of the movie that is playing +channel-type.kaleidescape.child_mode_state.label = Child Mode State +channel-type.kaleidescape.child_mode_state.description = Indicates if the on screen display is displaying the child user interface +channel-type.kaleidescape.cinemascape_mask.label = CinemaScape Mask +channel-type.kaleidescape.cinemascape_mask.description = When in CinemaScape mode, provides information about the frame aspect ratio +channel-type.kaleidescape.cinemascape_mode.label = CinemaScape Mode +channel-type.kaleidescape.cinemascape_mode.description = Identifies the CinemaScape mode currently active +channel-type.kaleidescape.color_description.label = Color Description +channel-type.kaleidescape.color_description.description = Indicates if the selected Movie is in color, black and white, etc. +channel-type.kaleidescape.content_color.label = Content Color +channel-type.kaleidescape.content_color.description = Provides color information about the currently playing content +channel-type.kaleidescape.content_color_eotf.label = Content Color EOTF +channel-type.kaleidescape.content_color_eotf.description = Identifies the Electro-Optical Transfer Function standard of the currently playing content +channel-type.kaleidescape.country.label = Country +channel-type.kaleidescape.country.description = The country that the selected Movie originates from +channel-type.kaleidescape.cover_art.label = Cover Art +channel-type.kaleidescape.cover_art.description = Cover Art image of the currently selected item +channel-type.kaleidescape.cover_url.label = Cover Art URL +channel-type.kaleidescape.cover_url.description = The URL of the Cover Art +channel-type.kaleidescape.directors.label = Directors +channel-type.kaleidescape.directors.description = A list of directors of the selected Movie +channel-type.kaleidescape.disc_location.label = Disc Location +channel-type.kaleidescape.disc_location.description = Indicates where the disc for the selected item is currently residing in the system (ie Vault, Tray, etc.) +channel-type.kaleidescape.genres.label = Genres +channel-type.kaleidescape.genres.description = A list of genres of the selected item +channel-type.kaleidescape.highlighted_selection.label = Highlighted Selection +channel-type.kaleidescape.highlighted_selection.description = Specifies the handle of the movie or album currently selected on the user interface +channel-type.kaleidescape.hires_cover_url.label = HiRes Cover Art URL +channel-type.kaleidescape.hires_cover_url.description = The URL of the high resolution Cover Art +channel-type.kaleidescape.movie_control.label = Control +channel-type.kaleidescape.movie_control.description = Control movie playback e.g. Play/Pause/Next/Previous/Fast Forward/Rewind +channel-type.kaleidescape.movie_location.label = Movie Location +channel-type.kaleidescape.movie_location.description = Identifies the location in the movie, ie: Main Content, Intermission, or End Credits +channel-type.kaleidescape.movie_media_type.label = Media Type +channel-type.kaleidescape.movie_media_type.description = The type of media that is currently playing +channel-type.kaleidescape.movie_play_mode.label = Play Mode +channel-type.kaleidescape.movie_play_mode.description = The Current playback mode of the movie +channel-type.kaleidescape.movie_play_speed.label = Play Speed +channel-type.kaleidescape.movie_play_speed.description = The speed of playback scanning +channel-type.kaleidescape.music_control.label = Control +channel-type.kaleidescape.music_control.description = Control music playback e.g. Play/Pause/Next/Previous/Fforward/Rewind +channel-type.kaleidescape.music_play_mode.label = Play Mode +channel-type.kaleidescape.music_play_mode.description = The current playback mode of the music +channel-type.kaleidescape.music_play_speed.label = Play Speed +channel-type.kaleidescape.music_play_speed.description = The speed of playback scanning +channel-type.kaleidescape.nowplay_handle.label = Now Playing Handle +channel-type.kaleidescape.nowplay_handle.description = The handle of the current now playing list +channel-type.kaleidescape.random.label = Random +channel-type.kaleidescape.random.description = Controls random playback for music +channel-type.kaleidescape.rating.label = Rating +channel-type.kaleidescape.rating.description = The MPAA rating of the selected Movie +channel-type.kaleidescape.rating_reason.label = Rating Reason +channel-type.kaleidescape.rating_reason.description = An explaination of why the selected movie received its rating +channel-type.kaleidescape.readiness_state.label = System Readiness State +channel-type.kaleidescape.readiness_state.description = Indicates the system's current idle mode +channel-type.kaleidescape.repeat.label = Repeat +channel-type.kaleidescape.repeat.description = Controls repeat playback for music +channel-type.kaleidescape.review.label = Review +channel-type.kaleidescape.review.description = A review of the selected Album +channel-type.kaleidescape.running_time.label = Running time +channel-type.kaleidescape.running_time.description = The total running time of the selected item +channel-type.kaleidescape.scale_mode.label = Scale Mode +channel-type.kaleidescape.scale_mode.description = Identifies whether the image from the player requires scaling +channel-type.kaleidescape.screen_mask.label = Screen Mask +channel-type.kaleidescape.screen_mask.description = Provides aspect ratio and masking information for the current video image +channel-type.kaleidescape.screen_mask2.label = Screen Mask 2 +channel-type.kaleidescape.screen_mask2.description = Provides masking information based on aspect ratio and overscan area +channel-type.kaleidescape.synopsis.label = Synopsis +channel-type.kaleidescape.synopsis.description = A synopsis of the selected Movie +channel-type.kaleidescape.title.label = Movie Title +channel-type.kaleidescape.title.description = The title of the selected Movie +channel-type.kaleidescape.title_length.label = Title Length +channel-type.kaleidescape.title_length.description = The total running time of the currently playing movie +channel-type.kaleidescape.title_loc.label = Title Location +channel-type.kaleidescape.title_loc.description = The running time elapsed of the currently playing movie +channel-type.kaleidescape.title_name.label = Title Name +channel-type.kaleidescape.title_name.description = The title of the movie currently playing +channel-type.kaleidescape.title_num.label = Title Number +channel-type.kaleidescape.title_num.description = The current movie title number that is playing +channel-type.kaleidescape.track.label = Track +channel-type.kaleidescape.track.description = The name of the currently playing track +channel-type.kaleidescape.track_handle.label = Track Handle +channel-type.kaleidescape.track_handle.description = The handle of the currently playing track +channel-type.kaleidescape.track_length.label = Track Length +channel-type.kaleidescape.track_length.description = The total running time of the current playing track +channel-type.kaleidescape.track_position.label = Track Position +channel-type.kaleidescape.track_position.description = The running time elapsed of the current playing track +channel-type.kaleidescape.track_progress.label = Track Progress +channel-type.kaleidescape.track_progress.description = The percentage complete of the current playing track +channel-type.kaleidescape.type.label = Detail Type +channel-type.kaleidescape.type.description = Indicates If the currently selected item is a Movie or Album +channel-type.kaleidescape.ui_state.label = UI State +channel-type.kaleidescape.ui_state.description = Provides information about which screen is visible in the Kaleidescape user interface +channel-type.kaleidescape.user_defined_event.label = User Defined Event +channel-type.kaleidescape.user_defined_event.description = Will contain custom event messages generated by scripts, sent from another component, or triggered by system events +channel-type.kaleidescape.user_input.label = User Input +channel-type.kaleidescape.user_input.description = Indicates if the user is being prompted for input, what type of input, and any currently entered characters +channel-type.kaleidescape.user_input_prompt.label = User Input Prompt +channel-type.kaleidescape.user_input_prompt.description = Indicates user input prompt info and properties currently shown on screen +channel-type.kaleidescape.video_color.label = Video Color +channel-type.kaleidescape.video_color.description = Provides Color Information About the Current Video Output +channel-type.kaleidescape.video_color_eotf.label = Video Color EOTF +channel-type.kaleidescape.video_color_eotf.description = Identifies the Electro-Optical Transfer Function standard of the current video output +channel-type.kaleidescape.video_mode.label = Video Mode - Raw +channel-type.kaleidescape.video_mode.description = Raw output of video mode data from the component, format: 00:00:00 +channel-type.kaleidescape.video_mode_component.label = Video Mode - Component +channel-type.kaleidescape.video_mode_component.description = Identifies the video currently active on the Component video output +channel-type.kaleidescape.video_mode_composite.label = Video Mode - Composite +channel-type.kaleidescape.video_mode_composite.description = Identifies the video currently active on the Composite video output +channel-type.kaleidescape.video_mode_hdmi.label = Video Mode - HDMI +channel-type.kaleidescape.video_mode_hdmi.description = Identifies the video currently active on the HDMI video output +channel-type.kaleidescape.year.label = Year +channel-type.kaleidescape.year.description = The release year of the selected item diff --git a/bundles/org.openhab.binding.keba/src/main/resources/OH-INF/i18n/keba.properties b/bundles/org.openhab.binding.keba/src/main/resources/OH-INF/i18n/keba.properties new file mode 100644 index 0000000000000..c6b061fe4e9f2 --- /dev/null +++ b/bundles/org.openhab.binding.keba/src/main/resources/OH-INF/i18n/keba.properties @@ -0,0 +1,90 @@ +# binding + +binding.keba.name = Keba Binding +binding.keba.description = This is the binding for Keba EV Charging Stations + +# thing types + +thing-type.keba.kecontact.label = KeContact EV Charging Station +thing-type.keba.kecontact.description = A KeContact EV Charging Station +thing-type.keba.kecontact.channel.I1.label = Current Phase 1 +thing-type.keba.kecontact.channel.I2.label = Current Phase 2 +thing-type.keba.kecontact.channel.I3.label = Current Phase 3 +thing-type.keba.kecontact.channel.U1.label = Voltage Phase 1 +thing-type.keba.kecontact.channel.U2.label = Voltage Phase 2 +thing-type.keba.kecontact.channel.U3.label = Voltage Phase 3 + +# thing types config + +thing-type.config.keba.kecontact.ipAddress.label = Network Address +thing-type.config.keba.kecontact.ipAddress.description = Network address of the wallbox +thing-type.config.keba.kecontact.refreshInterval.label = Refresh Interval +thing-type.config.keba.kecontact.refreshInterval.description = Specifies the refresh interval in seconds + +# channel types + +channel-type.keba.authenticate.label = Authenticate +channel-type.keba.authenticate.description = Authenticate and start a charging session +channel-type.keba.authon.label = Authentication Enabled +channel-type.keba.authon.description = Authentication enabled +channel-type.keba.authreq.label = Authentication Required +channel-type.keba.authreq.description = Authentication required +channel-type.keba.current.label = Current +channel-type.keba.current.description = Current +channel-type.keba.current_settable.label = Preset Current +channel-type.keba.current_settable.description = Preset Current +channel-type.keba.display.label = Display +channel-type.keba.display.description = Text to show on the P30 Series C or X display +channel-type.keba.enabled.label = Enabled +channel-type.keba.enabled.description = Activation state of the wallbox +channel-type.keba.energy.label = Energy Session +channel-type.keba.energy.description = Power consumption +channel-type.keba.error1.label = Error Code 1 +channel-type.keba.error1.description = Error code state, if in error. See the KeContact FAQ +channel-type.keba.error2.label = Error Code 2 +channel-type.keba.error2.description = Error code state, if in error. See the KeContact FAQ +channel-type.keba.failsafecurrent.label = Failsafe Current +channel-type.keba.failsafecurrent.description = Failsafe Current (if network is lost) +channel-type.keba.locked.label = Plug Lock +channel-type.keba.locked.description = Indicator if the plug is locked by the electrical vehicle +channel-type.keba.maxcurrent.label = Max. System Current +channel-type.keba.maxcurrent.description = Maximal System Current +channel-type.keba.pilotcurrent.label = Pilot Current +channel-type.keba.pilotcurrent.description = Current value offered to the vehicle via control pilot signalization (PWM) +channel-type.keba.pilotcurrentdutycyle.label = Pilot Current Duty Cycle +channel-type.keba.pilotcurrentdutycyle.description = Duty cycle of the control pilot signal +channel-type.keba.plugvehicle.label = Vehicle Plugged +channel-type.keba.plugvehicle.description = State of the vehicle plug, e.g. ON if plugged in, OFF if unplugged +channel-type.keba.plugwallbox.label = Wallbox Plugged +channel-type.keba.plugwallbox.description = State of the wallbox plug, e.g. ON if plugged in, OFF if unplugged +channel-type.keba.power.label = Power +channel-type.keba.power.description = Active Power +channel-type.keba.powerfactor.label = Power Factor +channel-type.keba.powerfactor.description = Power factor (cosphi) +channel-type.keba.range.label = Rel. Current +channel-type.keba.range.description = Current in % of the 6-63 A range accepted by the wallbox +channel-type.keba.sessionid.label = Session ID +channel-type.keba.sessionid.description = Session ID of the last charging session +channel-type.keba.sessionrfidclass.label = RFID Tag Class +channel-type.keba.sessionrfidclass.description = RFID Tag class used for the last charging session +channel-type.keba.sessionrfidtag.label = RFID Tag +channel-type.keba.sessionrfidtag.description = RFID Tag used for the last charging session +channel-type.keba.setenergylimit.label = Energy Limit +channel-type.keba.setenergylimit.description = An energy limit for an already running or the next charging session +channel-type.keba.state.label = Operation State +channel-type.keba.state.description = Current operational state of the wallbox +channel-type.keba.state.state.option.0 = Starting +channel-type.keba.state.state.option.1 = Not Ready +channel-type.keba.state.state.option.2 = Ready +channel-type.keba.state.state.option.3 = Charging +channel-type.keba.state.state.option.4 = Error +channel-type.keba.totalenergy.label = Energy Total +channel-type.keba.totalenergy.description = Total energy consumption is added up after each completed charging session +channel-type.keba.uptime.label = System Uptime +channel-type.keba.uptime.description = System uptime since the last reset of the wallbox +channel-type.keba.voltage.label = Voltage +channel-type.keba.voltage.description = Voltage +channel-type.keba.x1.label = X1 +channel-type.keba.x1.description = State of the X1 input +channel-type.keba.x2.label = X2 +channel-type.keba.x2.description = State of the X2 output diff --git a/bundles/org.openhab.binding.km200/src/main/resources/OH-INF/i18n/km200.properties b/bundles/org.openhab.binding.km200/src/main/resources/OH-INF/i18n/km200.properties new file mode 100644 index 0000000000000..7851dba1eca6c --- /dev/null +++ b/bundles/org.openhab.binding.km200/src/main/resources/OH-INF/i18n/km200.properties @@ -0,0 +1,46 @@ +# binding + +binding.km200.name = KM200 Binding +binding.km200.description = The KM200 Binding is communicating with a Buderus Logamatic web KM200 / KM100 / KM50 gateway. These devices are gateways for heating systems and allows to control them. It is possible to receive and send parameters. + +# thing types + +thing-type.km200.appliance.label = Appliance +thing-type.km200.appliance.description = This thing is representing the appliance (The heater inside of this heating system). +thing-type.km200.dhwCircuit.label = Hot Water Circuit +thing-type.km200.dhwCircuit.description = This thing is representing a hot water circuit. +thing-type.km200.gateway.label = Gateway +thing-type.km200.gateway.description = This thing is representing the gateway. (The connected KM200/100/50 device) +thing-type.km200.heatSource.label = Heat Source +thing-type.km200.heatSource.description = This thing is representing the heat source. +thing-type.km200.heatingCircuit.label = Heating Circuit +thing-type.km200.heatingCircuit.description = This thing is representing a heating circuit. +thing-type.km200.holidayMode.label = Holiday Mode +thing-type.km200.holidayMode.description = This thing is representing the holiday modes configuration. +thing-type.km200.kmdevice.label = KM200/100/50 +thing-type.km200.kmdevice.description = The KM200 binding is communicating with a Buderus Logamatic web KM200 / KM100 / KM50. It is possible to receive and send parameters like string or float values. +thing-type.km200.notification.label = Notifications +thing-type.km200.notification.description = This thing is representing the notifications. +thing-type.km200.sensor.label = Sensors +thing-type.km200.sensor.description = This thing is representing the sensors. +thing-type.km200.solarCircuit.label = Solar Circuit +thing-type.km200.solarCircuit.description = This thing is representing a solar circuit. +thing-type.km200.switchProgram.label = Switch Program +thing-type.km200.switchProgram.description = This thing is representing a switch program. +thing-type.km200.system.label = System +thing-type.km200.system.description = This thing is representing the system without sensors and appliance. +thing-type.km200.systemStates.label = System States +thing-type.km200.systemStates.description = This thing is representing the systems states. + +# thing types config + +thing-type.config.km200.kmdevice.ip4Address.label = IP4 Address +thing-type.config.km200.kmdevice.ip4Address.description = IP4 Address of the KMXXX device +thing-type.config.km200.kmdevice.maxNbrRepeats.label = Maximum Number of Repeats +thing-type.config.km200.kmdevice.maxNbrRepeats.description = Maximum number of repeats in case of a communication error (like HTTP 500 error) +thing-type.config.km200.kmdevice.privateKey.label = Private Key +thing-type.config.km200.kmdevice.privateKey.description = Private en-/decryption key built from MD5Salt, GatewayPassword and PrivatePassword +thing-type.config.km200.kmdevice.readDelay.label = Read Delay +thing-type.config.km200.kmdevice.readDelay.description = Delay between two read attempts in ms +thing-type.config.km200.kmdevice.refreshInterval.label = Auto Refresh Interval +thing-type.config.km200.kmdevice.refreshInterval.description = Auto refresh interval in seconds diff --git a/bundles/org.openhab.binding.knx/src/main/resources/OH-INF/i18n/knx.properties b/bundles/org.openhab.binding.knx/src/main/resources/OH-INF/i18n/knx.properties new file mode 100644 index 0000000000000..01c6da0176556 --- /dev/null +++ b/bundles/org.openhab.binding.knx/src/main/resources/OH-INF/i18n/knx.properties @@ -0,0 +1,134 @@ +# binding + +binding.knx.name = KNX Binding +binding.knx.description = This binding supports connecting to a KNX bus + +# thing types + +thing-type.knx.device.label = KNX Device +thing-type.knx.device.description = An addressable basic KNX device +thing-type.knx.ip.label = KNX/IP Gateway +thing-type.knx.ip.description = This is a KNX IP interface or router +thing-type.knx.serial.label = KNX FT1.2 Interface +thing-type.knx.serial.description = This is a serial interface for accessing the KNX bus + +# thing types config + +thing-type.config.knx.device.address.label = Address +thing-type.config.knx.device.address.description = The individual address in x.y.z notation +thing-type.config.knx.device.fetch.label = Fetch +thing-type.config.knx.device.fetch.description = Read out the device parameters and address/communication object tables +thing-type.config.knx.device.pingInterval.label = Interval +thing-type.config.knx.device.pingInterval.description = Interval (in seconds) between attempts to poll the device status +thing-type.config.knx.device.readInterval.label = Interval +thing-type.config.knx.device.readInterval.description = Interval (in seconds) between attempts to read the status group addresses on the bus +thing-type.config.knx.ip.autoReconnectPeriod.label = Auto Reconnect Period +thing-type.config.knx.ip.autoReconnectPeriod.description = Seconds between connection retries when KNX link has been lost, 0 means never retry, minimum 30s +thing-type.config.knx.ip.ipAddress.label = Network Address +thing-type.config.knx.ip.ipAddress.description = Network address of the KNX/IP gateway +thing-type.config.knx.ip.localIp.label = Local Network Address +thing-type.config.knx.ip.localIp.description = Network address of the local host to be used to set up the connection to the KNX/IP gateway +thing-type.config.knx.ip.localSourceAddr.label = Local Device Address +thing-type.config.knx.ip.localSourceAddr.description = The Physical Address (Individual Address) in x.y.z notation for identification of this KNX/IP gateway within the KNX bus +thing-type.config.knx.ip.portNumber.label = Port +thing-type.config.knx.ip.portNumber.description = Port number of the KNX/IP gateway +thing-type.config.knx.ip.readRetriesLimit.label = Read Retries Limit +thing-type.config.knx.ip.readRetriesLimit.description = Limits the read retries while initialization from the KNX bus +thing-type.config.knx.ip.readingPause.label = Reading Pause +thing-type.config.knx.ip.readingPause.description = Time in milliseconds of how long should be paused between two read requests to the bus during initialization +thing-type.config.knx.ip.responseTimeout.label = Response Timeout +thing-type.config.knx.ip.responseTimeout.description = Seconds to wait for a response from the KNX bus +thing-type.config.knx.ip.type.label = IP Connection Type +thing-type.config.knx.ip.type.description = The ip connection type for connecting to the KNX bus. Could be either TUNNEL or ROUTER +thing-type.config.knx.ip.type.option.TUNNEL = Tunnel +thing-type.config.knx.ip.type.option.ROUTER = Router +thing-type.config.knx.ip.useNAT.label = Use NAT +thing-type.config.knx.ip.useNAT.description = Set to "true" when having network address translation between this server and the gateway +thing-type.config.knx.serial.autoReconnectPeriod.label = Auto Reconnect Period +thing-type.config.knx.serial.autoReconnectPeriod.description = Seconds between connect retries when KNX link has been lost, 0 means never retry +thing-type.config.knx.serial.readRetriesLimit.label = Read Retries Limit +thing-type.config.knx.serial.readRetriesLimit.description = Limits the read retries while initialization from the KNX bus +thing-type.config.knx.serial.readingPause.label = Reading Pause +thing-type.config.knx.serial.readingPause.description = Time in milliseconds of how long should be paused between two read requests to the bus during initialization +thing-type.config.knx.serial.responseTimeout.label = Response Timeout +thing-type.config.knx.serial.responseTimeout.description = Seconds to wait for a response from the KNX bus +thing-type.config.knx.serial.serialPort.label = Serial Port +thing-type.config.knx.serial.serialPort.description = The serial port to use for connecting to the KNX bus + +# channel types + +channel-type.knx.color-control.label = Color Control +channel-type.knx.color-control.description = Control a color item (i.e. the status is not owned by KNX) +channel-type.knx.color.label = Color +channel-type.knx.color.description = A channel to control color information (RGB) +channel-type.knx.contact-control.label = Contact Control +channel-type.knx.contact-control.description = Control a contact item (i.e. the status is not owned by KNX) +channel-type.knx.contact.label = Contact +channel-type.knx.contact.description = A channel to manage a generic Group Addresses with a DPT compatible with Contact Items +channel-type.knx.datetime-control.label = DateTime Control +channel-type.knx.datetime-control.description = Control a date/time item (i.e. the status is not owned by KNX) +channel-type.knx.datetime.label = DateTime +channel-type.knx.datetime.description = A channel to manage a generic Group Addresses with a DPT compatible with DateTime Items +channel-type.knx.dimmer-control.label = Dimmer Control +channel-type.knx.dimmer-control.description = Control a dimmer item via KNX (i.e. the status is not owned by KNX) +channel-type.knx.dimmer.label = Dimmer +channel-type.knx.dimmer.description = A channel to control a dimmer +channel-type.knx.number-control.label = Number Control +channel-type.knx.number-control.description = Control a number item (i.e. the status is not owned by KNX) +channel-type.knx.number.label = Number +channel-type.knx.number.description = A channel to manage a generic Group Addresses with a DPT compatible with Number Items +channel-type.knx.rollershutter-control.label = Rollershutter Control +channel-type.knx.rollershutter-control.description = Control a rollershutter item (i.e. the status is not owned by KNX) +channel-type.knx.rollershutter.label = Rollershutter +channel-type.knx.rollershutter.description = A channel to control a rollershutter +channel-type.knx.string-control.label = String Control +channel-type.knx.string-control.description = Control a string item (i.e. the status is not owned by KNX) +channel-type.knx.string.label = String +channel-type.knx.string.description = A channel to manage a generic Group Addresses with a DPT compatible with String Items +channel-type.knx.switch-control.label = Switch Control +channel-type.knx.switch-control.description = Control a switch item via KNX (i.e. the status is not owned by KNX) +channel-type.knx.switch.label = Switch +channel-type.knx.switch.description = A channel to manage a generic Group Addresses with a DPT compatible with Switch Items + +# channel types config + +channel-type.config.knx.color-control.frequency.label = Frequency +channel-type.config.knx.color-control.frequency.description = Increase/decrease send frequency if color should be handled by the binding (in ms) - set to 0 if the KNX device sends them repeatedly itself +channel-type.config.knx.color-control.hsb.label = Color Value +channel-type.config.knx.color-control.hsb.description = The group address(es) in Group Address Notation for the color value +channel-type.config.knx.color-control.increaseDecrease.label = Address +channel-type.config.knx.color-control.increaseDecrease.description = The group address(es) in Group Address Notation to increase or decrease the color +channel-type.config.knx.color-control.position.label = Address +channel-type.config.knx.color-control.position.description = The group address(es) in Group Address Notation to set the absolute position of the color +channel-type.config.knx.color-control.switch.label = Address +channel-type.config.knx.color-control.switch.description = The group address(es) in Group Address Notation to toggle the color on or off +channel-type.config.knx.color.hsb.label = Color Value +channel-type.config.knx.color.hsb.description = The group address(es) in Group Address Notation for the color value +channel-type.config.knx.color.increaseDecrease.label = Address +channel-type.config.knx.color.increaseDecrease.description = The group address(es) in Group Address Notation to increase or decrease the color +channel-type.config.knx.color.position.label = Address +channel-type.config.knx.color.position.description = The group address(es) in Group Address Notation to set the absolute position of the color +channel-type.config.knx.color.switch.label = Address +channel-type.config.knx.color.switch.description = The group address(es) in Group Address Notation to toggle the color on or off +channel-type.config.knx.dimmer-control.frequency.label = Frequency +channel-type.config.knx.dimmer-control.frequency.description = Increase/decrease send frequency if dimming should be handled by the binding (in ms) - set to 0 if the KNX device sends them repeatedly itself +channel-type.config.knx.dimmer-control.increaseDecrease.label = Address +channel-type.config.knx.dimmer-control.increaseDecrease.description = The group address(es) in Group Address Notation to increase or decrease the dimmer +channel-type.config.knx.dimmer-control.position.label = Address +channel-type.config.knx.dimmer-control.position.description = The group address(es) in Group Address Notation to set the absolute position of the dimmer +channel-type.config.knx.dimmer-control.switch.label = Address +channel-type.config.knx.dimmer-control.switch.description = The group address(es) in Group Address Notation to toggle the dimmer on or off +channel-type.config.knx.dimmer.increaseDecrease.label = Address +channel-type.config.knx.dimmer.increaseDecrease.description = The group address(es) in Group Address Notation to increase or decrease the dimmer +channel-type.config.knx.dimmer.position.label = Address +channel-type.config.knx.dimmer.position.description = The group address(es) in Group Address Notation to set the absolute position of the dimmer +channel-type.config.knx.dimmer.switch.label = Address +channel-type.config.knx.dimmer.switch.description = The group address(es) in Group Address Notation to toggle the dimmer on or off +channel-type.config.knx.rollershutter.position.label = Address +channel-type.config.knx.rollershutter.position.description = The group address(es) in Group Address Notation to set the absolute position of the shutter, in % +channel-type.config.knx.rollershutter.stopMove.label = Address +channel-type.config.knx.rollershutter.stopMove.description = The group address(es) in Group Address Notation to start (MOVE) or STOP shutter movement +channel-type.config.knx.rollershutter.upDown.label = Address +channel-type.config.knx.rollershutter.upDown.description = The group address(es) in Group Address Notation to move the shutter in the DOWN or UP direction +channel-type.config.knx.single.ga.label = Address +channel-type.config.knx.single.ga.description = The group address(es) in Group Address Notation diff --git a/bundles/org.openhab.binding.konnected/src/main/resources/OH-INF/i18n/konnected.properties b/bundles/org.openhab.binding.konnected/src/main/resources/OH-INF/i18n/konnected.properties new file mode 100644 index 0000000000000..76930a2f35b45 --- /dev/null +++ b/bundles/org.openhab.binding.konnected/src/main/resources/OH-INF/i18n/konnected.properties @@ -0,0 +1,100 @@ +# binding + +binding.konnected.name = Konnected Binding +binding.konnected.description = This is the binding for Konnected. + +# thing types + +thing-type.konnected.module.label = The Konnected Alarm Panel +thing-type.konnected.module.description = The Konnected Module +thing-type.konnected.module.channel.Out.label = The out Pin +thing-type.konnected.module.channel.Zone_6.label = Zone 6 +thing-type.konnected.module.channel.Zone_6.description = Zone 6 Sensor + +# thing types config + +thing-type.config.konnected.module.blink.label = Blink +thing-type.config.konnected.module.blink.description = When set to false the Led on the device won't blink during transmission. +thing-type.config.konnected.module.controller_removewifi.label = Factory Reset +thing-type.config.konnected.module.controller_removewifi.description = Resets the module to Factory Conditions. +thing-type.config.konnected.module.controller_sendConfig.label = Update Settings +thing-type.config.konnected.module.controller_sendConfig.description = Manually sends the settings to the module. The binding will send settings on every restart and if there are any configuration changes but this can be used to manually update the settings as needed. +thing-type.config.konnected.module.controller_softreset.label = Soft Reset Module +thing-type.config.konnected.module.controller_softreset.description = Send A Restart Command to the Module. +thing-type.config.konnected.module.discovery.label = Discovery +thing-type.config.konnected.module.discovery.description = If set to false the device will not respond to discovery requests via UPnP. Make sure you have statically assigned an IP address to the module before turning this setting off. See https://help.konnected.io/support/solutions/articles/32000023968-disabling-device-discovery +thing-type.config.konnected.module.group.actions.label = Actions +thing-type.config.konnected.module.request_timeout.label = Request Timeout +thing-type.config.konnected.module.request_timeout.description = The timeout period in seconds for HTTP requests to the Konnected Alarm Panel. The default is 30. Adjusting this setting can help in networks situations with high latency where the binding is erroneously reporting the thing as offline. +thing-type.config.konnected.module.retry_count.label = Retry Count +thing-type.config.konnected.module.retry_count.description = The number of times the binding attempts to send http requests to the Konnected Alarm Panel. Increase this setting if you are experiencing situations where the module is reporting as offline but you can access the website of the Alarm Panel to confirm that the Alarm Panel is Konnected to the Network. This will allow the binding to attempt more retries before it considers the connection a failure and marks the thing as offline. + +# channel types + +channel-type.konnected.actuator.label = Actuator +channel-type.konnected.actuator.description = This zone is an actuator +channel-type.konnected.humidity.label = Humidity +channel-type.konnected.humidity.description = This zone measures humidity +channel-type.konnected.switch.label = Switch +channel-type.konnected.switch.description = This zone is a read only switch type zone +channel-type.konnected.temperature.label = Temperature +channel-type.konnected.temperature.description = This zone measures temperature + +# channel types config + +channel-type.config.konnected.actuator.momentary.label = Momentary +channel-type.config.konnected.actuator.momentary.description = The duration of the pulse in millisecods +channel-type.config.konnected.actuator.onvalue.label = On Value +channel-type.config.konnected.actuator.onvalue.description = The value that will be treated by the binding as an on command. For actuators that activate with a high command set to 1 and actuators that activate with a low value set to 0. +channel-type.config.konnected.actuator.onvalue.option.0 = 0 +channel-type.config.konnected.actuator.onvalue.option.1 = 1 +channel-type.config.konnected.actuator.pause.label = Pause +channel-type.config.konnected.actuator.pause.description = The time between pulses in millisecods +channel-type.config.konnected.actuator.times.label = Times +channel-type.config.konnected.actuator.times.description = is the number of times to repeat or `-1` for an infinitely repeating pulse +channel-type.config.konnected.actuator.zone.label = Zone Number +channel-type.config.konnected.actuator.zone.description = The Zone Number of the channel. +channel-type.config.konnected.actuator.zone.option.1 = 1 +channel-type.config.konnected.actuator.zone.option.2 = 2 +channel-type.config.konnected.actuator.zone.option.3 = 3 +channel-type.config.konnected.actuator.zone.option.4 = 4 +channel-type.config.konnected.actuator.zone.option.5 = 5 +channel-type.config.konnected.actuator.zone.option.6 = 6 +channel-type.config.konnected.actuator.zone.option.7 = Out +channel-type.config.konnected.humidity.zone.label = Zone Number +channel-type.config.konnected.humidity.zone.description = The Zone Number of the channel. +channel-type.config.konnected.humidity.zone.option.1 = 1 +channel-type.config.konnected.humidity.zone.option.2 = 2 +channel-type.config.konnected.humidity.zone.option.3 = 3 +channel-type.config.konnected.humidity.zone.option.4 = 4 +channel-type.config.konnected.humidity.zone.option.5 = 5 +channel-type.config.konnected.humidity.zone.option.6 = 6 +channel-type.config.konnected.humidity.zone.option.7 = Out +channel-type.config.konnected.switch.onvalue.label = On Value +channel-type.config.konnected.switch.onvalue.description = The value that will be treated by the binding as the on value. For sensors that activate with a high value leave at the default of 1 and sensors that activate with a low value set to 0. +channel-type.config.konnected.switch.onvalue.option.0 = 0 +channel-type.config.konnected.switch.onvalue.option.1 = 1 +channel-type.config.konnected.switch.zone.label = Zone Number +channel-type.config.konnected.switch.zone.description = The Zone Number of the channel. +channel-type.config.konnected.switch.zone.option.1 = 1 +channel-type.config.konnected.switch.zone.option.2 = 2 +channel-type.config.konnected.switch.zone.option.3 = 3 +channel-type.config.konnected.switch.zone.option.4 = 4 +channel-type.config.konnected.switch.zone.option.5 = 5 +channel-type.config.konnected.switch.zone.option.6 = 6 +channel-type.config.konnected.switch.zone.option.7 = Out +channel-type.config.konnected.temperature.ds18b20_address.label = DS18b20 Address +channel-type.config.konnected.temperature.ds18b20_address.description = This is the unique address of the sensor on the one wire bus. +channel-type.config.konnected.temperature.pollinterval.label = Poll Interval +channel-type.config.konnected.temperature.pollinterval.description = The interval in minutes to poll the sensor. +channel-type.config.konnected.temperature.tempsensorType.label = DHT22 +channel-type.config.konnected.temperature.tempsensorType.description = Is the sensor a dht22 or a ds18b20? Set to true for dht22 sensor +channel-type.config.konnected.temperature.zone.label = Zone Number +channel-type.config.konnected.temperature.zone.description = The Zone Number of the channel. +channel-type.config.konnected.temperature.zone.option.1 = 1 +channel-type.config.konnected.temperature.zone.option.2 = 2 +channel-type.config.konnected.temperature.zone.option.3 = 3 +channel-type.config.konnected.temperature.zone.option.4 = 4 +channel-type.config.konnected.temperature.zone.option.5 = 5 +channel-type.config.konnected.temperature.zone.option.6 = 6 +channel-type.config.konnected.temperature.zone.option.7 = Out diff --git a/bundles/org.openhab.binding.kostalinverter/src/main/resources/OH-INF/i18n/kostalinverter.properties b/bundles/org.openhab.binding.kostalinverter/src/main/resources/OH-INF/i18n/kostalinverter.properties new file mode 100644 index 0000000000000..38e723592e1e8 --- /dev/null +++ b/bundles/org.openhab.binding.kostalinverter/src/main/resources/OH-INF/i18n/kostalinverter.properties @@ -0,0 +1,338 @@ +# binding + +binding.kostalinverter.name = Kostal Inverter Binding +binding.kostalinverter.description = Extracts informations from a Kostal Inverter + +# thing types + +thing-type.kostalinverter.PIKOIQ100.label = KOSTAL PIKO IQ 10.0 +thing-type.kostalinverter.PIKOIQ100.description = Bindings for the KOSTAL PIKO IQ 10.0 solar inverter +thing-type.kostalinverter.PIKOIQ42.label = KOSTAL PIKO IQ 4.2 +thing-type.kostalinverter.PIKOIQ42.description = Bindings for the KOSTAL PIKO IQ 4.2 solar inverter +thing-type.kostalinverter.PIKOIQ55.label = KOSTAL PIKO IQ 5.5 +thing-type.kostalinverter.PIKOIQ55.description = Bindings for the KOSTAL PIKO IQ 5.5 solar inverter +thing-type.kostalinverter.PIKOIQ70.label = KOSTAL PIKO IQ 7.0 +thing-type.kostalinverter.PIKOIQ70.description = Bindings for the KOSTAL PIKO IQ 7.0 solar inverter +thing-type.kostalinverter.PIKOIQ85.label = KOSTAL PIKO IQ 8.5 +thing-type.kostalinverter.PIKOIQ85.description = Bindings for the KOSTAL PIKO IQ 8.5 solar inverter +thing-type.kostalinverter.PLENTICOREPLUS100WITHBATTERY.label = KOSTAL PLENTICORE Plus 10.0 (with Battery) +thing-type.kostalinverter.PLENTICOREPLUS100WITHBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 10.0 solar inverter (with battery attached on PV string 3) +thing-type.kostalinverter.PLENTICOREPLUS100WITHOUTBATTERY.label = KOSTAL PLENTICORE Plus 10.0 (no Battery) +thing-type.kostalinverter.PLENTICOREPLUS100WITHOUTBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 10.0 solar inverter (no battery attached) +thing-type.kostalinverter.PLENTICOREPLUS42WITHBATTERY.label = KOSTAL PLENTICORE Plus 4.2 (with Battery) +thing-type.kostalinverter.PLENTICOREPLUS42WITHBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 4.2 solar inverter (with battery attached on PV string 3) +thing-type.kostalinverter.PLENTICOREPLUS42WITHOUTBATTERY.label = KOSTAL PLENTICORE Plus 4.2 (no Battery) +thing-type.kostalinverter.PLENTICOREPLUS42WITHOUTBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 4.2 solar inverter (no battery attached) +thing-type.kostalinverter.PLENTICOREPLUS55WITHBATTERY.label = KOSTAL PLENTICORE Plus 5.5 (with Battery) +thing-type.kostalinverter.PLENTICOREPLUS55WITHBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 5.5 solar inverter (with battery attached on PV string 3) +thing-type.kostalinverter.PLENTICOREPLUS55WITHOUTBATTERY.label = KOSTAL PLENTICORE Plus 5.5 (no Battery) +thing-type.kostalinverter.PLENTICOREPLUS55WITHOUTBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 5.5 solar inverter (no battery attached) +thing-type.kostalinverter.PLENTICOREPLUS70WITHBATTERY.label = KOSTAL PLENTICORE Plus 7.0 (with Battery) +thing-type.kostalinverter.PLENTICOREPLUS70WITHBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 7.0 solar inverter (with battery attached on PV string 3) +thing-type.kostalinverter.PLENTICOREPLUS70WITHOUTBATTERY.label = KOSTAL PLENTICORE Plus 7.0 (no Battery) +thing-type.kostalinverter.PLENTICOREPLUS70WITHOUTBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 7.0 solar inverter (no battery attached) +thing-type.kostalinverter.PLENTICOREPLUS85WITHBATTERY.label = KOSTAL PLENTICORE Plus 8.5 (with Battery) +thing-type.kostalinverter.PLENTICOREPLUS85WITHBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 8.5 solar inverter (with battery attached on PV string 3) +thing-type.kostalinverter.PLENTICOREPLUS85WITHOUTBATTERY.label = KOSTAL PLENTICORE Plus 8.5 (no Battery) +thing-type.kostalinverter.PLENTICOREPLUS85WITHOUTBATTERY.description = Bindings for the KOSTAL PIKO PLENTICORE plus 8.5 solar inverter (no battery attached) +thing-type.kostalinverter.kostalinverter.label = Kostal Inverter +thing-type.kostalinverter.kostalinverter.description = Kostal Inverter +thing-type.kostalinverter.piko1020.label = KOSTAL PIKO 10-20 +thing-type.kostalinverter.piko1020.description = Bindings for the KOSTAL PIKO 10-20 + +# thing types config + +thing-type.config.kostalinverter.kostalinverter.password.label = Password +thing-type.config.kostalinverter.kostalinverter.refreshInterval.label = Refresh Interval +thing-type.config.kostalinverter.kostalinverter.refreshInterval.description = States how often a refresh shall occur (in s) +thing-type.config.kostalinverter.kostalinverter.url.label = URL +thing-type.config.kostalinverter.kostalinverter.url.description = URL of the web interface (e.g. http://192.168.0.1) +thing-type.config.kostalinverter.kostalinverter.userName.label = Username +thing-type.config.kostalinverter.kostalpiko1020.hasBattery.label = Inverter Type +thing-type.config.kostalinverter.kostalpiko1020.hasBattery.description = Type of inverter, with/without battery. +thing-type.config.kostalinverter.kostalpiko1020.password.label = Password +thing-type.config.kostalinverter.kostalpiko1020.password.description = The password to the inverter. +thing-type.config.kostalinverter.kostalpiko1020.refreshInterval.label = Refresh Interval +thing-type.config.kostalinverter.kostalpiko1020.refreshInterval.description = Refresh Interval in seconds. +thing-type.config.kostalinverter.kostalpiko1020.url.label = IP Address +thing-type.config.kostalinverter.kostalpiko1020.url.description = IP address of the inverter. +thing-type.config.kostalinverter.kostalpiko1020.username.label = Username +thing-type.config.kostalinverter.kostalpiko1020.username.description = The username to the inverter. +thing-type.config.kostalinverter.plenticorepikoiq.refreshInternalInSeconds.label = Refresh Interval +thing-type.config.kostalinverter.plenticorepikoiq.refreshInternalInSeconds.description = States how often a refresh shall occur (in s) +thing-type.config.kostalinverter.plenticorepikoiq.url.label = IP Address / Hostname +thing-type.config.kostalinverter.plenticorepikoiq.url.description = Enter the IP address or the hostname of the inverter. Note that DNS resolution must work properly to identify the inverter by its name +thing-type.config.kostalinverter.plenticorepikoiq.userPassword.label = Password +thing-type.config.kostalinverter.plenticorepikoiq.userPassword.description = Enter the user password here + +# channel types + +channel-type.kostalinverter.device-local-ac-cos-phi.label = Cos Phi +channel-type.kostalinverter.device-local-ac-cos-phi.description = AC Power Factor +channel-type.kostalinverter.device-local-ac-current-power.label = AC Power +channel-type.kostalinverter.device-local-ac-current-power.description = Current AC power of the inverter +channel-type.kostalinverter.device-local-ac-frequency.label = AC Frequency +channel-type.kostalinverter.device-local-ac-frequency.description = AC Frequency +channel-type.kostalinverter.device-local-ac-phase-1-current-amperage.label = P1 Amperage +channel-type.kostalinverter.device-local-ac-phase-1-current-amperage.description = Amperage of phase 1 +channel-type.kostalinverter.device-local-ac-phase-1-current-power.label = P1 Power +channel-type.kostalinverter.device-local-ac-phase-1-current-power.description = Power of phase 1 +channel-type.kostalinverter.device-local-ac-phase-1-current-voltage.label = P1 Voltage +channel-type.kostalinverter.device-local-ac-phase-1-current-voltage.description = Voltage of phase 1 +channel-type.kostalinverter.device-local-ac-phase-2-current-amperage.label = P2 Amperage +channel-type.kostalinverter.device-local-ac-phase-2-current-amperage.description = Amperage of phase 2 +channel-type.kostalinverter.device-local-ac-phase-2-current-power.label = P2 Power +channel-type.kostalinverter.device-local-ac-phase-2-current-power.description = Power of phase 2 +channel-type.kostalinverter.device-local-ac-phase-2-current-voltage.label = P2 Voltage +channel-type.kostalinverter.device-local-ac-phase-2-current-voltage.description = Voltage of phase 2 +channel-type.kostalinverter.device-local-ac-phase-3-current-amperage.label = P3 Amperage +channel-type.kostalinverter.device-local-ac-phase-3-current-amperage.description = Amperage of phase 3 +channel-type.kostalinverter.device-local-ac-phase-3-current-power.label = P3 Power +channel-type.kostalinverter.device-local-ac-phase-3-current-power.description = Power of phase 3 +channel-type.kostalinverter.device-local-ac-phase-3-current-voltage.label = P3 Voltage +channel-type.kostalinverter.device-local-ac-phase-3-current-voltage.description = Voltage of phase 3 +channel-type.kostalinverter.device-local-akt-home-consumption-bat.label = Home Consumption Bat +channel-type.kostalinverter.device-local-akt-home-consumption-bat.description = Current consumption from battery +channel-type.kostalinverter.device-local-akt-home-consumption-grid.label = Home Consumption Grid +channel-type.kostalinverter.device-local-akt-home-consumption-grid.description = Current consumption from grid +channel-type.kostalinverter.device-local-akt-home-consumption-solar.label = Home Consumption PV +channel-type.kostalinverter.device-local-akt-home-consumption-solar.description = Current consumption from solar panels +channel-type.kostalinverter.device-local-bat-state-of-charge.label = Bat State of Charge +channel-type.kostalinverter.device-local-bat-state-of-charge.description = Current battery charge state +channel-type.kostalinverter.device-local-battery-amperage.label = Battery Amperage +channel-type.kostalinverter.device-local-battery-amperage.description = Current amperage of the battery +channel-type.kostalinverter.device-local-battery-charge-time-from-set.label = Battery Charge Time from Set +channel-type.kostalinverter.device-local-battery-charge-time-from-set.description = Set battery charge time from +channel-type.kostalinverter.device-local-battery-charge-time-to-set.label = Battery Charge Time to Set +channel-type.kostalinverter.device-local-battery-charge-time-to-set.description = Set battery charge time to +channel-type.kostalinverter.device-local-battery-full-charge-capacity.label = Battery Capacity +channel-type.kostalinverter.device-local-battery-full-charge-capacity.description = Capacity of the battery if charged fully +channel-type.kostalinverter.device-local-battery-loading-cycles.label = Battery Loading Cycles +channel-type.kostalinverter.device-local-battery-loading-cycles.description = Amount of loading cycles done by the battery +channel-type.kostalinverter.device-local-battery-power.label = Battery Power +channel-type.kostalinverter.device-local-battery-power.description = Current battery charge +channel-type.kostalinverter.device-local-battery-state-of-charge.label = Battery Charge +channel-type.kostalinverter.device-local-battery-state-of-charge.description = Current battery charge status +channel-type.kostalinverter.device-local-battery-temperature.label = Battery Temperature +channel-type.kostalinverter.device-local-battery-temperature.description = Current battery temperature +channel-type.kostalinverter.device-local-battery-usage-consumption-set.label = Battery Usage Consumption Set +channel-type.kostalinverter.device-local-battery-usage-consumption-set.description = Set battery usage consumption +channel-type.kostalinverter.device-local-battery-usage-consumption.label = Battery Usage Consumption +channel-type.kostalinverter.device-local-battery-usage-consumption.description = Battery usage consumption +channel-type.kostalinverter.device-local-battery-usage-strategy-set.label = Battery Usage Strategy Set +channel-type.kostalinverter.device-local-battery-usage-strategy-set.description = Set battery usage strategy +channel-type.kostalinverter.device-local-battery-voltage.label = Battery Voltage +channel-type.kostalinverter.device-local-battery-voltage.description = Current voltage of the battery +channel-type.kostalinverter.device-local-battery-voltage.label = Battery Voltage +channel-type.kostalinverter.device-local-battery-voltage.description = Current battery voltage +channel-type.kostalinverter.device-local-charge-cycles.label = Charge Cycles +channel-type.kostalinverter.device-local-charge-cycles.description = Total number of charge cycles +channel-type.kostalinverter.device-local-current-dir.label = Current Dir +channel-type.kostalinverter.device-local-current-dir.description = Current direction +channel-type.kostalinverter.device-local-current.label = Current +channel-type.kostalinverter.device-local-current.description = Current +channel-type.kostalinverter.device-local-dc-power-pv.label = DC Power PV +channel-type.kostalinverter.device-local-dc-power-pv.description = Current power from solar panels +channel-type.kostalinverter.device-local-dc-power.label = DC Power +channel-type.kostalinverter.device-local-dc-power.description = Current DC power of the inverter +channel-type.kostalinverter.device-local-dc1-current.label = DC1 Amperage +channel-type.kostalinverter.device-local-dc1-current.description = Current amperage from solar panels, DC1 +channel-type.kostalinverter.device-local-dc1-power.label = DC1 Power +channel-type.kostalinverter.device-local-dc1-power.description = Current power from solar panels, DC1 +channel-type.kostalinverter.device-local-dc1-voltage.label = DC1 Voltage +channel-type.kostalinverter.device-local-dc1-voltage.description = Current voltage from solar panels, DC1 +channel-type.kostalinverter.device-local-dc2-current.label = DC2 Amperage +channel-type.kostalinverter.device-local-dc2-current.description = Current amperage from solar panels, DC2 +channel-type.kostalinverter.device-local-dc2-power.label = DC2 Power +channel-type.kostalinverter.device-local-dc2-power.description = Current power from solar panels, DC2 +channel-type.kostalinverter.device-local-dc2-voltage.label = DC2 Voltage +channel-type.kostalinverter.device-local-dc2-voltage.description = Current voltage from solar panels, DC2 +channel-type.kostalinverter.device-local-dc3-current.label = DC3 Amperage +channel-type.kostalinverter.device-local-dc3-current.description = Current amperage from solar panels, DC3 +channel-type.kostalinverter.device-local-dc3-power.label = DC3 Power +channel-type.kostalinverter.device-local-dc3-power.description = Current power from solar panels, DC3 +channel-type.kostalinverter.device-local-dc3-voltage.label = DC3 Voltage +channel-type.kostalinverter.device-local-dc3-voltage.description = Current voltage from solar panels, DC3 +channel-type.kostalinverter.device-local-external-module-control-set.label = External Module Control Set +channel-type.kostalinverter.device-local-external-module-control-set.description = Set External Module Control +channel-type.kostalinverter.device-local-external-module-control.label = External Module Control +channel-type.kostalinverter.device-local-external-module-control.description = External Module Control +channel-type.kostalinverter.device-local-grid-cos-phi.label = Grid Cos Phi +channel-type.kostalinverter.device-local-grid-cos-phi.description = Current power factor on grid +channel-type.kostalinverter.device-local-grid-current-l1.label = Grid Amperage L1 +channel-type.kostalinverter.device-local-grid-current-l1.description = Current output amperage to the grid, L1 +channel-type.kostalinverter.device-local-grid-current-l2.label = Grid Amperage L2 +channel-type.kostalinverter.device-local-grid-current-l2.description = Current output amperage to the grid, L2 +channel-type.kostalinverter.device-local-grid-current-l3.label = Grid Amperage L3 +channel-type.kostalinverter.device-local-grid-current-l3.description = Current output amperage to the grid, L3 +channel-type.kostalinverter.device-local-grid-freq.label = Grid Freq +channel-type.kostalinverter.device-local-grid-freq.description = Current frequency on grid +channel-type.kostalinverter.device-local-grid-output-power.label = Grid Output Power +channel-type.kostalinverter.device-local-grid-output-power.description = Current output power to the grid +channel-type.kostalinverter.device-local-grid-power-l1.label = Grid Power L1 +channel-type.kostalinverter.device-local-grid-power-l1.description = Current output power to the grid, L1 +channel-type.kostalinverter.device-local-grid-power-l2.label = Grid Power L2 +channel-type.kostalinverter.device-local-grid-power-l2.description = Current output power to the grid, L2 +channel-type.kostalinverter.device-local-grid-power-l3.label = Grid Power L3 +channel-type.kostalinverter.device-local-grid-power-l3.description = Current output power to the grid, L3 +channel-type.kostalinverter.device-local-grid-voltage-l1.label = Grid Voltage L1 +channel-type.kostalinverter.device-local-grid-voltage-l1.description = Current output voltage to the grid, L1 +channel-type.kostalinverter.device-local-grid-voltage-l2.label = Grid Voltage L2 +channel-type.kostalinverter.device-local-grid-voltage-l2.description = Current output voltage to the grid, L2 +channel-type.kostalinverter.device-local-grid-voltage-l3.label = Grid Voltage L3 +channel-type.kostalinverter.device-local-grid-voltage-l3.description = Current output voltage to the grid, L3 +channel-type.kostalinverter.device-local-homeconsumption-from-battery.label = Home Consumption Battery +channel-type.kostalinverter.device-local-homeconsumption-from-battery.description = Current home consumption obtained from the battery +channel-type.kostalinverter.device-local-homeconsumption-from-grid.label = Home Consumption Grid +channel-type.kostalinverter.device-local-homeconsumption-from-grid.description = Current home consumption obtained from the grid +channel-type.kostalinverter.device-local-homeconsumption-from-pv.label = Home Consumption PV +channel-type.kostalinverter.device-local-homeconsumption-from-pv.description = Current home consumption obtained from photovoltaic +channel-type.kostalinverter.device-local-homeconsumption-total.label = Home Consumption +channel-type.kostalinverter.device-local-homeconsumption-total.description = Current total home consumption +channel-type.kostalinverter.device-local-limit-evu-absolute.label = Feed-in Limit +channel-type.kostalinverter.device-local-limit-evu-absolute.description = Permitted feed-in quantity as absolute value as specified by the energy supplier +channel-type.kostalinverter.device-local-limit-evu-relativ.label = Feed-in Limit Relative +channel-type.kostalinverter.device-local-limit-evu-relativ.description = Permitted feed-in quantity as relative value as specified by the energy supplier +channel-type.kostalinverter.device-local-loginterval.label = Loginterval +channel-type.kostalinverter.device-local-loginterval.description = Value for log interval +channel-type.kostalinverter.device-local-max-depth-of-discharge-set.label = Max Depth of Discharge Set +channel-type.kostalinverter.device-local-max-depth-of-discharge-set.description = Set max depth of discharge +channel-type.kostalinverter.device-local-max-depth-of-discharge.label = Max Depth of Discharge +channel-type.kostalinverter.device-local-max-depth-of-discharge.description = Max depth of discharge +channel-type.kostalinverter.device-local-operating-status.label = Operating Status +channel-type.kostalinverter.device-local-operating-status.description = Operating status +channel-type.kostalinverter.device-local-ownconsumption.label = Own Consumption +channel-type.kostalinverter.device-local-ownconsumption.description = Current own consumption +channel-type.kostalinverter.device-local-phase-sel-home-consump-l1.label = Home Consumption L1 +channel-type.kostalinverter.device-local-phase-sel-home-consump-l1.description = Current home consumption, L1 +channel-type.kostalinverter.device-local-phase-sel-home-consump-l2.label = Home Consumption L2 +channel-type.kostalinverter.device-local-phase-sel-home-consump-l2.description = Current home consumption, L2 +channel-type.kostalinverter.device-local-phase-sel-home-consump-l3.label = Home Consumption L3 +channel-type.kostalinverter.device-local-phase-sel-home-consump-l3.description = Current home consumption, L3 +channel-type.kostalinverter.device-local-pvstring-1-amperage.label = PV Str1 Amperage +channel-type.kostalinverter.device-local-pvstring-1-amperage.description = Current amperage of photovoltaic string 1 +channel-type.kostalinverter.device-local-pvstring-1-power.label = PV Str1 Power +channel-type.kostalinverter.device-local-pvstring-1-power.description = Current power of photovoltaic string 1 +channel-type.kostalinverter.device-local-pvstring-1-voltage.label = PV Str1 Voltage +channel-type.kostalinverter.device-local-pvstring-1-voltage.description = Current voltage of photovoltaic string 1 +channel-type.kostalinverter.device-local-pvstring-2-amperage.label = PV Str2 Amperage +channel-type.kostalinverter.device-local-pvstring-2-amperage.description = Current amperage of photovoltaic string 2 +channel-type.kostalinverter.device-local-pvstring-2-power.label = PV Str2 Power +channel-type.kostalinverter.device-local-pvstring-2-power.description = Current power of photovoltaic string 2 +channel-type.kostalinverter.device-local-pvstring-2-voltage.label = PV Str2 Voltage +channel-type.kostalinverter.device-local-pvstring-2-voltage.description = Current voltage of photovoltaic string 2 +channel-type.kostalinverter.device-local-pvstring-3-amperage.label = PV Str3 Amperage +channel-type.kostalinverter.device-local-pvstring-3-amperage.description = Current amperage of photovoltaic string 3 +channel-type.kostalinverter.device-local-pvstring-3-power.label = PV Str3 Power +channel-type.kostalinverter.device-local-pvstring-3-power.description = Current power of photovoltaic string 3 +channel-type.kostalinverter.device-local-pvstring-3-voltage.label = PV Str3 Voltage +channel-type.kostalinverter.device-local-pvstring-3-voltage.description = Current voltage of photovoltaic string 3 +channel-type.kostalinverter.device-local-s0-inpulse-cnt.label = S0 Inpulse Cnt +channel-type.kostalinverter.device-local-s0-inpulse-cnt.description = S0-pulse counter +channel-type.kostalinverter.device-local-self-consumption.label = Self Consumption +channel-type.kostalinverter.device-local-self-consumption.description = Current self consumption +channel-type.kostalinverter.device-local-shadow-management-set.label = Shadow Management Set +channel-type.kostalinverter.device-local-shadow-management-set.description = Set shadow management +channel-type.kostalinverter.device-local-shadow-management.label = Shadow Management +channel-type.kostalinverter.device-local-shadow-management.description = Shadow management +channel-type.kostalinverter.device-local-smart-battery-control-set.label = Smart Battery Control Set +channel-type.kostalinverter.device-local-smart-battery-control-set.description = Set smart battery control +channel-type.kostalinverter.device-local-smart-battery-control.label = Smart Battery Control +channel-type.kostalinverter.device-local-smart-battery-control.description = Smart battery control +channel-type.kostalinverter.device-local-worktime.label = Uptime +channel-type.kostalinverter.device-local-worktime.description = Uptime of the inverter +channel-type.kostalinverter.scb-event-error-count-mc.label = MC Errors +channel-type.kostalinverter.scb-event-error-count-mc.description = Number of errors reported by the main controller +channel-type.kostalinverter.scb-event-error-count-scb.label = SCB Errors +channel-type.kostalinverter.scb-event-error-count-scb.description = Number of errors reported by the smart communication board +channel-type.kostalinverter.scb-event-error-count-sfh.label = SFH Errors +channel-type.kostalinverter.scb-event-error-count-sfh.description = Number of errors reported by the grid interface controller +channel-type.kostalinverter.scb-event-warning-count-scb.label = SCB Warnings +channel-type.kostalinverter.scb-event-warning-count-scb.description = Number of warnings reported by the smart communication board +channel-type.kostalinverter.statistic-autarky-day.label = Autarky Day +channel-type.kostalinverter.statistic-autarky-day.description = Autarky ratio of this day +channel-type.kostalinverter.statistic-autarky-month.label = Autarky Month +channel-type.kostalinverter.statistic-autarky-month.description = Autarky ratio of this month +channel-type.kostalinverter.statistic-autarky-total.label = Autarky Total +channel-type.kostalinverter.statistic-autarky-total.description = Autarky ratio overall +channel-type.kostalinverter.statistic-autarky-year.label = Autarky Year +channel-type.kostalinverter.statistic-autarky-year.description = Autarky ratio of this year +channel-type.kostalinverter.statistic-autonomy-degree-day.label = Autonomy Degree Day +channel-type.kostalinverter.statistic-autonomy-degree-day.description = Total autonomy degree day +channel-type.kostalinverter.statistic-autonomy-degree-total.label = Autonomy Degree Total +channel-type.kostalinverter.statistic-autonomy-degree-total.description = Total autonomy degree +channel-type.kostalinverter.statistic-co2saving-day.label = CO2 Savings Day +channel-type.kostalinverter.statistic-co2saving-day.description = Savings in Co2 emissions today +channel-type.kostalinverter.statistic-co2saving-month.label = CO2 Savings Month +channel-type.kostalinverter.statistic-co2saving-month.description = Savings in Co2 emissions this month +channel-type.kostalinverter.statistic-co2saving-total.label = CO2 Savings Total +channel-type.kostalinverter.statistic-co2saving-total.description = Savings in Co2 emissions overall +channel-type.kostalinverter.statistic-co2saving-year.label = CO2 Savings Year +channel-type.kostalinverter.statistic-co2saving-year.description = Savings in Co2 emissions this year +channel-type.kostalinverter.statistic-home-consumption-day.label = Home Consumption Day +channel-type.kostalinverter.statistic-home-consumption-day.description = Total home consumption day +channel-type.kostalinverter.statistic-home-consumption-total.label = Home Consumption Total +channel-type.kostalinverter.statistic-home-consumption-total.description = Total home consumption +channel-type.kostalinverter.statistic-homeconsumption-day.label = Home Consumption Day +channel-type.kostalinverter.statistic-homeconsumption-day.description = Home consumption today +channel-type.kostalinverter.statistic-homeconsumption-from-battery-day.label = Home Consumption Battery Day +channel-type.kostalinverter.statistic-homeconsumption-from-battery-day.description = Home consumption obtained from the battery today +channel-type.kostalinverter.statistic-homeconsumption-from-battery-month.label = Home Consumption Battery Month +channel-type.kostalinverter.statistic-homeconsumption-from-battery-month.description = Home consumption obtained from the battery this month +channel-type.kostalinverter.statistic-homeconsumption-from-battery-total.label = Home Consumption Battery Total +channel-type.kostalinverter.statistic-homeconsumption-from-battery-total.description = Home consumption obtained from the battery overall +channel-type.kostalinverter.statistic-homeconsumption-from-battery-year.label = Home Consumption Battery Year +channel-type.kostalinverter.statistic-homeconsumption-from-battery-year.description = Home consumption obtained from the battery this year +channel-type.kostalinverter.statistic-homeconsumption-from-grid-day.label = Home Consumption Grid Day +channel-type.kostalinverter.statistic-homeconsumption-from-grid-day.description = Home consumption obtained from the grid today +channel-type.kostalinverter.statistic-homeconsumption-from-grid-month.label = Home Consumption Grid Month +channel-type.kostalinverter.statistic-homeconsumption-from-grid-month.description = Home consumption obtained from the grid this month +channel-type.kostalinverter.statistic-homeconsumption-from-grid-total.label = Home Consumption Grid Total +channel-type.kostalinverter.statistic-homeconsumption-from-grid-total.description = Home consumption obtained from the grid overall +channel-type.kostalinverter.statistic-homeconsumption-from-grid-year.label = Home Consumption Grid Year +channel-type.kostalinverter.statistic-homeconsumption-from-grid-year.description = Home consumption obtained from the grid this year +channel-type.kostalinverter.statistic-homeconsumption-from-pv-day.label = Home Consumption PV Day +channel-type.kostalinverter.statistic-homeconsumption-from-pv-day.description = Home consumption obtained from the photovoltaic plant today +channel-type.kostalinverter.statistic-homeconsumption-from-pv-month.label = Home Consumption PV Month +channel-type.kostalinverter.statistic-homeconsumption-from-pv-month.description = Home consumption obtained from the photovoltaic plant this month +channel-type.kostalinverter.statistic-homeconsumption-from-pv-total.label = Home Consumption PV Total +channel-type.kostalinverter.statistic-homeconsumption-from-pv-total.description = Home consumption obtained from the photovoltaic plant overall +channel-type.kostalinverter.statistic-homeconsumption-from-pv-year.label = Home Consumption PV Year +channel-type.kostalinverter.statistic-homeconsumption-from-pv-year.description = Home consumption obtained from the photovoltaic plant this year +channel-type.kostalinverter.statistic-homeconsumption-month.label = Home Consumption Month +channel-type.kostalinverter.statistic-homeconsumption-month.description = Home consumption this month +channel-type.kostalinverter.statistic-homeconsumption-total.label = Home Consumption Total +channel-type.kostalinverter.statistic-homeconsumption-total.description = Home consumption overall +channel-type.kostalinverter.statistic-homeconsumption-year.label = Home Consumption Year +channel-type.kostalinverter.statistic-homeconsumption-year.description = Home consumption this year +channel-type.kostalinverter.statistic-operating-time-total.label = Operating Time Total +channel-type.kostalinverter.statistic-operating-time-total.description = Total operating time +channel-type.kostalinverter.statistic-own-cons-rate-day.label = Own Cons Rate Day +channel-type.kostalinverter.statistic-own-cons-rate-day.description = Total own consumption rate day +channel-type.kostalinverter.statistic-own-cons-rate-total.label = Own Cons Rate Total +channel-type.kostalinverter.statistic-own-cons-rate-total.description = Total own consumption rate +channel-type.kostalinverter.statistic-own-consumption-day.label = Own Consumption Day +channel-type.kostalinverter.statistic-own-consumption-day.description = Total own consumption day +channel-type.kostalinverter.statistic-own-consumption-total.label = Own Consumption Total +channel-type.kostalinverter.statistic-own-consumption-total.description = Total own consumptionl +channel-type.kostalinverter.statistic-ownconsumption-rate-day.label = Own Consumption Day +channel-type.kostalinverter.statistic-ownconsumption-rate-day.description = Percentage of electricity demand covered by photovoltaics today +channel-type.kostalinverter.statistic-ownconsumption-rate-month.label = Own Consumption Month +channel-type.kostalinverter.statistic-ownconsumption-rate-month.description = Percentage of electricity demand covered by photovoltaics this month +channel-type.kostalinverter.statistic-ownconsumption-rate-total.label = Own Consumption Total +channel-type.kostalinverter.statistic-ownconsumption-rate-total.description = Percentage of electricity demand covered by photovoltaics overall +channel-type.kostalinverter.statistic-ownconsumption-rate-year.label = Own Consumption Year +channel-type.kostalinverter.statistic-ownconsumption-rate-year.description = Percentage of electricity demand covered by photovoltaics this year +channel-type.kostalinverter.statistic-yield-day-second-gen.label = Yield Day +channel-type.kostalinverter.statistic-yield-day-second-gen.description = Total produced power day +channel-type.kostalinverter.statistic-yield-day.label = Yield Day +channel-type.kostalinverter.statistic-yield-day.description = Yield of the photovoltaic plant today +channel-type.kostalinverter.statistic-yield-month.label = Yield Month +channel-type.kostalinverter.statistic-yield-month.description = Yield of the photovoltaic plant this month +channel-type.kostalinverter.statistic-yield-total-second-gen.label = Yield Total +channel-type.kostalinverter.statistic-yield-total-second-gen.description = Total produced power +channel-type.kostalinverter.statistic-yield-total.label = Yield Total +channel-type.kostalinverter.statistic-yield-total.description = Yield of the photovoltaic plant overall +channel-type.kostalinverter.statistic-yield-year.label = Yield Year +channel-type.kostalinverter.statistic-yield-year.description = Yield of the photovoltaic plant this year +channel-type.kostalinverter.status.label = Status diff --git a/bundles/org.openhab.binding.kvv/src/main/resources/OH-INF/i18n/kvv.properties b/bundles/org.openhab.binding.kvv/src/main/resources/OH-INF/i18n/kvv.properties new file mode 100644 index 0000000000000..524ec04d876b3 --- /dev/null +++ b/bundles/org.openhab.binding.kvv/src/main/resources/OH-INF/i18n/kvv.properties @@ -0,0 +1,36 @@ +# binding + +binding.kvv.name = KVV Binding +binding.kvv.description = This is the binding for KVV. + +# thing types + +thing-type.kvv.bridge.label = KVV Bridge +thing-type.kvv.bridge.description = The KVV bridge connects to the KVV API. +thing-type.kvv.stop.label = KVV Stop +thing-type.kvv.stop.description = Train stop for KVV Binding. + +# thing types config + +thing-type.config.kvv.bridge.apiKey.label = API key +thing-type.config.kvv.bridge.apiKey.description = API key of the KVV API +thing-type.config.kvv.bridge.maxTrains.label = Maximum Trains Listed +thing-type.config.kvv.bridge.maxTrains.description = Maximum number of trains listed. +thing-type.config.kvv.bridge.updateInterval.label = Update Interval +thing-type.config.kvv.bridge.updateInterval.description = Update interval in seconds. +thing-type.config.kvv.stop.stopId.label = Stop ID +thing-type.config.kvv.stop.stopId.description = ID of the train stop. + +# channel group types + +channel-group-type.kvv.train.label = KVV Train +channel-group-type.kvv.train.description = This is a single KVV train + +# channel types + +channel-type.kvv.destination.label = Destination of the train +channel-type.kvv.destination.description = Name of the Train Line +channel-type.kvv.eta.label = Estimated Time Available +channel-type.kvv.eta.description = Time at which the train arrives +channel-type.kvv.name.label = Train Line Name +channel-type.kvv.name.description = Name of the Train Line diff --git a/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties new file mode 100644 index 0000000000000..a9443bbbc8f31 --- /dev/null +++ b/bundles/org.openhab.binding.lcn/src/main/resources/OH-INF/i18n/lcn.properties @@ -0,0 +1,224 @@ +# binding + +binding.lcn.name = LCN Binding +binding.lcn.description = This is the binding for Local Control Network (LCN) + +# thing types + +thing-type.lcn.group.label = LCN Group +thing-type.lcn.group.description = An LCN group with multiple modules, configured in LCN-PRO +thing-type.lcn.module.label = LCN Module +thing-type.lcn.module.description = An LCN bus module, e.g. LCN-UPP, LCN-SH, LCN-HU +thing-type.lcn.pckGateway.label = LCN-PCHK Gateway +thing-type.lcn.pckGateway.description = An LCN gateway speaking the PCK language. E.g. LCN-PCHK software or the DIN rail device LCN-PKE. + +# thing types config + +thing-type.config.lcn.group.groupId.label = Group Number +thing-type.config.lcn.group.groupId.description = The group number, configured in LCN-PRO +thing-type.config.lcn.group.moduleId.label = Module ID +thing-type.config.lcn.group.moduleId.description = The module ID of any module in the group. The state of this module is used for visualization of the group as representative for all modules. +thing-type.config.lcn.group.segmentId.label = Segment ID +thing-type.config.lcn.group.segmentId.description = The segment ID of all modules in this group (0 if no segments are present) +thing-type.config.lcn.module.moduleId.label = Module ID +thing-type.config.lcn.module.moduleId.description = The module ID, configured in LCN-PRO +thing-type.config.lcn.module.segmentId.label = Segment ID +thing-type.config.lcn.module.segmentId.description = The segment ID the module is in (0 if no segments are present) +thing-type.config.lcn.pckGateway.hostname.label = Hostname +thing-type.config.lcn.pckGateway.hostname.description = The hostname or the IP address of the PCK gateway +thing-type.config.lcn.pckGateway.mode.label = Dimming Mode +thing-type.config.lcn.pckGateway.mode.description = ATTENTION: Dimming range of all modules. Must be the same value as configured in LCN-PRO (Options/Settings/Expert Settings). If you only have modules with firmware newer than Feb. 2013, you probably want to choose 0 - 200. +thing-type.config.lcn.pckGateway.mode.option.native50 = 0 - 50 +thing-type.config.lcn.pckGateway.mode.option.native200 = 0 - 200 +thing-type.config.lcn.pckGateway.password.label = Password +thing-type.config.lcn.pckGateway.password.description = The login password of the PCK gateway +thing-type.config.lcn.pckGateway.port.label = Port +thing-type.config.lcn.pckGateway.port.description = The IP port of the PCK gateway +thing-type.config.lcn.pckGateway.timeoutMs.label = Connection Timeout +thing-type.config.lcn.pckGateway.timeoutMs.description = Period after which an LCN command is resent, when no acknowledge has been received (in ms). +thing-type.config.lcn.pckGateway.username.label = Username +thing-type.config.lcn.pckGateway.username.description = The login username of the PCK gateway + +# channel group types + +channel-group-type.lcn.binarysensors.label = Binary Sensors +channel-group-type.lcn.binarysensors.channel.1.label = Binary Sensor 1 +channel-group-type.lcn.binarysensors.channel.2.label = Binary Sensor 2 +channel-group-type.lcn.binarysensors.channel.3.label = Binary Sensor 3 +channel-group-type.lcn.binarysensors.channel.4.label = Binary Sensor 4 +channel-group-type.lcn.binarysensors.channel.5.label = Binary Sensor 5 +channel-group-type.lcn.binarysensors.channel.6.label = Binary Sensor 6 +channel-group-type.lcn.binarysensors.channel.7.label = Binary Sensor 7 +channel-group-type.lcn.binarysensors.channel.8.label = Binary Sensor 8 +channel-group-type.lcn.codes.label = Access Control +channel-group-type.lcn.hostcommands.label = Host Commands +channel-group-type.lcn.hostcommands.description = Command from LCN to openHAB +channel-group-type.lcn.keyslocktablea.label = Keys Locks Table A +channel-group-type.lcn.keyslocktablea.channel.1.label = Key 1 +channel-group-type.lcn.keyslocktablea.channel.2.label = Key 2 +channel-group-type.lcn.keyslocktablea.channel.3.label = Key 3 +channel-group-type.lcn.keyslocktablea.channel.4.label = Key 4 +channel-group-type.lcn.keyslocktablea.channel.5.label = Key 5 +channel-group-type.lcn.keyslocktablea.channel.6.label = Key 6 +channel-group-type.lcn.keyslocktablea.channel.7.label = Key 7 +channel-group-type.lcn.keyslocktablea.channel.8.label = Key 8 +channel-group-type.lcn.keyslocktableb.label = Keys Locks Table B +channel-group-type.lcn.keyslocktableb.channel.1.label = Key 1 +channel-group-type.lcn.keyslocktableb.channel.2.label = Key 2 +channel-group-type.lcn.keyslocktableb.channel.3.label = Key 3 +channel-group-type.lcn.keyslocktableb.channel.4.label = Key 4 +channel-group-type.lcn.keyslocktableb.channel.5.label = Key 5 +channel-group-type.lcn.keyslocktableb.channel.6.label = Key 6 +channel-group-type.lcn.keyslocktableb.channel.7.label = Key 7 +channel-group-type.lcn.keyslocktableb.channel.8.label = Key 8 +channel-group-type.lcn.keyslocktablec.label = Keys Locks Table C +channel-group-type.lcn.keyslocktablec.channel.1.label = Key 1 +channel-group-type.lcn.keyslocktablec.channel.2.label = Key 2 +channel-group-type.lcn.keyslocktablec.channel.3.label = Key 3 +channel-group-type.lcn.keyslocktablec.channel.4.label = Key 4 +channel-group-type.lcn.keyslocktablec.channel.5.label = Key 5 +channel-group-type.lcn.keyslocktablec.channel.6.label = Key 6 +channel-group-type.lcn.keyslocktablec.channel.7.label = Key 7 +channel-group-type.lcn.keyslocktablec.channel.8.label = Key 8 +channel-group-type.lcn.keyslocktabled.label = Keys Locks Table D +channel-group-type.lcn.keyslocktabled.channel.1.label = Key 1 +channel-group-type.lcn.keyslocktabled.channel.2.label = Key 2 +channel-group-type.lcn.keyslocktabled.channel.3.label = Key 3 +channel-group-type.lcn.keyslocktabled.channel.4.label = Key 4 +channel-group-type.lcn.keyslocktabled.channel.5.label = Key 5 +channel-group-type.lcn.keyslocktabled.channel.6.label = Key 6 +channel-group-type.lcn.keyslocktabled.channel.7.label = Key 7 +channel-group-type.lcn.keyslocktabled.channel.8.label = Key 8 +channel-group-type.lcn.leds.label = LEDs +channel-group-type.lcn.leds.channel.1.label = LED 1 +channel-group-type.lcn.leds.channel.10.label = LED 10 +channel-group-type.lcn.leds.channel.11.label = LED 11 +channel-group-type.lcn.leds.channel.12.label = LED 12 +channel-group-type.lcn.leds.channel.2.label = LED 2 +channel-group-type.lcn.leds.channel.3.label = LED 3 +channel-group-type.lcn.leds.channel.4.label = LED 4 +channel-group-type.lcn.leds.channel.5.label = LED 5 +channel-group-type.lcn.leds.channel.6.label = LED 6 +channel-group-type.lcn.leds.channel.7.label = LED 7 +channel-group-type.lcn.leds.channel.8.label = LED 8 +channel-group-type.lcn.leds.channel.9.label = LED 9 +channel-group-type.lcn.logics.label = Logic Operations +channel-group-type.lcn.logics.channel.1.label = Logic Operation 1 +channel-group-type.lcn.logics.channel.2.label = Logic Operation 2 +channel-group-type.lcn.logics.channel.3.label = Logic Operation 3 +channel-group-type.lcn.logics.channel.4.label = Logic Operation 4 +channel-group-type.lcn.outputs.label = Dimmer Outputs +channel-group-type.lcn.outputs.channel.1.label = Output 1 +channel-group-type.lcn.outputs.channel.2.label = Output 2 +channel-group-type.lcn.outputs.channel.3.label = Output 3 +channel-group-type.lcn.outputs.channel.4.label = Output 4 +channel-group-type.lcn.outputs.channel.color.label = RGB Color Control (Outputs 1-3) +channel-group-type.lcn.relays.label = Relays +channel-group-type.lcn.relays.channel.1.label = Relay 1 +channel-group-type.lcn.relays.channel.2.label = Relay 2 +channel-group-type.lcn.relays.channel.3.label = Relay 3 +channel-group-type.lcn.relays.channel.4.label = Relay 4 +channel-group-type.lcn.relays.channel.5.label = Relay 5 +channel-group-type.lcn.relays.channel.6.label = Relay 6 +channel-group-type.lcn.relays.channel.7.label = Relay 7 +channel-group-type.lcn.relays.channel.8.label = Relay 8 +channel-group-type.lcn.rollershutteroutputs.label = Roller Shutter (Dimmer) +channel-group-type.lcn.rollershutteroutputs.channel.1.label = Shutter 1-2 +channel-group-type.lcn.rollershutterrelays.label = Roller Shutter (Relay) +channel-group-type.lcn.rollershutterrelays.channel.1.label = Shutter 1-2 +channel-group-type.lcn.rollershutterrelays.channel.2.label = Shutter 3-4 +channel-group-type.lcn.rollershutterrelays.channel.3.label = Shutter 5-6 +channel-group-type.lcn.rollershutterrelays.channel.4.label = Shutter 7-8 +channel-group-type.lcn.rvarlocks.label = RVar Lock State +channel-group-type.lcn.rvarlocks.channel.1.label = R1Var Lock +channel-group-type.lcn.rvarlocks.channel.2.label = R2Var Lock +channel-group-type.lcn.rvarsetpoints.label = RVar Setpoints +channel-group-type.lcn.rvarsetpoints.channel.1.label = R1Var Setpoint +channel-group-type.lcn.rvarsetpoints.channel.2.label = R2Var Setpoint +channel-group-type.lcn.s0inputs.label = S0 Counters +channel-group-type.lcn.s0inputs.channel.1.label = S0 Counter 1 +channel-group-type.lcn.s0inputs.channel.2.label = S0 Counter 2 +channel-group-type.lcn.s0inputs.channel.3.label = S0 Counter 3 +channel-group-type.lcn.s0inputs.channel.4.label = S0 Counter 4 +channel-group-type.lcn.thresholdregisters1.label = Threshold Register 1 +channel-group-type.lcn.thresholdregisters1.channel.1.label = Threshold 1 +channel-group-type.lcn.thresholdregisters1.channel.2.label = Threshold 2 +channel-group-type.lcn.thresholdregisters1.channel.3.label = Threshold 3 +channel-group-type.lcn.thresholdregisters1.channel.4.label = Threshold 4 +channel-group-type.lcn.thresholdregisters1.channel.5.label = Threshold 5 +channel-group-type.lcn.thresholdregisters1.channel.5.description = Only before Feb. 2013 +channel-group-type.lcn.thresholdregisters2.label = Threshold Register 2 +channel-group-type.lcn.thresholdregisters2.channel.1.label = Threshold 1 +channel-group-type.lcn.thresholdregisters2.channel.2.label = Threshold 2 +channel-group-type.lcn.thresholdregisters2.channel.3.label = Threshold 3 +channel-group-type.lcn.thresholdregisters2.channel.4.label = Threshold 4 +channel-group-type.lcn.thresholdregisters3.label = Threshold Register 3 +channel-group-type.lcn.thresholdregisters3.channel.1.label = Threshold 1 +channel-group-type.lcn.thresholdregisters3.channel.2.label = Threshold 2 +channel-group-type.lcn.thresholdregisters3.channel.3.label = Threshold 3 +channel-group-type.lcn.thresholdregisters3.channel.4.label = Threshold 4 +channel-group-type.lcn.thresholdregisters4.label = Threshold Register 4 +channel-group-type.lcn.thresholdregisters4.channel.1.label = Threshold 1 +channel-group-type.lcn.thresholdregisters4.channel.2.label = Threshold 2 +channel-group-type.lcn.thresholdregisters4.channel.3.label = Threshold 3 +channel-group-type.lcn.thresholdregisters4.channel.4.label = Threshold 4 +channel-group-type.lcn.variables.label = Variables +channel-group-type.lcn.variables.channel.1.label = Variable 1 or TVar +channel-group-type.lcn.variables.channel.10.label = Variable 10 +channel-group-type.lcn.variables.channel.11.label = Variable 11 +channel-group-type.lcn.variables.channel.12.label = Variable 12 +channel-group-type.lcn.variables.channel.2.label = Variable 2 +channel-group-type.lcn.variables.channel.3.label = Variable 3 +channel-group-type.lcn.variables.channel.4.label = Variable 4 +channel-group-type.lcn.variables.channel.5.label = Variable 5 +channel-group-type.lcn.variables.channel.6.label = Variable 6 +channel-group-type.lcn.variables.channel.7.label = Variable 7 +channel-group-type.lcn.variables.channel.8.label = Variable 8 +channel-group-type.lcn.variables.channel.9.label = Variable 9 + +# channel types + +channel-type.lcn.binarysensor.label = Binary Sensor +channel-type.lcn.color.label = Color +channel-type.lcn.fingerprints.label = Fingerprint Codes +channel-type.lcn.keylock.label = Keys Lock State +channel-type.lcn.led.label = LED +channel-type.lcn.led.state.option.OFF = Off +channel-type.lcn.led.state.option.ON = On +channel-type.lcn.led.state.option.BLINK = Blink +channel-type.lcn.led.state.option.FLICKER = Flicker +channel-type.lcn.logic.label = Logic Operation +channel-type.lcn.logic.state.option.NOT = Not (not fulfilled) +channel-type.lcn.logic.state.option.OR = Or (partly fulfilled) +channel-type.lcn.logic.state.option.AND = And (fulfilled) +channel-type.lcn.output.label = Output +channel-type.lcn.relay.label = Relay +channel-type.lcn.remotecontrolcodes.label = Remote Control (Codes) +channel-type.lcn.remotecontrolkeys.label = Remote Control (Keys) +channel-type.lcn.remotecontrolsbatterylow.label = Low Battery +channel-type.lcn.rollershutter.label = Roller Shutter +channel-type.lcn.rvarlock.label = RVar Lock State +channel-type.lcn.sendKeys.label = Send Keys +channel-type.lcn.transponders.label = Transponder Codes +channel-type.lcn.variable.label = Variable + +# channel types config + +channel-type.config.lcn.binarysensor.invertState.label = Invert State +channel-type.config.lcn.binarysensor.invertState.description = Per default a binary sensor state 0 corresponds to "closed" while 1 corresponds to "open". Use this parameter to invert that logic. +channel-type.config.lcn.rollershutter.invertUpDown.label = Invert Up/Down +channel-type.config.lcn.rollershutter.invertUpDown.description = According LCN spec., the Up wire is connected to the "normally open" contact/Output 1. Use this parameter to invert that logic. +channel-type.config.lcn.variable.parameter.label = Pulses per kWh +channel-type.config.lcn.variable.parameter.description = Only for S0 counters (power or energy) +channel-type.config.lcn.variable.unit.label = Unit +channel-type.config.lcn.variable.unit.description = Unit of the sensor +channel-type.config.lcn.variable.unit.option.native = LCN Native +channel-type.config.lcn.variable.unit.option.temperature = Temperature (°C or °F) +channel-type.config.lcn.variable.unit.option.light = Light (Lux) +channel-type.config.lcn.variable.unit.option.co2 = CO₂ (ppm) +channel-type.config.lcn.variable.unit.option.power = Power (W) +channel-type.config.lcn.variable.unit.option.energy = Energy (kWh) +channel-type.config.lcn.variable.unit.option.current = Current (mA) +channel-type.config.lcn.variable.unit.option.voltage = Voltage (V) +channel-type.config.lcn.variable.unit.option.angle = Angle (°) +channel-type.config.lcn.variable.unit.option.windspeed = Windspeed (m/s) diff --git a/bundles/org.openhab.binding.leapmotion/src/main/resources/OH-INF/i18n/leapmotion.properties b/bundles/org.openhab.binding.leapmotion/src/main/resources/OH-INF/i18n/leapmotion.properties new file mode 100644 index 0000000000000..a7c86db7241b0 --- /dev/null +++ b/bundles/org.openhab.binding.leapmotion/src/main/resources/OH-INF/i18n/leapmotion.properties @@ -0,0 +1,14 @@ +# binding + +binding.leapmotion.name = Leap Motion Binding +binding.leapmotion.description = This is the binding for Leap Motion controllers. + +# thing types + +thing-type.leapmotion.controller.label = Leap Motion Controller +thing-type.leapmotion.controller.description = A Leap Motion Gesture Sensor + +# channel types + +channel-type.leapmotion.gesture.label = Gestures +channel-type.leapmotion.gesture.description = Provides recognized gestures from the controller diff --git a/bundles/org.openhab.binding.lgtvserial/src/main/resources/OH-INF/i18n/lgtvserial.properties b/bundles/org.openhab.binding.lgtvserial/src/main/resources/OH-INF/i18n/lgtvserial.properties new file mode 100644 index 0000000000000..317fc7d3fb10e --- /dev/null +++ b/bundles/org.openhab.binding.lgtvserial/src/main/resources/OH-INF/i18n/lgtvserial.properties @@ -0,0 +1,563 @@ +# binding + +binding.lgtvserial.name = LG TV Serial Binding +binding.lgtvserial.description = Controlling LG TVs using serial (RS232C) protocol + +# thing types + +thing-type.lgtvserial.lgtv-LK-series.label = LK Series +thing-type.lgtvserial.lgtv-LK-series.description = This thing supports the LCD TV models LK +thing-type.lgtvserial.lgtv-LV-series.label = LV/LW Series +thing-type.lgtvserial.lgtv-LV-series.description = This thing supports the LED LCD TV models LV and LW except *LV255C, *LV355B, *LV355C models +thing-type.lgtvserial.lgtv-LVx55-series.label = LV/LW Series +thing-type.lgtvserial.lgtv-LVx55-series.description = This thing supports the *LV255C, *LV355B, *LV355C models. +thing-type.lgtvserial.lgtv-M6503C.label = M6503C Model +thing-type.lgtvserial.lgtv-M6503C.description = This thing supports the M6503C LG TV +thing-type.lgtvserial.lgtv-PW-series.label = PW Series +thing-type.lgtvserial.lgtv-PW-series.description = This thing supports the PLASMA TV models PW +thing-type.lgtvserial.lgtv.label = Generic LG TV +thing-type.lgtvserial.lgtv.description = Generic LG television connected through a serial interface. This thing should be used only when there is no proper thing defined for your TV model as it has most existing channels for most known commands. + +# thing types config + +thing-type.config.lgtvserial.serial.port.label = Serial Port +thing-type.config.lgtvserial.serial.port.description = Select serial port (COM1, /dev/ttyS0, ...) +thing-type.config.lgtvserial.serial.setId.label = Set ID +thing-type.config.lgtvserial.serial.setId.description = Set ID configured in the TV. If 0, this will send a command to every chained TV. + +# channel types + +channel-type.lgtvserial.3d-extended.label = 3d Extended +channel-type.lgtvserial.3d-extended.description = Change the 3d option, if your TV supports it +channel-type.lgtvserial.3d.label = 3d +channel-type.lgtvserial.3d.description = Change the 3d mode, if your TV supports it +channel-type.lgtvserial.aspect-ratio-M6503C.label = Aspect Ratio +channel-type.lgtvserial.aspect-ratio-M6503C.description = Adjust the screen format +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.01 = Normal Screen (4:3) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.02 = Wide Screen (16:9) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.04 = Zoom1 (AV) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.05 = Zoom2 (AV) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.06 = Original (AV) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.07 = 14:9 (AV) +channel-type.lgtvserial.aspect-ratio-M6503C.state.option.09 = Just scan(HD DTV), 1:1 (RGB PC, HDMI/DVI PC) +channel-type.lgtvserial.aspect-ratio-SAC34134216.label = Aspect Ratio +channel-type.lgtvserial.aspect-ratio-SAC34134216.description = Adjust the screen format +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.01 = 4:3 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.02 = 16:9 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.04 = Zoom +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.06 = Set by program +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.09 = Just scan +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.10 = Cinema Zoom 1 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.11 = Cinema Zoom 2 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.12 = Cinema Zoom 3 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.13 = Cinema Zoom 4 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.14 = Cinema Zoom 5 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.15 = Cinema Zoom 6 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.16 = Cinema Zoom 7 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.17 = Cinema Zoom 8 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.18 = Cinema Zoom 9 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.19 = Cinema Zoom 10 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1A = Cinema Zoom 11 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1B = Cinema Zoom 12 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1C = Cinema Zoom 13 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1D = Cinema Zoom 14 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1E = Cinema Zoom 15 +channel-type.lgtvserial.aspect-ratio-SAC34134216.state.option.1F = Cinema Zoom 16 +channel-type.lgtvserial.aspect-ratio.label = Aspect Ratio +channel-type.lgtvserial.aspect-ratio.description = Adjust the screen format +channel-type.lgtvserial.aspect-ratio.state.option.01 = 4:3 +channel-type.lgtvserial.aspect-ratio.state.option.02 = 16:9 +channel-type.lgtvserial.aspect-ratio.state.option.04 = Zoom +channel-type.lgtvserial.aspect-ratio.state.option.06 = Set by program +channel-type.lgtvserial.aspect-ratio.state.option.09 = Just scan +channel-type.lgtvserial.aspect-ratio.state.option.10 = Cinema Zoom 1 +channel-type.lgtvserial.aspect-ratio.state.option.11 = Cinema Zoom 2 +channel-type.lgtvserial.aspect-ratio.state.option.12 = Cinema Zoom 3 +channel-type.lgtvserial.aspect-ratio.state.option.13 = Cinema Zoom 4 +channel-type.lgtvserial.aspect-ratio.state.option.14 = Cinema Zoom 5 +channel-type.lgtvserial.aspect-ratio.state.option.15 = Cinema Zoom 6 +channel-type.lgtvserial.aspect-ratio.state.option.16 = Cinema Zoom 7 +channel-type.lgtvserial.aspect-ratio.state.option.17 = Cinema Zoom 8 +channel-type.lgtvserial.aspect-ratio.state.option.18 = Cinema Zoom 9 +channel-type.lgtvserial.aspect-ratio.state.option.19 = Cinema Zoom 10 +channel-type.lgtvserial.aspect-ratio.state.option.1A = Cinema Zoom 11 +channel-type.lgtvserial.aspect-ratio.state.option.1B = Cinema Zoom 12 +channel-type.lgtvserial.aspect-ratio.state.option.1C = Cinema Zoom 13 +channel-type.lgtvserial.aspect-ratio.state.option.1D = Cinema Zoom 14 +channel-type.lgtvserial.aspect-ratio.state.option.1E = Cinema Zoom 15 +channel-type.lgtvserial.aspect-ratio.state.option.1F = Cinema Zoom 16 +channel-type.lgtvserial.auto-sleep.label = Auto Sleep +channel-type.lgtvserial.auto-sleep.description = Set Auto Sleep +channel-type.lgtvserial.auto-volume.label = Auto Volume +channel-type.lgtvserial.auto-volume.description = Automatically adjust the volume level +channel-type.lgtvserial.backlight.label = Backlight +channel-type.lgtvserial.backlight.description = Display backlight brightness +channel-type.lgtvserial.balance.label = Balance +channel-type.lgtvserial.balance.description = Adjust balance +channel-type.lgtvserial.bass.label = Bass +channel-type.lgtvserial.bass.description = Adjust bass +channel-type.lgtvserial.brightness.label = Brightness +channel-type.lgtvserial.brightness.description = Adjust screen brightness +channel-type.lgtvserial.color-temperature.label = Color Temperature +channel-type.lgtvserial.color-temperature.description = Color temperature of the display +channel-type.lgtvserial.color-temperature.state.option.0 = Cool +channel-type.lgtvserial.color-temperature.state.option.1 = Normal +channel-type.lgtvserial.color-temperature.state.option.2 = Warm +channel-type.lgtvserial.color-temperature2.label = Color Temperature +channel-type.lgtvserial.color-temperature2.description = Color temperature of the display (between 0 and 100) +channel-type.lgtvserial.color.label = Color +channel-type.lgtvserial.color.description = Adjust screen color +channel-type.lgtvserial.contrast.label = Contrast +channel-type.lgtvserial.contrast.description = Contrast +channel-type.lgtvserial.dpm.label = DPM Select +channel-type.lgtvserial.dpm.description = Set the DPM (Display Power Management) function +channel-type.lgtvserial.elapsed-time.label = Elapsed Time +channel-type.lgtvserial.elapsed-time.description = Read the elapsed time +channel-type.lgtvserial.energy-saving.label = Energy Saving +channel-type.lgtvserial.energy-saving.description = Control the energy saving function +channel-type.lgtvserial.energy-saving.state.option.00 = Off +channel-type.lgtvserial.energy-saving.state.option.01 = Minimum +channel-type.lgtvserial.energy-saving.state.option.02 = Medium +channel-type.lgtvserial.energy-saving.state.option.03 = Maximum +channel-type.lgtvserial.energy-saving.state.option.04 = Auto/Intelligent sensor (depending on model) +channel-type.lgtvserial.energy-saving.state.option.05 = Screen off +channel-type.lgtvserial.fan-fault-check.label = Fan Fault +channel-type.lgtvserial.fan-fault-check.description = Check the fan fault of the TV +channel-type.lgtvserial.fan-fault-check.state.option.0 = Fan fault +channel-type.lgtvserial.fan-fault-check.state.option.1 = Fan OK +channel-type.lgtvserial.fan-fault-check.state.option.2 = N/A(Not Available) +channel-type.lgtvserial.h-position.label = H Position +channel-type.lgtvserial.h-position.description = Set the horizontal position +channel-type.lgtvserial.input-M6503C.label = Input +channel-type.lgtvserial.input-M6503C.description = Input select +channel-type.lgtvserial.input-M6503C.state.option.02 = AV +channel-type.lgtvserial.input-M6503C.state.option.04 = Component +channel-type.lgtvserial.input-M6503C.state.option.07 = RGB (PC) +channel-type.lgtvserial.input-M6503C.state.option.08 = HDMI (DTV) +channel-type.lgtvserial.input-M6503C.state.option.09 = HDMI (PC) +channel-type.lgtvserial.input-SAC34134216.label = Input +channel-type.lgtvserial.input-SAC34134216.description = Input select +channel-type.lgtvserial.input-SAC34134216.state.option.00 = DTV (Antenna) +channel-type.lgtvserial.input-SAC34134216.state.option.01 = DTV (cable) +channel-type.lgtvserial.input-SAC34134216.state.option.10 = Analog (Antenna) +channel-type.lgtvserial.input-SAC34134216.state.option.11 = Analog (Cable) +channel-type.lgtvserial.input-SAC34134216.state.option.20 = AV or AV1 +channel-type.lgtvserial.input-SAC34134216.state.option.21 = AV2 +channel-type.lgtvserial.input-SAC34134216.state.option.40 = Component or Component1 +channel-type.lgtvserial.input-SAC34134216.state.option.41 = Component2 +channel-type.lgtvserial.input-SAC34134216.state.option.60 = RGB-PC +channel-type.lgtvserial.input-SAC34134216.state.option.90 = HDMI1 +channel-type.lgtvserial.input-SAC34134216.state.option.91 = HDMI2 +channel-type.lgtvserial.input-SAC34134216.state.option.92 = HDMI3 +channel-type.lgtvserial.input-SAC34134216.state.option.93 = HDMI4 +channel-type.lgtvserial.input.label = Input +channel-type.lgtvserial.input.description = Input select +channel-type.lgtvserial.input.state.option.00 = DTV (Antenna) +channel-type.lgtvserial.input.state.option.01 = DTV (cable) +channel-type.lgtvserial.input.state.option.02 = AV +channel-type.lgtvserial.input.state.option.04 = Component +channel-type.lgtvserial.input.state.option.07 = RGB (PC) +channel-type.lgtvserial.input.state.option.08 = HDMI (DTV) +channel-type.lgtvserial.input.state.option.09 = HDMI (PC) +channel-type.lgtvserial.input.state.option.10 = Analog (Antenna) +channel-type.lgtvserial.input.state.option.11 = Analog (Cable) +channel-type.lgtvserial.input.state.option.20 = AV or AV1 +channel-type.lgtvserial.input.state.option.21 = AV2 +channel-type.lgtvserial.input.state.option.40 = Component or Component1 +channel-type.lgtvserial.input.state.option.41 = Component2 +channel-type.lgtvserial.input.state.option.60 = RGB-PC +channel-type.lgtvserial.input.state.option.90 = HDMI1 +channel-type.lgtvserial.input.state.option.91 = HDMI2 +channel-type.lgtvserial.input.state.option.92 = HDMI3 +channel-type.lgtvserial.input.state.option.93 = HDMI4 +channel-type.lgtvserial.input2-M6503C.label = Input +channel-type.lgtvserial.input2-M6503C.description = Input select +channel-type.lgtvserial.input2-M6503C.state.option.20 = AV +channel-type.lgtvserial.input2-M6503C.state.option.40 = Component +channel-type.lgtvserial.input2-M6503C.state.option.60 = RGB (PC) +channel-type.lgtvserial.input2-M6503C.state.option.90 = HDMI (DTV) +channel-type.lgtvserial.input2-M6503C.state.option.A0 = HDMI (PC) +channel-type.lgtvserial.ir-key-code-M6503C.label = IR Code +channel-type.lgtvserial.ir-key-code-M6503C.description = Send IR remote key code +channel-type.lgtvserial.ir-key-code-M6503C.state.option.00 = Channel up +channel-type.lgtvserial.ir-key-code-M6503C.state.option.01 = Channel down +channel-type.lgtvserial.ir-key-code-M6503C.state.option.02 = Volume up +channel-type.lgtvserial.ir-key-code-M6503C.state.option.03 = Volume down +channel-type.lgtvserial.ir-key-code-M6503C.state.option.08 = Power toggle +channel-type.lgtvserial.ir-key-code-M6503C.state.option.09 = Mute +channel-type.lgtvserial.ir-key-code-M6503C.state.option.0B = Input +channel-type.lgtvserial.ir-key-code-M6503C.state.option.0E = Sleep +channel-type.lgtvserial.ir-key-code-M6503C.state.option.10 = Number 0 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.11 = Number 1 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.12 = Number 2 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.13 = Number 3 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.14 = Number 4 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.15 = Number 5 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.16 = Number 6 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.17 = Number 7 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.18 = Number 8 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.19 = Number 9 +channel-type.lgtvserial.ir-key-code-M6503C.state.option.43 = Menu +channel-type.lgtvserial.ir-key-code-M6503C.state.option.44 = SET +channel-type.lgtvserial.ir-key-code-M6503C.state.option.5A = AV Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.5B = Exit +channel-type.lgtvserial.ir-key-code-M6503C.state.option.6E = PSM +channel-type.lgtvserial.ir-key-code-M6503C.state.option.76 = ARC (4:3) Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.77 = ARC (16:9) Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.79 = ARC Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.AF = ARC (Zoom) Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.BF = Component Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.C4 = Power on +channel-type.lgtvserial.ir-key-code-M6503C.state.option.C5 = Power off +channel-type.lgtvserial.ir-key-code-M6503C.state.option.C6 = HDMI/DVI Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.D5 = RGB PC Discrete +channel-type.lgtvserial.ir-key-code-M6503C.state.option.98 = AV +channel-type.lgtvserial.ir-key-code-M6503C.state.option.99 = Auto config Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.label = IR Code +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.description = Send IR remote key code +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.08 = Power toggle +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.45 = Q.Menu +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.43 = Home or Menu +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.0B = Input +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.10 = Number 0 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.11 = Number 1 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.12 = Number 2 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.13 = Number 3 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.14 = Number 4 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.15 = Number 5 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.16 = Number 6 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.17 = Number 7 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.18 = Number 8 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.19 = Number 9 +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.4C = - (Dash)/List +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.1A = Flashbk or Q.VIEW +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.09 = Mute/Delete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.02 = Volume up +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.03 = Volume down +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.00 = Channel up +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.01 = Channel down +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.1E = FAV/MARK +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.40 = ˄ Up +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.41 = ˅ Down +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.07 = ˂ Left +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.06 = ˃ Right +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.44 = Enter +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.28 = Back or Return +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.79 = Ratio +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.BA = Freeze +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.95 = Energy saving +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.7E = SIMPLINK +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.AA = Info +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.30 = AV mode +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.B1 = ■ Stop +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.B0 = ▶ Play +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.BA = ⏸ Pause +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.8E = ▶▶ Fast forward +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.8F = ◀◀ Rewind +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C1 = Red +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C0 = Green +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C2 = Yellow +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C3 = Blue +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.0F = TV +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.DC = 3D +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.5B = Exit +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.0C = Portal +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.AB = Guide +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.D6 = TV Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C4 = Power on +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.C5 = Power off +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.5A = AV1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.D0 = AV2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.BF = Component1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.D4 = Component2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.D5 = RGB PC Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.CE = HDMI1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.CC = HDMI2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.E9 = HDMI3 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.DA = HDMI4 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.76 = Ratio 4:3 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.77 = Ratio 16:9 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216-LV255C-LV355B-LV355C.state.option.AF = Ratio Zoom Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.label = IR Code +channel-type.lgtvserial.ir-key-code-SAC34134216.description = Send IR remote key code +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.08 = Power toggle +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.45 = Q.Menu +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.43 = Home or Menu +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.0B = Input +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.10 = Number 0 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.11 = Number 1 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.12 = Number 2 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.13 = Number 3 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.14 = Number 4 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.15 = Number 5 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.16 = Number 6 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.17 = Number 7 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.18 = Number 8 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.19 = Number 9 +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.4C = - (Dash)/List +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.1A = Flashbk or Q.VIEW +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.09 = Mute/Delete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.02 = Volume up +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.03 = Volume down +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.00 = Channel up +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.01 = Channel down +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.1E = FAV/MARK +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.40 = ˄ Up +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.41 = ˅ Down +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.07 = ˂ Left +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.06 = ˃ Right +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.44 = Enter +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.28 = Back or Return +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.79 = Ratio +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.BA = Freeze +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.95 = Energy saving +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.7E = SIMPLINK +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.AA = Info +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.30 = AV mode +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.B1 = ■ Stop +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.B0 = ▶ Play +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.BA = ⏸ Pause +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.8E = ▶▶ Fast forward +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.8F = ◀◀ Rewind +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.72 = Red +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.71 = Green +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.63 = Yellow +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.61 = Blue +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.0F = TV +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.DC = 3D +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.5B = Exit +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.0C = Portal +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.AB = Guide +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.D6 = TV Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.C4 = Power on +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.C5 = Power off +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.5A = AV1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.D0 = AV2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.BF = Component1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.D4 = Component2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.D5 = RGB PC Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.CE = HDMI1 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.CC = HDMI2 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.E9 = HDMI3 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.DA = HDMI4 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.76 = Ratio 4:3 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.77 = Ratio 16:9 Discrete +channel-type.lgtvserial.ir-key-code-SAC34134216.state.option.AF = Ratio Zoom Discrete +channel-type.lgtvserial.ir-key-code.label = IR Code +channel-type.lgtvserial.ir-key-code.description = Send IR remote key code +channel-type.lgtvserial.ir-key-code.state.option.00 = Channel up +channel-type.lgtvserial.ir-key-code.state.option.01 = Channel down +channel-type.lgtvserial.ir-key-code.state.option.02 = Volume up +channel-type.lgtvserial.ir-key-code.state.option.03 = Volume down +channel-type.lgtvserial.ir-key-code.state.option.06 = Right +channel-type.lgtvserial.ir-key-code.state.option.07 = Left +channel-type.lgtvserial.ir-key-code.state.option.08 = Power toggle +channel-type.lgtvserial.ir-key-code.state.option.09 = Mute/Delete +channel-type.lgtvserial.ir-key-code.state.option.0B = Input +channel-type.lgtvserial.ir-key-code.state.option.0C = Portal +channel-type.lgtvserial.ir-key-code.state.option.0E = Sleep +channel-type.lgtvserial.ir-key-code.state.option.0F = TV +channel-type.lgtvserial.ir-key-code.state.option.10 = Number 0 +channel-type.lgtvserial.ir-key-code.state.option.11 = Number 1 +channel-type.lgtvserial.ir-key-code.state.option.12 = Number 2 +channel-type.lgtvserial.ir-key-code.state.option.13 = Number 3 +channel-type.lgtvserial.ir-key-code.state.option.14 = Number 4 +channel-type.lgtvserial.ir-key-code.state.option.15 = Number 5 +channel-type.lgtvserial.ir-key-code.state.option.16 = Number 6 +channel-type.lgtvserial.ir-key-code.state.option.17 = Number 7 +channel-type.lgtvserial.ir-key-code.state.option.18 = Number 8 +channel-type.lgtvserial.ir-key-code.state.option.19 = Number 9 +channel-type.lgtvserial.ir-key-code.state.option.1A = Flashbk or Q.VIEW +channel-type.lgtvserial.ir-key-code.state.option.1E = FAV/MARK +channel-type.lgtvserial.ir-key-code.state.option.28 = Back or Return +channel-type.lgtvserial.ir-key-code.state.option.30 = AV mode +channel-type.lgtvserial.ir-key-code.state.option.40 = Up +channel-type.lgtvserial.ir-key-code.state.option.41 = Down +channel-type.lgtvserial.ir-key-code.state.option.43 = Home or Menu +channel-type.lgtvserial.ir-key-code.state.option.44 = SET/Enter +channel-type.lgtvserial.ir-key-code.state.option.45 = Q.Menu +channel-type.lgtvserial.ir-key-code.state.option.4C = - (Dash)/List +channel-type.lgtvserial.ir-key-code.state.option.5A = AV Discrete +channel-type.lgtvserial.ir-key-code.state.option.5B = Exit +channel-type.lgtvserial.ir-key-code.state.option.61 = Blue +channel-type.lgtvserial.ir-key-code.state.option.63 = Yellow +channel-type.lgtvserial.ir-key-code.state.option.6E = PSM +channel-type.lgtvserial.ir-key-code.state.option.71 = Green +channel-type.lgtvserial.ir-key-code.state.option.72 = Red +channel-type.lgtvserial.ir-key-code.state.option.76 = ARC (4:3) Discrete +channel-type.lgtvserial.ir-key-code.state.option.77 = ARC (16:9) Discrete +channel-type.lgtvserial.ir-key-code.state.option.79 = ARC Discrete/Ratio +channel-type.lgtvserial.ir-key-code.state.option.7E = SIMPLINK +channel-type.lgtvserial.ir-key-code.state.option.8E = ▶▶ Fast forward +channel-type.lgtvserial.ir-key-code.state.option.8F = ◀◀ Rewind +channel-type.lgtvserial.ir-key-code.state.option.95 = Energy saving +channel-type.lgtvserial.ir-key-code.state.option.98 = AV +channel-type.lgtvserial.ir-key-code.state.option.99 = Auto config Discrete +channel-type.lgtvserial.ir-key-code.state.option.AA = Info +channel-type.lgtvserial.ir-key-code.state.option.AB = Guide +channel-type.lgtvserial.ir-key-code.state.option.AF = ARC (Zoom) Discrete +channel-type.lgtvserial.ir-key-code.state.option.B0 = ▶ Play +channel-type.lgtvserial.ir-key-code.state.option.B1 = ■ Stop +channel-type.lgtvserial.ir-key-code.state.option.BA = ⏸ Freeze/Pause +channel-type.lgtvserial.ir-key-code.state.option.BF = Component Discrete +channel-type.lgtvserial.ir-key-code.state.option.C0 = Green +channel-type.lgtvserial.ir-key-code.state.option.C1 = Red +channel-type.lgtvserial.ir-key-code.state.option.C2 = Yellow +channel-type.lgtvserial.ir-key-code.state.option.C3 = Blue +channel-type.lgtvserial.ir-key-code.state.option.C4 = Power on +channel-type.lgtvserial.ir-key-code.state.option.C5 = Power off +channel-type.lgtvserial.ir-key-code.state.option.C6 = HDMI/DVI Discrete +channel-type.lgtvserial.ir-key-code.state.option.CC = HDMI2 Discrete +channel-type.lgtvserial.ir-key-code.state.option.CE = HDMI1 Discrete +channel-type.lgtvserial.ir-key-code.state.option.D0 = AV2 Discrete +channel-type.lgtvserial.ir-key-code.state.option.D4 = Component2 Discrete +channel-type.lgtvserial.ir-key-code.state.option.D5 = RGB PC Discrete +channel-type.lgtvserial.ir-key-code.state.option.D6 = TV Discrete +channel-type.lgtvserial.ir-key-code.state.option.DA = HDMI4 Discrete +channel-type.lgtvserial.ir-key-code.state.option.DC = 3D +channel-type.lgtvserial.ir-key-code.state.option.E9 = HDMI3 Discrete +channel-type.lgtvserial.ism-M6503C.label = ISM Method +channel-type.lgtvserial.ism-M6503C.description = Avoid having a fixed image remain on screen +channel-type.lgtvserial.ism-M6503C.state.option.01 = Inversion +channel-type.lgtvserial.ism-M6503C.state.option.02 = Orbiter +channel-type.lgtvserial.ism-M6503C.state.option.04 = White Wash +channel-type.lgtvserial.ism-M6503C.state.option.08 = Normal +channel-type.lgtvserial.ism-M6503C.state.option.10 = Dot Wash +channel-type.lgtvserial.ism-SAC34134216.label = ISM Method +channel-type.lgtvserial.ism-SAC34134216.description = Avoid having a fixed image remain on screen +channel-type.lgtvserial.ism-SAC34134216.state.option.02 = Orbiter +channel-type.lgtvserial.ism-SAC34134216.state.option.04 = White Wash +channel-type.lgtvserial.ism-SAC34134216.state.option.08 = Normal +channel-type.lgtvserial.ism-SAC34134216.state.option.20 = Color Wash +channel-type.lgtvserial.ism-method.label = ISM Method +channel-type.lgtvserial.ism-method.description = Avoid having a fixed image remain on screen +channel-type.lgtvserial.ism-method.state.option.01 = Inversion +channel-type.lgtvserial.ism-method.state.option.02 = Orbiter +channel-type.lgtvserial.ism-method.state.option.04 = White Wash +channel-type.lgtvserial.ism-method.state.option.08 = Normal +channel-type.lgtvserial.ism-method.state.option.10 = Dot Wash +channel-type.lgtvserial.ism-method.state.option.20 = Color Wash +channel-type.lgtvserial.lamp-fault-check.label = Lamp Fault +channel-type.lgtvserial.lamp-fault-check.description = Check the lamp fault of the TV +channel-type.lgtvserial.lamp-fault-check.state.option.0 = Fan fault +channel-type.lgtvserial.lamp-fault-check.state.option.1 = Fan OK +channel-type.lgtvserial.natural-mode.label = Natural Mode +channel-type.lgtvserial.natural-mode.description = To assign the Tile Natural mode for Tiling function +channel-type.lgtvserial.osd-language.label = OSD Language +channel-type.lgtvserial.osd-language.description = Set the OSD language +channel-type.lgtvserial.osd-language.state.option.00 = English +channel-type.lgtvserial.osd-language.state.option.01 = French +channel-type.lgtvserial.osd-language.state.option.02 = German +channel-type.lgtvserial.osd-language.state.option.03 = Spanish +channel-type.lgtvserial.osd-language.state.option.04 = Italian +channel-type.lgtvserial.osd-language.state.option.05 = Portuguese +channel-type.lgtvserial.osd-language.state.option.06 = Chinese +channel-type.lgtvserial.osd-language.state.option.07 = Japanese +channel-type.lgtvserial.osd-language.state.option.08 = Korean +channel-type.lgtvserial.osd-language.state.option.09 = Russian +channel-type.lgtvserial.osd-select.label = OSD +channel-type.lgtvserial.osd-select.description = To select OSD (On Screen Display) on/off +channel-type.lgtvserial.picture-mode.label = Picture Mode +channel-type.lgtvserial.picture-mode.description = To adjust picture mode +channel-type.lgtvserial.picture-mode.state.option.00 = Vivid +channel-type.lgtvserial.picture-mode.state.option.01 = Standard +channel-type.lgtvserial.picture-mode.state.option.02 = Cinema +channel-type.lgtvserial.picture-mode.state.option.03 = Sport +channel-type.lgtvserial.picture-mode.state.option.04 = Game +channel-type.lgtvserial.picture-mode.state.option.05 = User1 +channel-type.lgtvserial.picture-mode.state.option.06 = User2 +channel-type.lgtvserial.power-indicator.label = Power Indicator +channel-type.lgtvserial.power-indicator.description = To set the LED for Power Indicator +channel-type.lgtvserial.power-saving.label = Power Saving +channel-type.lgtvserial.power-saving.description = Set the Power saving mode +channel-type.lgtvserial.power-saving.state.option.00 = Off +channel-type.lgtvserial.power-saving.state.option.01 = Static level 1 +channel-type.lgtvserial.power-saving.state.option.02 = Static level 2 +channel-type.lgtvserial.power-saving.state.option.03 = Static level 3 +channel-type.lgtvserial.power.label = Power +channel-type.lgtvserial.power.description = Power on/off +channel-type.lgtvserial.raw.label = Raw +channel-type.lgtvserial.raw.description = Send raw command over the serial power directly to TV(s) +channel-type.lgtvserial.screen-mute.label = Screen Mute +channel-type.lgtvserial.screen-mute.description = Select screen mute on/off +channel-type.lgtvserial.screen-mute.state.option.00 = Screen mute off (Picture on), Video-out Mute off +channel-type.lgtvserial.screen-mute.state.option.01 = Screen mute on (Picture off) +channel-type.lgtvserial.screen-mute.state.option.10 = Video-out Mute on +channel-type.lgtvserial.serial-number.label = Serial Number +channel-type.lgtvserial.serial-number.description = Read the serial numbers +channel-type.lgtvserial.sharpness.label = Sharpness +channel-type.lgtvserial.sharpness.description = Adjust screen sharpness +channel-type.lgtvserial.sleep-time.label = Sleep Time +channel-type.lgtvserial.sleep-time.description = Set sleep time +channel-type.lgtvserial.sleep-time.state.option.00 = Off +channel-type.lgtvserial.sleep-time.state.option.01 = 10 +channel-type.lgtvserial.sleep-time.state.option.02 = 20 +channel-type.lgtvserial.sleep-time.state.option.03 = 30 +channel-type.lgtvserial.sleep-time.state.option.04 = 60 +channel-type.lgtvserial.sleep-time.state.option.05 = 90 +channel-type.lgtvserial.sleep-time.state.option.06 = 120 +channel-type.lgtvserial.sleep-time.state.option.07 = 180 +channel-type.lgtvserial.sleep-time.state.option.08 = 240 +channel-type.lgtvserial.software-version.label = Software Version +channel-type.lgtvserial.software-version.description = Check the software version +channel-type.lgtvserial.sound-mode.label = Sound Mode +channel-type.lgtvserial.sound-mode.description = To adjust sound mode +channel-type.lgtvserial.sound-mode.state.option.00 = Clear Voice +channel-type.lgtvserial.sound-mode.state.option.01 = Standard +channel-type.lgtvserial.sound-mode.state.option.02 = Music +channel-type.lgtvserial.sound-mode.state.option.03 = Cinema +channel-type.lgtvserial.sound-mode.state.option.04 = Sport +channel-type.lgtvserial.sound-mode.state.option.05 = Game +channel-type.lgtvserial.sound-mode.state.option.06 = User +channel-type.lgtvserial.speaker.label = Speaker +channel-type.lgtvserial.speaker.description = Turn the speaker on or off +channel-type.lgtvserial.temperature-value.label = Temperature Value +channel-type.lgtvserial.temperature-value.description = Read the inside temperature value +channel-type.lgtvserial.tile-h-position.label = Horizontal Position +channel-type.lgtvserial.tile-h-position.description = Set the horizontal position +channel-type.lgtvserial.tile-h-size.label = Horizontal Size +channel-type.lgtvserial.tile-h-size.description = Set the horizontal size +channel-type.lgtvserial.tile-id-set.label = Tile ID Set +channel-type.lgtvserial.tile-id-set.description = To assign the Tile ID for Tiling function +channel-type.lgtvserial.tile-v-position.label = Vertical Position +channel-type.lgtvserial.tile-v-position.description = Set the vertical position +channel-type.lgtvserial.tile-v-size.label = Vertical Size +channel-type.lgtvserial.tile-v-size.description = Set the vertical size +channel-type.lgtvserial.tile.label = Tile Mode +channel-type.lgtvserial.tile.description = Change a tile mode +channel-type.lgtvserial.tile.state.option.00 = Tile mode off +channel-type.lgtvserial.tile.state.option.11 = 1 x 1 mode (same as off) +channel-type.lgtvserial.tile.state.option.12 = 1 x 2 mode +channel-type.lgtvserial.tile.state.option.13 = 1 x 3 mode +channel-type.lgtvserial.tile.state.option.14 = 1 x 4 mode +channel-type.lgtvserial.tile.state.option.15 = 1 x 5 mode +channel-type.lgtvserial.tile.state.option.21 = 2 x 1 mode +channel-type.lgtvserial.tile.state.option.22 = 2 x 2 mode +channel-type.lgtvserial.tile.state.option.23 = 2 x 3 mode +channel-type.lgtvserial.tile.state.option.24 = 2 x 4 mode +channel-type.lgtvserial.tile.state.option.25 = 2 x 5 mode +channel-type.lgtvserial.tile.state.option.31 = 3 x 1 mode +channel-type.lgtvserial.tile.state.option.32 = 3 x 2 mode +channel-type.lgtvserial.tile.state.option.33 = 3 x 3 mode +channel-type.lgtvserial.tile.state.option.34 = 3 x 4 mode +channel-type.lgtvserial.tile.state.option.35 = 3 x 5 mode +channel-type.lgtvserial.tile.state.option.41 = 4 x 1 mode +channel-type.lgtvserial.tile.state.option.42 = 4 x 2 mode +channel-type.lgtvserial.tile.state.option.43 = 4 x 3 mode +channel-type.lgtvserial.tile.state.option.44 = 4 x 4 mode +channel-type.lgtvserial.tile.state.option.45 = 4 x 5 mode +channel-type.lgtvserial.tile.state.option.51 = 5 x 1 mode +channel-type.lgtvserial.tile.state.option.52 = 5 x 2 mode +channel-type.lgtvserial.tile.state.option.53 = 5 x 3 mode +channel-type.lgtvserial.tile.state.option.54 = 5 x 4 mode +channel-type.lgtvserial.tile.state.option.55 = 5 x 5 mode +channel-type.lgtvserial.tint.label = Tint +channel-type.lgtvserial.tint.description = Tint control (%) +channel-type.lgtvserial.treble.label = Treble +channel-type.lgtvserial.treble.description = Treble control (%) +channel-type.lgtvserial.v-position.label = V Position +channel-type.lgtvserial.v-position.description = Set the vertical position +channel-type.lgtvserial.volume-mute.label = Mute +channel-type.lgtvserial.volume-mute.description = Mute on/off +channel-type.lgtvserial.volume.label = Volume +channel-type.lgtvserial.volume.description = Volume control (%) diff --git a/bundles/org.openhab.binding.linuxinput/src/main/resources/OH-INF/i18n/linuxinput.properties b/bundles/org.openhab.binding.linuxinput/src/main/resources/OH-INF/i18n/linuxinput.properties new file mode 100644 index 0000000000000..4dcd2a9244fac --- /dev/null +++ b/bundles/org.openhab.binding.linuxinput/src/main/resources/OH-INF/i18n/linuxinput.properties @@ -0,0 +1,26 @@ +# binding + +binding.linuxinput.name = LinuxInput Binding +binding.linuxinput.description = This is the binding for LinuxInput. + +# thing types + +thing-type.linuxinput.input-device.label = LinuxInput Device +thing-type.linuxinput.input-device.description = Input device + +# thing types config + +thing-type.config.linuxinput.input-device.enable.label = Enable +thing-type.config.linuxinput.input-device.enable.description = If the Thing should be enabled and consume all input from this device +thing-type.config.linuxinput.input-device.path.label = Path +thing-type.config.linuxinput.input-device.path.description = Path to device file + +# channel group types + +channel-group-type.linuxinput.keypresses.label = Key Presses + +# channel types + +channel-type.linuxinput.device-grab.label = Device Grab +channel-type.linuxinput.key-press.label = Key Pressed +channel-type.linuxinput.key.label = Key Event diff --git a/bundles/org.openhab.binding.lirc/src/main/resources/OH-INF/i18n/lirc.properties b/bundles/org.openhab.binding.lirc/src/main/resources/OH-INF/i18n/lirc.properties new file mode 100644 index 0000000000000..6f57716373e94 --- /dev/null +++ b/bundles/org.openhab.binding.lirc/src/main/resources/OH-INF/i18n/lirc.properties @@ -0,0 +1,27 @@ +# binding + +binding.lirc.name = LIRC Binding +binding.lirc.description = The LIRC binding allows transmission and receipt of standard infrared remote control signals via a LIRC server. + +# thing types + +thing-type.lirc.bridge.label = LIRC Server +thing-type.lirc.bridge.description = The LIRC Server Bridge. +thing-type.lirc.remote.label = Remote Control +thing-type.lirc.remote.description = An IR remote control + +# thing types config + +thing-type.config.lirc.bridge.host.label = Hostname +thing-type.config.lirc.bridge.host.description = The host of the LIRC server +thing-type.config.lirc.bridge.portNumber.label = Port +thing-type.config.lirc.bridge.portNumber.description = The port number the LIRC server is listening to. +thing-type.config.lirc.remote.remote.label = Remote Name +thing-type.config.lirc.remote.remote.description = The name of the remote as configured in LIRC + +# channel types + +channel-type.lirc.event.label = Button Event +channel-type.lirc.event.description = Triggers whenever a button is pressed +channel-type.lirc.transmit.label = Transmit Command +channel-type.lirc.transmit.description = Used to transmit IR commands diff --git a/bundles/org.openhab.binding.loxone/src/main/resources/OH-INF/i18n/loxone.properties b/bundles/org.openhab.binding.loxone/src/main/resources/OH-INF/i18n/loxone.properties new file mode 100644 index 0000000000000..640cdce9856b6 --- /dev/null +++ b/bundles/org.openhab.binding.loxone/src/main/resources/OH-INF/i18n/loxone.properties @@ -0,0 +1,116 @@ +# binding + +binding.loxone.name = Loxone Binding +binding.loxone.description = This is the binding for Loxone Miniserver + +# thing types + +thing-type.loxone.miniserver.label = Loxone Miniserver +thing-type.loxone.miniserver.description = IP gateway for Loxone Smarthome system + +# thing types config + +thing-type.config.loxone.miniserver.authMethod.label = Authorization Method +thing-type.config.loxone.miniserver.authMethod.description = Method used to authorize user in the Miniserver +thing-type.config.loxone.miniserver.authMethod.option.0 = Automatic +thing-type.config.loxone.miniserver.authMethod.option.1 = Hash-based +thing-type.config.loxone.miniserver.authMethod.option.2 = Token-based +thing-type.config.loxone.miniserver.authToken.label = Token +thing-type.config.loxone.miniserver.authToken.description = Token acquired by the binding from the Miniserver. Applicable only in token-based authentication mode. +thing-type.config.loxone.miniserver.comErrorDelay.label = Communication Error Delay +thing-type.config.loxone.miniserver.comErrorDelay.description = Time between connection close (as a result of some communication error) and next connection attempt (seconds, 0-3600) +thing-type.config.loxone.miniserver.connectErrDelay.label = Connect Error Delay +thing-type.config.loxone.miniserver.connectErrDelay.description = Time between failed websocket connect attempts (seconds, 0-600) +thing-type.config.loxone.miniserver.firstConDelay.label = First Connection Delay +thing-type.config.loxone.miniserver.firstConDelay.description = Time between binding initialization and first connection attempt (seconds, 0-120) +thing-type.config.loxone.miniserver.group.miniserver.label = Miniserver Settings +thing-type.config.loxone.miniserver.group.miniserver.description = Connection to Miniserver +thing-type.config.loxone.miniserver.group.security.label = Security Settings +thing-type.config.loxone.miniserver.group.security.description = Authentication and encryption parameters +thing-type.config.loxone.miniserver.group.sizes.label = Size Settings +thing-type.config.loxone.miniserver.group.sizes.description = Various sizing parameters +thing-type.config.loxone.miniserver.group.timeouts.label = Timeout Settings +thing-type.config.loxone.miniserver.group.timeouts.description = Various timeout parameters +thing-type.config.loxone.miniserver.host.label = Host +thing-type.config.loxone.miniserver.host.description = Host address or IP of the Loxone Miniserver +thing-type.config.loxone.miniserver.httpsPort.label = HTTPS Port +thing-type.config.loxone.miniserver.httpsPort.description = HTTPS Web interface port of the Loxone Miniserver +thing-type.config.loxone.miniserver.keepAlivePeriod.label = Period Between Connection Keep-alive Messages +thing-type.config.loxone.miniserver.keepAlivePeriod.description = Time between sending two consecutive keep-alive messages (seconds, 1-600) +thing-type.config.loxone.miniserver.maxBinMsgSize.label = Maximum Binary Message Size (kB) +thing-type.config.loxone.miniserver.maxBinMsgSize.description = Websocket client's maximum binary message size in kB +thing-type.config.loxone.miniserver.maxTextMsgSize.label = Maximum Text Message Size (kB) +thing-type.config.loxone.miniserver.maxTextMsgSize.description = Websocket client's maximum text message size in kB +thing-type.config.loxone.miniserver.password.label = Password +thing-type.config.loxone.miniserver.password.description = User password on the Loxone Miniserver. In token-based authentication this password will be cleared after token is acquired. +thing-type.config.loxone.miniserver.port.label = HTTP Port +thing-type.config.loxone.miniserver.port.description = HTTP Web interface port of the Loxone Miniserver +thing-type.config.loxone.miniserver.responseTimeout.label = Miniserver Response Timeout +thing-type.config.loxone.miniserver.responseTimeout.description = Time to wait for a response from Miniserver to a request sent from the binding (seconds, 0-60) +thing-type.config.loxone.miniserver.user.label = User +thing-type.config.loxone.miniserver.user.description = User name on the Loxone Miniserver +thing-type.config.loxone.miniserver.userErrorDelay.label = Authentication Error Delay +thing-type.config.loxone.miniserver.userErrorDelay.description = Time in seconds between user login error as a result of wrong name/password or no authority and next connection attempt (seconds, 0-3600) +thing-type.config.loxone.miniserver.webSocketType.label = WebSocket Connection Type +thing-type.config.loxone.miniserver.webSocketType.description = Protocol used to communicate over WebSocket to the Miniserver +thing-type.config.loxone.miniserver.webSocketType.option.0 = Automatic +thing-type.config.loxone.miniserver.webSocketType.option.1 = Force HTTPS +thing-type.config.loxone.miniserver.webSocketType.option.2 = Force HTTP + +# channel types + +channel-type.loxone.colorPickerTypeId.label = Loxone ColorPicker +channel-type.loxone.colorPickerTypeId.description = Loxone's Color Picker V2 control +channel-type.loxone.dimmerTypeId.label = Loxone Dimmer +channel-type.loxone.dimmerTypeId.description = Loxone's dimmer control +channel-type.loxone.iRoomV2ActiveModeTypeId.label = Active Mode +channel-type.loxone.iRoomV2ActiveModeTypeId.description = Loxone Intelligent Room Controller V2 Active Mode. +channel-type.loxone.iRoomV2ActiveModeTypeId.state.option.0 = Economy +channel-type.loxone.iRoomV2ActiveModeTypeId.state.option.1 = Comfort temperature +channel-type.loxone.iRoomV2ActiveModeTypeId.state.option.2 = Building protection +channel-type.loxone.iRoomV2ActiveModeTypeId.state.option.3 = Manual +channel-type.loxone.iRoomV2ComfortToleranceTypeId.label = Comfort Tolerance Temperature +channel-type.loxone.iRoomV2ComfortToleranceTypeId.description = Loxone Intelligent Room Controller V2 Comfort Tolerance. +channel-type.loxone.iRoomV2OperatingModeTypeId.label = Operating Mode +channel-type.loxone.iRoomV2OperatingModeTypeId.description = Loxone Intelligent Room Controller V2 Operating Mode. +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.0 = Automatic, heating and cooling allowed +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.1 = Automatic, only heating allowed +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.2 = Automatic, only cooling allowed +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.3 = Manual, heating and cooling allowed +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.4 = Manual, only heating allowed +channel-type.loxone.iRoomV2OperatingModeTypeId.state.option.5 = Manual, only cooling allowed +channel-type.loxone.iRoomV2PrepareStateTypeId.label = Prepare State +channel-type.loxone.iRoomV2PrepareStateTypeId.description = Loxone Intelligent Room Controller V2 Prepare State. +channel-type.loxone.iRoomV2PrepareStateTypeId.state.option.-1 = Cooling down +channel-type.loxone.iRoomV2PrepareStateTypeId.state.option.0 = No action +channel-type.loxone.iRoomV2PrepareStateTypeId.state.option.1 = Heating up +channel-type.loxone.lightCtrlTypeId.label = Loxone Light Controller / Hotel Light Controller +channel-type.loxone.lightCtrlTypeId.description = Loxone's light controllers (LightController). +channel-type.loxone.lightCtrlTypeId.state.option.0 = All off +channel-type.loxone.lightCtrlTypeId.state.option.1 = Scene 1 +channel-type.loxone.lightCtrlTypeId.state.option.2 = Scene 2 +channel-type.loxone.lightCtrlTypeId.state.option.3 = Scene 3 +channel-type.loxone.lightCtrlTypeId.state.option.4 = Scene 4 +channel-type.loxone.lightCtrlTypeId.state.option.5 = Scene 5 +channel-type.loxone.lightCtrlTypeId.state.option.6 = Scene 6 +channel-type.loxone.lightCtrlTypeId.state.option.7 = Scene 7 +channel-type.loxone.lightCtrlTypeId.state.option.8 = Scene 8 +channel-type.loxone.lightCtrlTypeId.state.option.9 = All on +channel-type.loxone.numberTypeId.label = Loxone Virtual Input Information +channel-type.loxone.numberTypeId.description = Loxone's Virtual Inputs. +channel-type.loxone.radioButtonTypeId.label = Loxone Radio Button (8x and 16x) +channel-type.loxone.radioButtonTypeId.description = Loxone's radio button controls (Radio). +channel-type.loxone.roAnalogTypeId.label = Loxone Virtual Analog State Read-only Information +channel-type.loxone.roAnalogTypeId.description = Loxone's state information controls (InfoOnlyAnalog, read-only). +channel-type.loxone.roDateTimeTypeId.label = Date Time +channel-type.loxone.roDateTimeTypeId.description = Date and time of an event +channel-type.loxone.roNumberTypeId.label = Loxone State Read-only Information +channel-type.loxone.roNumberTypeId.description = Loxone's time counter (TimedSwitch, read-only). +channel-type.loxone.roSwitchTypeId.label = Loxone Digital Read-only Information +channel-type.loxone.roSwitchTypeId.description = Loxone's digital information controls (InfoOnlyDigital, read-only). +channel-type.loxone.roTextTypeId.label = Loxone State Read-only Information +channel-type.loxone.roTextTypeId.description = Loxone's state information controls (TextState, read-only). +channel-type.loxone.rollerShutterTypeId.label = Loxone Jalousie +channel-type.loxone.rollerShutterTypeId.description = Loxone's Jalousies (rollershutters, blinds). +channel-type.loxone.switchTypeId.label = Loxone Switch +channel-type.loxone.switchTypeId.description = Loxone's virtual input of switch type and push button controls. diff --git a/bundles/org.openhab.binding.luftdateninfo/src/main/resources/OH-INF/i18n/luftdateninfo.properties b/bundles/org.openhab.binding.luftdateninfo/src/main/resources/OH-INF/i18n/luftdateninfo.properties new file mode 100644 index 0000000000000..9bd90d74e4a19 --- /dev/null +++ b/bundles/org.openhab.binding.luftdateninfo/src/main/resources/OH-INF/i18n/luftdateninfo.properties @@ -0,0 +1,47 @@ +# binding + +binding.luftdateninfo.name = LuftdatenInfo Binding +binding.luftdateninfo.description = Binding to integrate DIY Sensors from luftdaten.info Sensor Community + +# thing types + +thing-type.luftdateninfo.conditions.label = Condition Sensor +thing-type.luftdateninfo.conditions.description = Sensor to measure Temperature and Humidity conditions +thing-type.luftdateninfo.noise.label = Noise Sensor +thing-type.luftdateninfo.noise.description = Sensor to measure noise on location +thing-type.luftdateninfo.particulate.label = Particulate Sensor +thing-type.luftdateninfo.particulate.description = Sensor to measure Particulate Matter (PM) + +# thing types config + +thing-type.config.luftdateninfo.conditions.ipAddress.label = Internal IP Address +thing-type.config.luftdateninfo.conditions.ipAddress.description = Local IP address of your personal owned sensor +thing-type.config.luftdateninfo.conditions.sensorid.label = External Sensor ID +thing-type.config.luftdateninfo.conditions.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/ +thing-type.config.luftdateninfo.noise.ipAddress.label = Internal IP Address +thing-type.config.luftdateninfo.noise.ipAddress.description = Local IP address of your personal owned sensor +thing-type.config.luftdateninfo.noise.sensorid.label = External Sensor ID +thing-type.config.luftdateninfo.noise.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/ +thing-type.config.luftdateninfo.particulate.ipAddress.label = Internal IP Address +thing-type.config.luftdateninfo.particulate.ipAddress.description = Local IP address of your personal owned sensor +thing-type.config.luftdateninfo.particulate.sensorid.label = External Sensor ID +thing-type.config.luftdateninfo.particulate.sensorid.description = Sensor ID from https://deutschland.maps.sensor.community/ + +# channel types + +channel-type.luftdateninfo.hum-channel.label = Humidity +channel-type.luftdateninfo.hum-channel.description = Humidity from the selected Sensor ID +channel-type.luftdateninfo.noise-eq-channel.label = Average Noise +channel-type.luftdateninfo.noise-eq-channel.description = Average noise level from the selected Sensor ID +channel-type.luftdateninfo.noise-max-channel.label = Maximum Noise +channel-type.luftdateninfo.noise-max-channel.description = Maximum noise level (last 2.5 minutes) from the selected Sensor ID +channel-type.luftdateninfo.noise-min-channel.label = Minimum Noise +channel-type.luftdateninfo.noise-min-channel.description = Minimum noise level (last 2.5 minutes) from the selected Sensor ID +channel-type.luftdateninfo.pm100-channel.label = Particulate Matter category 10.0 +channel-type.luftdateninfo.pm25-channel.label = Particulate Matter category 2.5 +channel-type.luftdateninfo.pressure-channel.label = Atmospheric Pressure +channel-type.luftdateninfo.pressure-channel.description = Atmospheric Pressure from the selected Sensor ID +channel-type.luftdateninfo.pressure-sea-channel.label = Atmospheric Pressure Sea Level +channel-type.luftdateninfo.pressure-sea-channel.description = Atmospheric Pressure at sea level from the selected Sensor ID +channel-type.luftdateninfo.temp-channel.label = Temperature +channel-type.luftdateninfo.temp-channel.description = Temperature from the selected Sensor ID diff --git a/bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/i18n/lutron.properties b/bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/i18n/lutron.properties new file mode 100644 index 0000000000000..3d3ddf7eadebb --- /dev/null +++ b/bundles/org.openhab.binding.lutron/src/main/resources/OH-INF/i18n/lutron.properties @@ -0,0 +1,500 @@ +# binding + +binding.lutron.name = Lutron Binding +binding.lutron.description = The Lutron binding interfaces with Lutron lighting control and home automation systems such as RadioRA, RadioRA 2, HomeWorks, HomeWorks QS, RA2 Select, Caseta, and GRAFIK Eye. + +# thing types + +thing-type.lutron.blind.label = Lutron Blind +thing-type.lutron.blind.description = Controls venetian and horizontal sheer blinds +thing-type.lutron.cco.label = CCO +thing-type.lutron.cco.description = Contact Closure Output +thing-type.lutron.ccomaintained.label = Maintained CCO (Deprecated) +thing-type.lutron.ccomaintained.description = Maintained Contact Closure Output (Deprecated) +thing-type.lutron.ccopulsed.label = Pulsed CCO (Deprecated) +thing-type.lutron.ccopulsed.description = Pulsed Contact Closure Output (Deprecated) +thing-type.lutron.dimmer.label = Lutron Dimmer +thing-type.lutron.dimmer.description = Controls dimmable loads +thing-type.lutron.fan.label = Fan Speed Controller +thing-type.lutron.fan.description = Controls ceiling fans +thing-type.lutron.grafikeye.label = GRAFIK Eye +thing-type.lutron.grafikeye.description = Controls a GRAFIK Eye +thing-type.lutron.grafikeye.channel.zoneintensity1.label = Zone 1 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity1.description = The intensity level of zone 1 +thing-type.lutron.grafikeye.channel.zoneintensity2.label = Zone 2 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity2.description = The intensity level of zone 2 +thing-type.lutron.grafikeye.channel.zoneintensity3.label = Zone 3 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity3.description = The intensity level of zone 3 +thing-type.lutron.grafikeye.channel.zoneintensity4.label = Zone 4 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity4.description = The intensity level of zone 4 +thing-type.lutron.grafikeye.channel.zoneintensity5.label = Zone 5 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity5.description = The intensity level of zone 5 +thing-type.lutron.grafikeye.channel.zoneintensity6.label = Zone 6 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity6.description = The intensity level of zone 6 +thing-type.lutron.grafikeye.channel.zoneintensity7.label = Zone 7 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity7.description = The intensity level of zone 7 +thing-type.lutron.grafikeye.channel.zoneintensity8.label = Zone 8 Intensity +thing-type.lutron.grafikeye.channel.zoneintensity8.description = The intensity level of zone 8 +thing-type.lutron.grafikeye.channel.zonelower1.label = Ramps Zone 1 Down +thing-type.lutron.grafikeye.channel.zonelower1.description = Starts the ramping of Zone 1 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower2.label = Ramps Zone 2 Down +thing-type.lutron.grafikeye.channel.zonelower2.description = Starts the ramping of Zone 2 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower3.label = Ramps Zone 3 Down +thing-type.lutron.grafikeye.channel.zonelower3.description = Starts the ramping of Zone 3 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower4.label = Ramps Zone 4 Down +thing-type.lutron.grafikeye.channel.zonelower4.description = Starts the ramping of Zone 4 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower5.label = Ramps Zone 5 Down +thing-type.lutron.grafikeye.channel.zonelower5.description = Starts the ramping of Zone 5 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower6.label = Ramps Zone 6 Down +thing-type.lutron.grafikeye.channel.zonelower6.description = Starts the ramping of Zone 6 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower7.label = Ramps Zone 7 Down +thing-type.lutron.grafikeye.channel.zonelower7.description = Starts the ramping of Zone 7 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zonelower8.label = Ramps Zone 8 Down +thing-type.lutron.grafikeye.channel.zonelower8.description = Starts the ramping of Zone 8 down (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise1.label = Ramps Zone 1 Up +thing-type.lutron.grafikeye.channel.zoneraise1.description = Starts the ramping of Zone 1 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise2.label = Ramps Zone 2 Up +thing-type.lutron.grafikeye.channel.zoneraise2.description = Starts the ramping of Zone 2 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise3.label = Ramps Zone 3 Up +thing-type.lutron.grafikeye.channel.zoneraise3.description = Starts the ramping of Zone 3 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise4.label = Ramps Zone 4 Up +thing-type.lutron.grafikeye.channel.zoneraise4.description = Starts the ramping of Zone 4 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise5.label = Ramps Zone 5 Up +thing-type.lutron.grafikeye.channel.zoneraise5.description = Starts the ramping of Zone 5 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise6.label = Ramps Zone 6 Up +thing-type.lutron.grafikeye.channel.zoneraise6.description = Starts the ramping of Zone 6 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise7.label = Ramps Zone 7 Up +thing-type.lutron.grafikeye.channel.zoneraise7.description = Starts the ramping of Zone 7 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneraise8.label = Ramps Zone 8 Up +thing-type.lutron.grafikeye.channel.zoneraise8.description = Starts the ramping of Zone 8 up (in zonefade seconds) +thing-type.lutron.grafikeye.channel.zoneshade1.label = Zone 1 Shade +thing-type.lutron.grafikeye.channel.zoneshade1.description = The shade status of zone 1 +thing-type.lutron.grafikeye.channel.zoneshade2.label = Zone 2 Shade +thing-type.lutron.grafikeye.channel.zoneshade2.description = The shade status of zone 2 +thing-type.lutron.grafikeye.channel.zoneshade3.label = Zone 3 Shade +thing-type.lutron.grafikeye.channel.zoneshade3.description = The shade status of zone 3 +thing-type.lutron.grafikeye.channel.zoneshade4.label = Zone 4 Shade +thing-type.lutron.grafikeye.channel.zoneshade4.description = The shade status of zone 4 +thing-type.lutron.grafikeye.channel.zoneshade5.label = Zone 5 Shade +thing-type.lutron.grafikeye.channel.zoneshade5.description = The shade status of zone 5 +thing-type.lutron.grafikeye.channel.zoneshade6.label = Zone 6 Shade +thing-type.lutron.grafikeye.channel.zoneshade6.description = The shade status of zone 6 +thing-type.lutron.grafikeye.channel.zoneshade7.label = Zone 7 Shade +thing-type.lutron.grafikeye.channel.zoneshade7.description = The shade status of zone 7 +thing-type.lutron.grafikeye.channel.zoneshade8.label = Zone 8 Shade +thing-type.lutron.grafikeye.channel.zoneshade8.description = The shade status of zone 8 +thing-type.lutron.grafikeyekeypad.label = GRAFIK Eye QS Keypad +thing-type.lutron.grafikeyekeypad.description = Lutron GRAFIK Eye QS for RadioRA 2/HomeWorks QS +thing-type.lutron.greenmode.label = Green Mode +thing-type.lutron.greenmode.description = Green mode step control +thing-type.lutron.hwdimmer.label = Lutron Dimmer (Legacy HomeWorks) +thing-type.lutron.hwdimmer.description = Controls dimmable loads for legacy HomeWorks systems +thing-type.lutron.hwserialbridge.label = Lutron HomeWorks RS232 Bridge +thing-type.lutron.hwserialbridge.description = RS232 access point to Legacy Lutron HomeWorks lighting control system +thing-type.lutron.intlkeypad.label = International seeTouch Keypad +thing-type.lutron.intlkeypad.description = Lutron International seeTouch keypad (HomeWorks QS Only) +thing-type.lutron.ipbridge.label = Lutron IP Access Point +thing-type.lutron.ipbridge.description = Lutron controller using Lutron Integration Protocol (LIP) over TCP/IP +thing-type.lutron.keypad.label = seeTouch Keypad +thing-type.lutron.keypad.description = Lutron seeTouch/Hybrid seeTouch wall keypad +thing-type.lutron.leapbridge.label = Lutron LEAP Access Point +thing-type.lutron.leapbridge.description = Lutron controller using LEAP protocol over TCP/IP +thing-type.lutron.occupancysensor.label = Radio Powr Savr Sensor +thing-type.lutron.occupancysensor.description = Motion sensor to detect occupancy status +thing-type.lutron.ogroup.label = Occupancy Group +thing-type.lutron.ogroup.description = Shows state of occupancy sensor group +thing-type.lutron.palladiomkeypad.label = Palladiom Keypad +thing-type.lutron.palladiomkeypad.description = Lutron Palladiom keypad (HomeWorks QS Only) +thing-type.lutron.pico.label = Pico Keypad +thing-type.lutron.pico.description = Lutron wireless Pico keypad +thing-type.lutron.prgbridge.label = Lutron GRX-PRG or GRX-CI-PRG Bridge +thing-type.lutron.prgbridge.description = Ethernet access point to Lutron GRAFIK Eye 3x/4x Systems +thing-type.lutron.prgbridge.channel.ssnextminute.label = Super Schedule Next Minute +thing-type.lutron.prgbridge.channel.ssnextminute.description = Minutes until the next step in the super schedule +thing-type.lutron.prgbridge.channel.ssnextsecond.label = Super Schedule Next Seconds +thing-type.lutron.prgbridge.channel.ssnextsecond.description = Seconds until the next step in the super schedule +thing-type.lutron.prgbridge.channel.ssnextstep.label = Super Schedule Next Step +thing-type.lutron.prgbridge.channel.ssnextstep.description = The next step number in the Super Schedule +thing-type.lutron.prgbridge.channel.sspause.label = Super Schedule Pause +thing-type.lutron.prgbridge.channel.sspause.description = Pause the super schedule +thing-type.lutron.prgbridge.channel.ssresume.label = Super Schedule Resume +thing-type.lutron.prgbridge.channel.ssresume.description = Resume the super schedule +thing-type.lutron.prgbridge.channel.ssstart.label = Super Schedule Start +thing-type.lutron.prgbridge.channel.ssstart.description = Start the super schedule +thing-type.lutron.prgbridge.channel.sunrise.label = Sunrise +thing-type.lutron.prgbridge.channel.sunrise.description = Today's sunrise +thing-type.lutron.prgbridge.channel.sunset.label = Sunset +thing-type.lutron.prgbridge.channel.sunset.description = Today's sunset +thing-type.lutron.prgbridge.channel.zonelowerstop.label = All Zone Lower Stop +thing-type.lutron.prgbridge.channel.zonelowerstop.description = Stopping all ramping down on all Control Units +thing-type.lutron.prgbridge.channel.zoneraisestop.label = All Zone Raise Stop +thing-type.lutron.prgbridge.channel.zoneraisestop.description = Stopping all ramping up on all Control Units +thing-type.lutron.qsio.label = QS IO Interface +thing-type.lutron.qsio.description = Lutron QS IO Interface +thing-type.lutron.ra-dimmer.label = Lutron Dimmer (Legacy RadioRA) +thing-type.lutron.ra-dimmer.description = Controls dimmable loads for legacy RadioRA systems +thing-type.lutron.ra-phantomButton.label = Phantom Button (Legacy RadioRA) +thing-type.lutron.ra-phantomButton.description = Phantom Button for Legacy RadioRA systems +thing-type.lutron.ra-rs232.label = Lutron RadioRA RS232 +thing-type.lutron.ra-rs232.description = RS-232 access to legacy Lutron RadioRA systems +thing-type.lutron.ra-switch.label = Lutron Switch (Legacy RadioRA) +thing-type.lutron.ra-switch.description = On/off switch for Legacy RadioRA systems +thing-type.lutron.shade.label = Lutron Shade +thing-type.lutron.shade.description = Controls roller shades, drapes, and motor controllers +thing-type.lutron.switch.label = Lutron Switch +thing-type.lutron.switch.description = On/off switch +thing-type.lutron.sysvar.label = System State Variable +thing-type.lutron.sysvar.description = HomeWorks QS system state variable +thing-type.lutron.timeclock.label = Timeclock +thing-type.lutron.timeclock.description = RA2/HWQS timeclock and scheduler module +thing-type.lutron.timeclock.channel.disableevent.label = Disable Event +thing-type.lutron.timeclock.channel.enableevent.label = Enable Event +thing-type.lutron.timeclock.channel.execevent.label = Execute Event +thing-type.lutron.timeclock.channel.sunrise.label = Sunrise +thing-type.lutron.timeclock.channel.sunrise.description = Today's sunrise time +thing-type.lutron.timeclock.channel.sunset.label = Sunset +thing-type.lutron.timeclock.channel.sunset.description = Today's sunset time +thing-type.lutron.ttkeypad.label = Tabletop seeTouch Keypad +thing-type.lutron.ttkeypad.description = Lutron wireless tabletop keypad +thing-type.lutron.vcrx.label = VCRX +thing-type.lutron.vcrx.description = Lutron visor control receiver +thing-type.lutron.virtualkeypad.label = Virtual Keypad +thing-type.lutron.virtualkeypad.description = Virtual integration keypad on repeater +thing-type.lutron.wci.label = WCI +thing-type.lutron.wci.description = QS Wallbox Closure Interface + +# thing types config + +thing-type.config.lutron.blind.integrationId.label = Integration ID +thing-type.config.lutron.blind.integrationId.description = Address of blind in the Lutron system +thing-type.config.lutron.blind.type.label = Type +thing-type.config.lutron.blind.type.description = Type of blind +thing-type.config.lutron.blind.type.option.Sheer = Sheer +thing-type.config.lutron.blind.type.option.Venetian = Venetian +thing-type.config.lutron.cco.integrationId.label = Integration ID +thing-type.config.lutron.cco.integrationId.description = Address of CCO in the Lutron control system +thing-type.config.lutron.cco.outputType.label = Output Type +thing-type.config.lutron.cco.outputType.description = CCO Output Type +thing-type.config.lutron.cco.outputType.option.Pulsed = Pulsed +thing-type.config.lutron.cco.outputType.option.Maintained = Maintained +thing-type.config.lutron.cco.pulseLength.label = Pulse Length +thing-type.config.lutron.cco.pulseLength.description = Pulse length in seconds (0.25 - 99.00) +thing-type.config.lutron.ccomaintained.integrationId.label = Integration ID +thing-type.config.lutron.ccomaintained.integrationId.description = Address of CCO in the Lutron control system +thing-type.config.lutron.ccopulsed.integrationId.label = Integration ID +thing-type.config.lutron.ccopulsed.integrationId.description = Address of CCO in the Lutron control system +thing-type.config.lutron.ccopulsed.pulseLength.label = Pulse Length +thing-type.config.lutron.ccopulsed.pulseLength.description = Pulse length in seconds (0.25 - 99.00) +thing-type.config.lutron.dimmer.fadeInTime.label = Fade In Time +thing-type.config.lutron.dimmer.fadeInTime.description = Fade time in seconds when turning on the light +thing-type.config.lutron.dimmer.fadeOutTime.label = Fade Out Time +thing-type.config.lutron.dimmer.fadeOutTime.description = Fade time in seconds when turning off the light +thing-type.config.lutron.dimmer.integrationId.label = Integration ID +thing-type.config.lutron.dimmer.integrationId.description = Address of dimmer in the Lutron lighting system +thing-type.config.lutron.dimmer.onLevel.label = On Level +thing-type.config.lutron.dimmer.onLevel.description = Output level to go to when an ON command is received. Default is 100%. +thing-type.config.lutron.dimmer.onToLast.label = Turn On To Last Level +thing-type.config.lutron.dimmer.onToLast.description = If set to true, dimmer will go to the last non-zero level set when an ON command is received. If the last level cannot be determined, the value of onLevel will be used instead. +thing-type.config.lutron.fan.integrationId.label = Integration ID +thing-type.config.lutron.fan.integrationId.description = Address of fan controller in the Lutron system +thing-type.config.lutron.grafikeye.controlUnit.label = Integration ID +thing-type.config.lutron.grafikeye.controlUnit.description = Address of dimmer in the Lutron lighting system +thing-type.config.lutron.grafikeye.fade.label = Default Zone Intensity Fade Time +thing-type.config.lutron.grafikeye.fade.description = Default fade time (in seconds) to new intensity +thing-type.config.lutron.grafikeye.polling.label = Polling Interval +thing-type.config.lutron.grafikeye.polling.description = Interval (in seconds) to poll the actual state of the Matrix +thing-type.config.lutron.grafikeye.shadeZones.label = Shade Zone(s) +thing-type.config.lutron.grafikeye.shadeZones.description = Comma delimited list of zones that are QED shades +thing-type.config.lutron.grafikeye.shadeZones.label = Shade Zones +thing-type.config.lutron.grafikeye.shadeZones.description = Comma separated list of zones that are shades +thing-type.config.lutron.grafikeyekeypad.autorelease.label = Auto-release +thing-type.config.lutron.grafikeyekeypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.grafikeyekeypad.integrationId.label = Integration ID +thing-type.config.lutron.grafikeyekeypad.integrationId.description = Address of GRAFIK Eye in the Lutron lighting system +thing-type.config.lutron.grafikeyekeypad.model.label = GRAFIK Eye Keypad Layout +thing-type.config.lutron.grafikeyekeypad.model.description = Number of shade button columns +thing-type.config.lutron.grafikeyekeypad.model.option.0COL = No shade button columns +thing-type.config.lutron.grafikeyekeypad.model.option.1COL = 1 shade button column +thing-type.config.lutron.grafikeyekeypad.model.option.2COL = 2 shade button columns +thing-type.config.lutron.grafikeyekeypad.model.option.3COL = 3 shade button columns +thing-type.config.lutron.greenmode.integrationId.label = Integration ID +thing-type.config.lutron.greenmode.integrationId.description = Address of green mode controller in the Lutron control system +thing-type.config.lutron.greenmode.pollInterval.label = Poll Interval +thing-type.config.lutron.greenmode.pollInterval.description = Poll interval in minutes (0 = polling disabled) +thing-type.config.lutron.hwdimmer.address.label = Address +thing-type.config.lutron.hwdimmer.address.description = Address of dimmer in the Lutron lighting system +thing-type.config.lutron.hwdimmer.defaultLevel.label = Default Level +thing-type.config.lutron.hwdimmer.defaultLevel.description = The default dimmer level to use when turning the light on +thing-type.config.lutron.hwdimmer.fadeTime.label = Fade Time +thing-type.config.lutron.hwdimmer.fadeTime.description = Fade time in seconds to set the light level +thing-type.config.lutron.hwserialbridge.baudRate.label = Baud Rate +thing-type.config.lutron.hwserialbridge.baudRate.description = The baud rate to use for the RS232 connection. Valid values are 300, 600, 1200, 2400, 4800, 9600 (default), 19200, 38400, 57600, and 115200. +thing-type.config.lutron.hwserialbridge.baudRate.option.300 = 300 +thing-type.config.lutron.hwserialbridge.baudRate.option.600 = 600 +thing-type.config.lutron.hwserialbridge.baudRate.option.1200 = 1200 +thing-type.config.lutron.hwserialbridge.baudRate.option.2400 = 2400 +thing-type.config.lutron.hwserialbridge.baudRate.option.4800 = 4800 +thing-type.config.lutron.hwserialbridge.baudRate.option.9600 = 9600 +thing-type.config.lutron.hwserialbridge.baudRate.option.19200 = 19200 +thing-type.config.lutron.hwserialbridge.baudRate.option.38400 = 38400 +thing-type.config.lutron.hwserialbridge.baudRate.option.57600 = 57600 +thing-type.config.lutron.hwserialbridge.baudRate.option.115200 = 115200 +thing-type.config.lutron.hwserialbridge.serialPort.label = HomeWorks Bridge Serial Port +thing-type.config.lutron.hwserialbridge.serialPort.description = The serial port name for the HomeWorks processor. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux. +thing-type.config.lutron.hwserialbridge.updateTime.label = Update Processor Time +thing-type.config.lutron.hwserialbridge.updateTime.description = The older HomeWorks processors seem to have difficulty keeping track of the time, especially where daylight savings is concerned. If this option is selected, the HomeWorks bridge will automatically update the processor on initialization and once per day thereafter. +thing-type.config.lutron.intlkeypad.autorelease.label = Auto-release +thing-type.config.lutron.intlkeypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.intlkeypad.integrationId.label = Integration ID +thing-type.config.lutron.intlkeypad.integrationId.description = Address of keypad in the Lutron lighting system +thing-type.config.lutron.intlkeypad.model.label = Keypad Model +thing-type.config.lutron.intlkeypad.model.description = Keypad/faceplate model number without the system prefix +thing-type.config.lutron.intlkeypad.model.option.2B = 2B +thing-type.config.lutron.intlkeypad.model.option.3B = 3B +thing-type.config.lutron.intlkeypad.model.option.4B = 4B +thing-type.config.lutron.intlkeypad.model.option.5BRL = 5BRL +thing-type.config.lutron.intlkeypad.model.option.6BRL = 6BRL +thing-type.config.lutron.intlkeypad.model.option.7BRL = 7BRL +thing-type.config.lutron.intlkeypad.model.option.8BRL = 8BRL +thing-type.config.lutron.intlkeypad.model.option.10BRL = 10BRL +thing-type.config.lutron.intlkeypad.model.option.Generic = Generic +thing-type.config.lutron.ipbridge.delay.label = Send Delay +thing-type.config.lutron.ipbridge.delay.description = The delay in milliseconds between sending integration commands (for throttling) +thing-type.config.lutron.ipbridge.discoveryFile.label = Discovery Data File +thing-type.config.lutron.ipbridge.discoveryFile.description = File to read device discovery information from (for debugging) +thing-type.config.lutron.ipbridge.heartbeat.label = Keepalive Heartbeat Interval +thing-type.config.lutron.ipbridge.heartbeat.description = The period in minutes between connection heartbeat checks +thing-type.config.lutron.ipbridge.ipAddress.label = IP or Host Name +thing-type.config.lutron.ipbridge.ipAddress.description = The IP or host name of the Lutron integration access point +thing-type.config.lutron.ipbridge.password.label = Password +thing-type.config.lutron.ipbridge.password.description = The user password to log in to the integration access point +thing-type.config.lutron.ipbridge.reconnect.label = Reconnect Interval +thing-type.config.lutron.ipbridge.reconnect.description = The period in minutes that the handler will wait between connection attempts +thing-type.config.lutron.ipbridge.user.label = User Name +thing-type.config.lutron.ipbridge.user.description = The user name to log in to the integration access point +thing-type.config.lutron.keypad.autorelease.label = Auto-release +thing-type.config.lutron.keypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.keypad.integrationId.label = Integration ID +thing-type.config.lutron.keypad.integrationId.description = Address of keypad in the Lutron lighting system +thing-type.config.lutron.keypad.model.label = Keypad Model +thing-type.config.lutron.keypad.model.description = Keypad model number without the system prefix +thing-type.config.lutron.keypad.model.option.H1RLD = H1RLD +thing-type.config.lutron.keypad.model.option.H2RLD = H2RLD +thing-type.config.lutron.keypad.model.option.H3BSRL = H3BSRL +thing-type.config.lutron.keypad.model.option.H3S = H3S +thing-type.config.lutron.keypad.model.option.H4S = H4S +thing-type.config.lutron.keypad.model.option.H5BRL = H5BRL +thing-type.config.lutron.keypad.model.option.H6BRL = H6BRL +thing-type.config.lutron.keypad.model.option.HN1RLD = HN1RLD +thing-type.config.lutron.keypad.model.option.HN2RLD = HN2RLD +thing-type.config.lutron.keypad.model.option.HN3BSRL = HN3BSRL +thing-type.config.lutron.keypad.model.option.HN3S = HN3S +thing-type.config.lutron.keypad.model.option.HN4S = HN4S +thing-type.config.lutron.keypad.model.option.HN5BRL = HN5BRL +thing-type.config.lutron.keypad.model.option.HN6BRL = HN6BRL +thing-type.config.lutron.keypad.model.option.W1RLD = W1RLD +thing-type.config.lutron.keypad.model.option.W2RLD = W2RLD +thing-type.config.lutron.keypad.model.option.W3BD = W3BD +thing-type.config.lutron.keypad.model.option.W3BRL = W3BRL +thing-type.config.lutron.keypad.model.option.W3BSRL = W3BSRL +thing-type.config.lutron.keypad.model.option.W3S = W3S +thing-type.config.lutron.keypad.model.option.W4S = W4S +thing-type.config.lutron.keypad.model.option.W5BRL = W5BRL +thing-type.config.lutron.keypad.model.option.W5BRLIR = W5BRLIR +thing-type.config.lutron.keypad.model.option.W6BRL = W6BRL +thing-type.config.lutron.keypad.model.option.W7B = W7B +thing-type.config.lutron.keypad.model.option.Generic = Generic +thing-type.config.lutron.leapbridge.certValidate.label = Validate SSL Certificates +thing-type.config.lutron.leapbridge.certValidate.description = Validate server SSL certificate +thing-type.config.lutron.leapbridge.delay.label = Send Delay +thing-type.config.lutron.leapbridge.delay.description = The delay in milliseconds between sending integration commands (for throttling) +thing-type.config.lutron.leapbridge.heartbeat.label = Keepalive Heartbeat Interval +thing-type.config.lutron.leapbridge.heartbeat.description = The period in minutes between connection heartbeat checks +thing-type.config.lutron.leapbridge.ipAddress.label = IP or Host Name +thing-type.config.lutron.leapbridge.ipAddress.description = The IP or host name of the Lutron integration access point +thing-type.config.lutron.leapbridge.keystore.label = Keystore File +thing-type.config.lutron.leapbridge.keystore.description = Java keystore containing caseta key and certs +thing-type.config.lutron.leapbridge.keystorePassword.label = Keystore Password +thing-type.config.lutron.leapbridge.keystorePassword.description = Password for the keystore file +thing-type.config.lutron.leapbridge.port.label = TCP Port +thing-type.config.lutron.leapbridge.port.description = The bridge TCP port +thing-type.config.lutron.leapbridge.reconnect.label = Reconnect Interval +thing-type.config.lutron.leapbridge.reconnect.description = The period in minutes that the handler will wait between connection attempts +thing-type.config.lutron.occupancysensor.integrationId.label = Integration ID +thing-type.config.lutron.occupancysensor.integrationId.description = Address of sensor in the Lutron lighting system +thing-type.config.lutron.ogroup.integrationId.label = Integration ID +thing-type.config.lutron.ogroup.integrationId.description = Occupancy group number +thing-type.config.lutron.palladiomkeypad.autorelease.label = Auto-release +thing-type.config.lutron.palladiomkeypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.palladiomkeypad.integrationId.label = Integration ID +thing-type.config.lutron.palladiomkeypad.integrationId.description = Address of keypad in the Lutron lighting system +thing-type.config.lutron.palladiomkeypad.model.label = Keypad Model +thing-type.config.lutron.palladiomkeypad.model.description = Keypad/faceplate model number without the system prefix +thing-type.config.lutron.palladiomkeypad.model.option.2W = 2W +thing-type.config.lutron.palladiomkeypad.model.option.3W = 3W +thing-type.config.lutron.palladiomkeypad.model.option.4W = 4W +thing-type.config.lutron.palladiomkeypad.model.option.RW = RW +thing-type.config.lutron.palladiomkeypad.model.option.22W = 22W +thing-type.config.lutron.palladiomkeypad.model.option.24W = 24W +thing-type.config.lutron.palladiomkeypad.model.option.42W = 42W +thing-type.config.lutron.palladiomkeypad.model.option.44W = 44W +thing-type.config.lutron.palladiomkeypad.model.option.2RW = 2RW +thing-type.config.lutron.palladiomkeypad.model.option.4RW = 4RW +thing-type.config.lutron.palladiomkeypad.model.option.RRW = RRW +thing-type.config.lutron.palladiomkeypad.model.option.Generic = Generic +thing-type.config.lutron.pico.autorelease.label = Auto-release +thing-type.config.lutron.pico.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.pico.integrationId.label = Integration ID +thing-type.config.lutron.pico.integrationId.description = Address of keypad in the Lutron lighting system +thing-type.config.lutron.pico.model.label = Pico Model +thing-type.config.lutron.pico.model.description = Pico model number without the system prefix +thing-type.config.lutron.pico.model.option.2B = 2B +thing-type.config.lutron.pico.model.option.2BRL = 2BRL +thing-type.config.lutron.pico.model.option.3B = 3B +thing-type.config.lutron.pico.model.option.3BRL = 3BRL +thing-type.config.lutron.pico.model.option.4B = 4B +thing-type.config.lutron.pico.model.option.Generic = Generic +thing-type.config.lutron.prgbridge.ipAddress.label = IP or Host Name +thing-type.config.lutron.prgbridge.ipAddress.description = The IP or host name of the PRG access point +thing-type.config.lutron.prgbridge.retryPolling.label = Polling Interval to Try to Reconnect +thing-type.config.lutron.prgbridge.retryPolling.description = Interval (in seconds) to try to (re)connect to the matrix +thing-type.config.lutron.prgbridge.userName.label = User Name +thing-type.config.lutron.prgbridge.userName.description = The user name to log in to the PRG access point (typically "nwk" for connection 1 or "nwk2" for connection 2) +thing-type.config.lutron.qsio.integrationId.label = Integration ID +thing-type.config.lutron.qsio.integrationId.description = Address of QS IO Interface in the HomeWorks QS system +thing-type.config.lutron.ra-dimmer.fadeInSec.label = Fade In (sec) +thing-type.config.lutron.ra-dimmer.fadeInSec.description = Time in seconds dimmer should take when increasing the level +thing-type.config.lutron.ra-dimmer.fadeOutSec.label = Fade Out (sec) +thing-type.config.lutron.ra-dimmer.fadeOutSec.description = Time in seconds dimmer should take when lowering the level +thing-type.config.lutron.ra-dimmer.system.label = System Number +thing-type.config.lutron.ra-dimmer.system.description = System number (bridged systems only). Set to 1 or 2. 0 = NA (default). +thing-type.config.lutron.ra-dimmer.zoneNumber.label = Zone Number +thing-type.config.lutron.ra-dimmer.zoneNumber.description = Assigned Zone Number within the Lutron RadioRA system. +thing-type.config.lutron.ra-phantomButton.buttonNumber.label = Phantom Button Number +thing-type.config.lutron.ra-phantomButton.buttonNumber.description = Phantom Button Number within the Lutron RadioRA system. +thing-type.config.lutron.ra-phantomButton.system.label = System Number +thing-type.config.lutron.ra-phantomButton.system.description = System number (bridged systems only). Set to 1 or 2. 0 = NA (default). +thing-type.config.lutron.ra-rs232.baud.label = Baud Rate +thing-type.config.lutron.ra-rs232.baud.description = Baud Rate (defaults to 9600) +thing-type.config.lutron.ra-rs232.portName.label = Serial Port +thing-type.config.lutron.ra-rs232.portName.description = The serial port to use to communicate with a Lutron RadioRA system +thing-type.config.lutron.ra-switch.system.label = System Number +thing-type.config.lutron.ra-switch.system.description = System number (bridged systems only). Set to 1 or 2. 0 = NA (default). +thing-type.config.lutron.ra-switch.zoneNumber.label = Zone Number +thing-type.config.lutron.ra-switch.zoneNumber.description = Assigned Zone Number within the Lutron RadioRA system. +thing-type.config.lutron.shade.integrationId.label = Integration ID +thing-type.config.lutron.shade.integrationId.description = Address of shade in the Lutron system +thing-type.config.lutron.switch.integrationId.label = Integration ID +thing-type.config.lutron.switch.integrationId.description = Address of switch in the Lutron lighting system +thing-type.config.lutron.sysvar.integrationId.label = Integration ID +thing-type.config.lutron.sysvar.integrationId.description = Integration ID for state variable +thing-type.config.lutron.timeclock.integrationId.label = Integration ID +thing-type.config.lutron.timeclock.integrationId.description = Address of timeclock in the Lutron control system +thing-type.config.lutron.ttkeypad.autorelease.label = Auto-release +thing-type.config.lutron.ttkeypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.ttkeypad.integrationId.label = Integration ID +thing-type.config.lutron.ttkeypad.integrationId.description = Address of keypad in the Lutron lighting system +thing-type.config.lutron.ttkeypad.model.label = Keypad Model +thing-type.config.lutron.ttkeypad.model.description = Keypad model number without the system prefix +thing-type.config.lutron.ttkeypad.model.option.T5RL = T5RL +thing-type.config.lutron.ttkeypad.model.option.T10RL = T10RL +thing-type.config.lutron.ttkeypad.model.option.T15RL = T15RL +thing-type.config.lutron.ttkeypad.model.option.T5CRL = T5CRL +thing-type.config.lutron.ttkeypad.model.option.T10CRL = T10CRL +thing-type.config.lutron.ttkeypad.model.option.T15CRL = T15CRL +thing-type.config.lutron.ttkeypad.model.option.Generic = Generic +thing-type.config.lutron.vcrx.autorelease.label = Auto-release +thing-type.config.lutron.vcrx.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.vcrx.integrationId.label = Integration ID +thing-type.config.lutron.vcrx.integrationId.description = Address of VCRX in the Lutron control system +thing-type.config.lutron.virtualkeypad.autorelease.label = Auto-release +thing-type.config.lutron.virtualkeypad.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.virtualkeypad.integrationId.label = Integration ID +thing-type.config.lutron.virtualkeypad.integrationId.description = Address in the Lutron control system +thing-type.config.lutron.virtualkeypad.model.label = Virtual Keypad Type +thing-type.config.lutron.virtualkeypad.model.description = System type for virtual keypad +thing-type.config.lutron.virtualkeypad.model.option.Caseta = Caseta/RA2 Select Scene Buttons +thing-type.config.lutron.virtualkeypad.model.option.Other = HomeWorks/RadioRA 2/Other +thing-type.config.lutron.wci.autorelease.label = Auto-release +thing-type.config.lutron.wci.autorelease.description = Automatically release pressed buttons +thing-type.config.lutron.wci.integrationId.label = Integration ID +thing-type.config.lutron.wci.integrationId.description = Address of WCI in the Lutron control system + +# channel types + +channel-type.lutron.blindLift.label = Blind Level +channel-type.lutron.blindLift.description = Raise/lower the blind level +channel-type.lutron.blindTilt.label = Blind Tilt +channel-type.lutron.blindTilt.description = Tilt the blinds up/down +channel-type.lutron.button.label = Keypad Button +channel-type.lutron.button.description = Button to trigger a scene or rule +channel-type.lutron.buttonAdvanced.label = Keypad Button +channel-type.lutron.buttonAdvanced.description = Button to trigger a scene or rule +channel-type.lutron.buttonpress.label = Last Button Press +channel-type.lutron.buttonpress.description = Last button pressed +channel-type.lutron.cciState.label = CCI +channel-type.lutron.cciState.description = Contact Closure input +channel-type.lutron.clockmode.label = Timeclock Mode +channel-type.lutron.clockmode.description = Mode number for timeclock +channel-type.lutron.command-type.label = LEAP Command +channel-type.lutron.command-type.description = LEAP command to send (for debugging) +channel-type.lutron.eventindex.label = Timeclock Event Index +channel-type.lutron.eventindex.description = Timeclock event index number +channel-type.lutron.fanControl.label = Fan Speed +channel-type.lutron.fanControl.state.option.OFF = Off +channel-type.lutron.fanControl.state.option.LOW = Low +channel-type.lutron.fanControl.state.option.MEDIUM = Medium +channel-type.lutron.fanControl.state.option.MEDIUMHIGH = MediumHigh +channel-type.lutron.fanControl.state.option.HIGH = High +channel-type.lutron.greenstep.label = Step +channel-type.lutron.greenstep.description = Green mode step number +channel-type.lutron.groupState.label = Occupancy State +channel-type.lutron.groupState.state.option.OCCUPIED = Occupied +channel-type.lutron.groupState.state.option.UNOCCUPIED = Unoccupied +channel-type.lutron.groupState.state.option.UNKNOWN = Unknown +channel-type.lutron.ledIndicator.label = Keypad Button LED Indicator +channel-type.lutron.ledIndicator.description = LED indicator for the associated button +channel-type.lutron.ledIndicatorAdvanced.label = Keypad Button LED Indicator +channel-type.lutron.ledIndicatorAdvanced.description = LED indicator for the associated button +channel-type.lutron.lightDimmer.label = Light Level +channel-type.lutron.lightDimmer.description = Increase/decrease the light level +channel-type.lutron.occupiedState.label = Occupied State +channel-type.lutron.occupiedState.description = Occupancy status +channel-type.lutron.scene.label = Scene Selection +channel-type.lutron.scene.description = Scene selection +channel-type.lutron.scenelock.label = Scene Lock +channel-type.lutron.scenelock.description = Locks/Unlocks the scene +channel-type.lutron.sceneseq.label = Sequence Scenes +channel-type.lutron.sceneseq.description = Adds/Removes sequencing of scenes +channel-type.lutron.schedule.label = Schedule Number +channel-type.lutron.schedule.description = The schedule set on the PRG (0=suspend, 1=weekday, 2=weekend) +channel-type.lutron.shadeControl.label = Shade Level +channel-type.lutron.shadeControl.description = Raise/lower the shade level +channel-type.lutron.sunrisesunset.label = Sunrise/Sunset +channel-type.lutron.sunrisesunset.description = Today's sunrise/sunset time +channel-type.lutron.superschedulebutton.label = Superschedule +channel-type.lutron.superschedulebutton.description = superschedule +channel-type.lutron.superscheduleinfo.label = Super Schedule Number +channel-type.lutron.superscheduleinfo.description = Somenumber +channel-type.lutron.superschedulestatus.label = Super Schedule Status +channel-type.lutron.superschedulestatus.description = Status of the Super Schedule +channel-type.lutron.switchState.label = Switch State +channel-type.lutron.switchState.description = On/off status of the switch +channel-type.lutron.timeROAdvanced.label = DateTime +channel-type.lutron.timeROAdvanced.description = Advanced read-only DateTime +channel-type.lutron.timeclock.label = Time Clock +channel-type.lutron.timeclock.description = Current time on the PRG +channel-type.lutron.varstateType.label = Variable State +channel-type.lutron.varstateType.description = System variable state +channel-type.lutron.zonefade.label = Zone Fade (in Seconds) +channel-type.lutron.zonefade.description = Specifies the fade (in seconds [truncated to nearest minute if more than 60 seconds]) when applying intensity changes +channel-type.lutron.zoneintensity.label = Zone Intensity +channel-type.lutron.zoneintensity.description = Specifies the intensity of the zone +channel-type.lutron.zonelock.label = Zone Lockout +channel-type.lutron.zonelock.description = Locks/Unlocks the zone +channel-type.lutron.zonerampdown.label = Ramps Down the Zone +channel-type.lutron.zonerampdown.description = Starts ramping down the zone +channel-type.lutron.zonerampup.label = Ramps up the Zone +channel-type.lutron.zonerampup.description = Starts ramping up the zone +channel-type.lutron.zoneshade.label = Zone Shade +channel-type.lutron.zoneshade.description = Specifies the QED shade for the zone diff --git a/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/i18n/magentatv.properties b/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/i18n/magentatv.properties new file mode 100644 index 0000000000000..5093563ebbd01 --- /dev/null +++ b/bundles/org.openhab.binding.magentatv/src/main/resources/OH-INF/i18n/magentatv.properties @@ -0,0 +1,118 @@ +# binding + +binding.magentatv.name = MagentaTV Binding +binding.magentatv.description = This is the binding for MagentaTV receivers + +# thing types + +thing-type.magentatv.receiver.label = MagentaTV Media Receiver +thing-type.magentatv.receiver.description = Represents a Telekom Media Receiver for MagentaTV +thing-type.magentatv.receiver.group.control.label = Control +thing-type.magentatv.receiver.group.program.label = Program Information +thing-type.magentatv.receiver.group.status.label = Play Status + +# thing types config + +thing-type.config.magentatv.receiver.accountName.label = Account Name +thing-type.config.magentatv.receiver.accountName.description = Credentials: Login name (e.g. xxx@t-online.de, same as for the Telekom Kundencenter) +thing-type.config.magentatv.receiver.accountPassword.label = Account Password +thing-type.config.magentatv.receiver.accountPassword.description = Credentials: Account Password (same as for the Telekom Kundencenter) +thing-type.config.magentatv.receiver.ipAddress.label = Device IP Address +thing-type.config.magentatv.receiver.ipAddress.description = IP address of the receiver +thing-type.config.magentatv.receiver.port.label = Port +thing-type.config.magentatv.receiver.port.description = Port address for UPnP +thing-type.config.magentatv.receiver.udn.label = Unique Device Name +thing-type.config.magentatv.receiver.udn.description = The UDN identifies the Media Receiver +thing-type.config.magentatv.receiver.userId.label = User ID +thing-type.config.magentatv.receiver.userId.description = Technical User ID required for pairing process + +# channel group types + +channel-group-type.magentatv.control.label = Control +channel-group-type.magentatv.control.description = Control function for your Media Receiver +channel-group-type.magentatv.program.label = Program Information +channel-group-type.magentatv.program.description = Information on the running program +channel-group-type.magentatv.status.label = Play Status +channel-group-type.magentatv.status.description = Status information on media play + +# channel types + +channel-type.magentatv.channelCode.label = Channel Code +channel-type.magentatv.channelCode.description = Channel code in the channel list +channel-type.magentatv.channelNumber.label = Channel +channel-type.magentatv.channelNumber.description = Send channel number to switch program +channel-type.magentatv.key.label = Key +channel-type.magentatv.key.description = Send Key to the Media Receive (POWER/MENU/INFO... - see documentation) +channel-type.magentatv.key.command.option.POWER = POWER +channel-type.magentatv.key.command.option.HELP = Help +channel-type.magentatv.key.command.option.INFO = Info +channel-type.magentatv.key.command.option.MENU = Menu +channel-type.magentatv.key.command.option.EPG = EPG +channel-type.magentatv.key.command.option.TTEXT = TeleText +channel-type.magentatv.key.command.option.PORTAL = Portal +channel-type.magentatv.key.command.option.STAR = * +channel-type.magentatv.key.command.option.POUND = # +channel-type.magentatv.key.command.option.SPACE = Space +channel-type.magentatv.key.command.option.OK = Ok +channel-type.magentatv.key.command.option.ENTER = Enter +channel-type.magentatv.key.command.option.BACK = Back +channel-type.magentatv.key.command.option.DELETE = Delete +channel-type.magentatv.key.command.option.EXIT = Exit +channel-type.magentatv.key.command.option.OPTION = Opt +channel-type.magentatv.key.command.option.SETTINGS = Settings +channel-type.magentatv.key.command.option.UP = Up +channel-type.magentatv.key.command.option.DOWN = Down +channel-type.magentatv.key.command.option.LEFT = Left +channel-type.magentatv.key.command.option.RIGHT = Right +channel-type.magentatv.key.command.option.PGUP = Page Up +channel-type.magentatv.key.command.option.PGDOWN = Page Down +channel-type.magentatv.key.command.option.FAV = Favorites +channel-type.magentatv.key.command.option.RED = red +channel-type.magentatv.key.command.option.GREEN = green +channel-type.magentatv.key.command.option.YELLOW = yellow +channel-type.magentatv.key.command.option.BLUE = blue +channel-type.magentatv.key.command.option.SEARCH = Search +channel-type.magentatv.key.command.option.NEXT = Next +channel-type.magentatv.key.command.option.VOLUP = VolUp +channel-type.magentatv.key.command.option.VOLDOWN = VolDown +channel-type.magentatv.key.command.option.MUTE = Mute +channel-type.magentatv.key.command.option.CHUP = ChanUp +channel-type.magentatv.key.command.option.CHDOWN = ChanDown +channel-type.magentatv.key.command.option.LASTCH = Last Channel +channel-type.magentatv.key.command.option.NEXTCH = Next Channel +channel-type.magentatv.key.command.option.PREVCH = Prev Channel +channel-type.magentatv.key.command.option.BEGIN = Go Begin +channel-type.magentatv.key.command.option.END = Go End +channel-type.magentatv.key.command.option.PLAY = Play +channel-type.magentatv.key.command.option.PAUSE = Pause +channel-type.magentatv.key.command.option.REWIND = Rewind +channel-type.magentatv.key.command.option.FORWARD = Forward +channel-type.magentatv.key.command.option.PREVCHAP = Prev Chapter +channel-type.magentatv.key.command.option.NEXTCHAP = Next Chapter +channel-type.magentatv.key.command.option.TRACK = Track +channel-type.magentatv.key.command.option.REPLAY = Replay +channel-type.magentatv.key.command.option.SKIP = Skip +channel-type.magentatv.key.command.option.STOP = Stop +channel-type.magentatv.key.command.option.RECORD = Record +channel-type.magentatv.key.command.option.SUBTITLES = Sub Titles +channel-type.magentatv.key.command.option.MEDIA = Media +channel-type.magentatv.key.command.option.INTER = Interaction +channel-type.magentatv.key.command.option.SOURCE = Source +channel-type.magentatv.key.command.option.SWITCH = Switch IPTV/DVB +channel-type.magentatv.key.command.option.IPTV = IPTV +channel-type.magentatv.key.command.option.PIP = PIP +channel-type.magentatv.key.command.option.MULTIVIEW = Multi View +channel-type.magentatv.playMode.label = Play Mode +channel-type.magentatv.playMode.description = Play Mode for running program +channel-type.magentatv.programDuration.label = Duration +channel-type.magentatv.programDuration.description = Duration of the program +channel-type.magentatv.programPosition.label = Play Position +channel-type.magentatv.programPosition.description = Play Position since program started +channel-type.magentatv.programStart.label = Start +channel-type.magentatv.programStart.description = Program start time +channel-type.magentatv.programText.label = Description +channel-type.magentatv.programText.description = Some info on the running program +channel-type.magentatv.programTitle.label = Program +channel-type.magentatv.programTitle.description = Running program +channel-type.magentatv.runStatus.label = Status +channel-type.magentatv.runStatus.description = Run status diff --git a/bundles/org.openhab.binding.mcp23017/src/main/resources/OH-INF/i18n/mcp23017.properties b/bundles/org.openhab.binding.mcp23017/src/main/resources/OH-INF/i18n/mcp23017.properties new file mode 100644 index 0000000000000..cc1bf3185e2c2 --- /dev/null +++ b/bundles/org.openhab.binding.mcp23017/src/main/resources/OH-INF/i18n/mcp23017.properties @@ -0,0 +1,48 @@ +# binding + +binding.mcp23017.name = MCP23017 Binding +binding.mcp23017.description = This is the binding for MCP23017 I/O expansion chips. + +# thing types + +thing-type.mcp23017.mcp23017.label = MCP23017 +thing-type.mcp23017.mcp23017.description = Thing for mcp23017 integrated circuit + +# thing types config + +thing-type.config.mcp23017.mcp23017.address.label = I2C Device Address +thing-type.config.mcp23017.mcp23017.address.description = I2C Bus mcp2317 device Address in HEX +thing-type.config.mcp23017.mcp23017.bus_number.label = I2C BUS Number +thing-type.config.mcp23017.mcp23017.bus_number.description = I2C Bus number (0-6) +thing-type.config.mcp23017.mcp23017.bus_number.option.0 = 0 +thing-type.config.mcp23017.mcp23017.bus_number.option.1 = 1 +thing-type.config.mcp23017.mcp23017.bus_number.option.2 = 2 +thing-type.config.mcp23017.mcp23017.bus_number.option.3 = 3 +thing-type.config.mcp23017.mcp23017.bus_number.option.4 = 4 +thing-type.config.mcp23017.mcp23017.bus_number.option.5 = 5 +thing-type.config.mcp23017.mcp23017.bus_number.option.6 = 6 + +# channel group types + +channel-group-type.mcp23017.inputgroup.label = Input Pins +channel-group-type.mcp23017.inputgroup.description = MCP 23017 pins working in DIGITAL_INPUT mode (contact) +channel-group-type.mcp23017.outputgroup.label = Output Pins +channel-group-type.mcp23017.outputgroup.description = MCP 23017 pins working in DIGITAL_OUTPUT mode (switch) + +# channel types + +channel-type.mcp23017.input_pin.label = Input Pin +channel-type.mcp23017.input_pin.description = channel type for MCP23017 pin in DIGITAL_INPUT mode (contact) +channel-type.mcp23017.output_pin.label = Output Pin +channel-type.mcp23017.output_pin.description = channel type for MCP23017 pin in DIGITAL_INPUT mode (switch) + +# channel types config + +channel-type.config.mcp23017.input_pin.pull_mode.label = PullResistor Mode +channel-type.config.mcp23017.input_pin.pull_mode.description = mcp2317 input pull resistor mode +channel-type.config.mcp23017.input_pin.pull_mode.option.OFF = OFF +channel-type.config.mcp23017.input_pin.pull_mode.option.PULL_UP = Internal PULL_UP +channel-type.config.mcp23017.output_pin.default_state.label = Default State +channel-type.config.mcp23017.output_pin.default_state.description = mcp2317 pin default state (LOW, HIGH) +channel-type.config.mcp23017.output_pin.default_state.option.LOW = LOW +channel-type.config.mcp23017.output_pin.default_state.option.HIGH = HIGH diff --git a/bundles/org.openhab.binding.mecmeter/src/main/resources/OH-INF/i18n/mecmeter.properties b/bundles/org.openhab.binding.mecmeter/src/main/resources/OH-INF/i18n/mecmeter.properties new file mode 100644 index 0000000000000..6c87ffa78ab97 --- /dev/null +++ b/bundles/org.openhab.binding.mecmeter/src/main/resources/OH-INF/i18n/mecmeter.properties @@ -0,0 +1,152 @@ +# binding + +binding.mecmeter.name = mecMeter Binding +binding.mecmeter.description = This is the binding for the din-rail power meter from MEC. + +# thing types + +thing-type.mecmeter.meter.label = mecMeter +thing-type.mecmeter.meter.description = Power Meter from MEC + +# thing types config + +thing-type.config.mecmeter.meter.ip.label = IP +thing-type.config.mecmeter.meter.ip.description = The IP address of the mecMeter +thing-type.config.mecmeter.meter.password.label = Password +thing-type.config.mecmeter.meter.password.description = Enter the password +thing-type.config.mecmeter.meter.refreshInterval.label = Refresh Interval +thing-type.config.mecmeter.meter.refreshInterval.description = Refresh interval in seconds, default 5 seconds, range 1 to 300 seconds + +# channel group types + +channel-group-type.mecmeter.activefundpower_group.label = Active Fund Power +channel-group-type.mecmeter.activefundpower_group.channel.activefundpower_phase1.label = Active Fund Power P1 +channel-group-type.mecmeter.activefundpower_group.channel.activefundpower_phase2.label = Active Fund Power P2 +channel-group-type.mecmeter.activefundpower_group.channel.activefundpower_phase3.label = Active Fund Power P3 +channel-group-type.mecmeter.activeharmpower_group.label = Active Harm Power +channel-group-type.mecmeter.activeharmpower_group.channel.activeharmpower_phase1.label = Active Harm Power P1 +channel-group-type.mecmeter.activeharmpower_group.channel.activeharmpower_phase2.label = Active Harm Power P2 +channel-group-type.mecmeter.activeharmpower_group.channel.activeharmpower_phase3.label = Active Harm Power P3 +channel-group-type.mecmeter.activepower_group.label = Active Power +channel-group-type.mecmeter.activepower_group.channel.activepower_phase1.label = Active Power P1 +channel-group-type.mecmeter.activepower_group.channel.activepower_phase2.label = Active Power P2 +channel-group-type.mecmeter.activepower_group.channel.activepower_phase3.label = Active Power P3 +channel-group-type.mecmeter.angle_group.label = Angles +channel-group-type.mecmeter.angle_group.channel.phase_angle_currvolt_phase1.label = Angle Current to P1 +channel-group-type.mecmeter.angle_group.channel.phase_angle_currvolt_phase2.label = Angle Current to P2 +channel-group-type.mecmeter.angle_group.channel.phase_angle_currvolt_phase3.label = Angle Current to P3 +channel-group-type.mecmeter.app_energy_group.label = Apparent Energy +channel-group-type.mecmeter.app_energy_group.channel.appenergy_consumption_phase1.label = Apparent Energy P1 +channel-group-type.mecmeter.app_energy_group.channel.appenergy_consumption_phase2.label = Apparent Energy P2 +channel-group-type.mecmeter.app_energy_group.channel.appenergy_consumption_phase3.label = Apparent Energy P3 +channel-group-type.mecmeter.apppower_group.label = Apparent Power +channel-group-type.mecmeter.apppower_group.channel.apppower_phase1.label = Apparent Power P1 +channel-group-type.mecmeter.apppower_group.channel.apppower_phase2.label = Apparent Power P2 +channel-group-type.mecmeter.apppower_group.channel.apppower_phase3.label = Apparent Power P3 +channel-group-type.mecmeter.current_group.label = Current +channel-group-type.mecmeter.current_group.channel.current_phase1.label = Current P1 +channel-group-type.mecmeter.current_group.channel.current_phase2.label = Current P2 +channel-group-type.mecmeter.current_group.channel.current_phase3.label = Current P3 +channel-group-type.mecmeter.fwd_active_energy_group.label = Fwd Active Energy +channel-group-type.mecmeter.fwd_active_energy_group.channel.fwd_active_energy_phase1.label = Fwd Active Energy P1 +channel-group-type.mecmeter.fwd_active_energy_group.channel.fwd_active_energy_phase2.label = Fwd Active Energy P2 +channel-group-type.mecmeter.fwd_active_energy_group.channel.fwd_active_energy_phase3.label = Fwd Active Energy P3 +channel-group-type.mecmeter.fwd_active_fund_energy_group.label = Fwd Active Fund Energy +channel-group-type.mecmeter.fwd_active_fund_energy_group.channel.fwd_active_fund_energy_phase1.label = Fwd Active Fund Energy P1 +channel-group-type.mecmeter.fwd_active_fund_energy_group.channel.fwd_active_fund_energy_phase2.label = Fwd Active Fund Energy P2 +channel-group-type.mecmeter.fwd_active_fund_energy_group.channel.fwd_active_fund_energy_phase3.label = Fwd Active Fund Energy P3 +channel-group-type.mecmeter.fwd_active_harm_energy_group.label = Fwd Active Harm Energy +channel-group-type.mecmeter.fwd_active_harm_energy_group.channel.fwd_active_harm_energy_phase1.label = Fwd Active Harm Energy P1 +channel-group-type.mecmeter.fwd_active_harm_energy_group.channel.fwd_active_harm_energy_phase2.label = Fwd Active Harm Energy P2 +channel-group-type.mecmeter.fwd_active_harm_energy_group.channel.fwd_active_harm_energy_phase3.label = Fwd Active Harm Energy P3 +channel-group-type.mecmeter.fwd_reactive_energy_group.label = Fwd Reactive Energy +channel-group-type.mecmeter.fwd_reactive_energy_group.channel.fwd_reactive_energy_phase1.label = Fwd Reactive Energy P1 +channel-group-type.mecmeter.fwd_reactive_energy_group.channel.fwd_reactive_energy_phase2.label = Fwd Reactive Energy P2 +channel-group-type.mecmeter.fwd_reactive_energy_group.channel.fwd_reactive_energy_phase3.label = Fwd Reactive Energy P3 +channel-group-type.mecmeter.general_group.label = General Channels +channel-group-type.mecmeter.general_group.description = General Channels +channel-group-type.mecmeter.powerfactor_group.label = Power Factor +channel-group-type.mecmeter.powerfactor_group.channel.powerFactor_phase1.label = Power Factor P1 +channel-group-type.mecmeter.powerfactor_group.channel.powerFactor_phase2.label = Power Factor P2 +channel-group-type.mecmeter.powerfactor_group.channel.powerFactor_phase3.label = Power Factor P3 +channel-group-type.mecmeter.reactivepower_group.label = Reactive Power +channel-group-type.mecmeter.reactivepower_group.channel.reactivepower_phase1.label = Reactive Power P1 +channel-group-type.mecmeter.reactivepower_group.channel.reactivepower_phase2.label = Reactive Power P2 +channel-group-type.mecmeter.reactivepower_group.channel.reactivepower_phase3.label = Reactive Power P3 +channel-group-type.mecmeter.rev_active_energy_group.label = Rev Active Energy +channel-group-type.mecmeter.rev_active_energy_group.channel.rev_active_energy_phase1.label = Rev Active Energy P1 +channel-group-type.mecmeter.rev_active_energy_group.channel.rev_active_energy_phase2.label = Rev Active Energy P2 +channel-group-type.mecmeter.rev_active_energy_group.channel.rev_active_energy_phase3.label = Rev Active Energy P3 +channel-group-type.mecmeter.rev_active_fund_energy_group.label = Rev Active Fund Energy +channel-group-type.mecmeter.rev_active_fund_energy_group.channel.rev_active_fund_energy_phase1.label = Rev Active Fund Energy P1 +channel-group-type.mecmeter.rev_active_fund_energy_group.channel.rev_active_fund_energy_phase2.label = Rev Active Fund Energy P2 +channel-group-type.mecmeter.rev_active_fund_energy_group.channel.rev_active_fund_energy_phase3.label = Rev Active Fund Energy P3 +channel-group-type.mecmeter.rev_active_harm_energy_group.label = Rev Active Harm Energy +channel-group-type.mecmeter.rev_active_harm_energy_group.channel.rev_active_harm_energy_phase1.label = Rev Active Harm Energy P1 +channel-group-type.mecmeter.rev_active_harm_energy_group.channel.rev_active_harm_energy_phase2.label = Rev Active Harm Energy P2 +channel-group-type.mecmeter.rev_active_harm_energy_group.channel.rev_active_harm_energy_phase3.label = Rev Active Harm Energy P3 +channel-group-type.mecmeter.rev_reactive_energy_group.label = Rev Reactive Energy +channel-group-type.mecmeter.rev_reactive_energy_group.channel.rev_reactive_energy_phase1.label = Rev Reactive Energy P1 +channel-group-type.mecmeter.rev_reactive_energy_group.channel.rev_reactive_energy_phase2.label = Rev Reactive Energy P2 +channel-group-type.mecmeter.rev_reactive_energy_group.channel.rev_reactive_energy_phase3.label = Rev Reactive Energy P3 +channel-group-type.mecmeter.voltage_group.label = Voltage +channel-group-type.mecmeter.voltage_group.channel.voltage_phase1.label = Voltage P1 +channel-group-type.mecmeter.voltage_group.channel.voltage_phase2.label = Voltage P2 +channel-group-type.mecmeter.voltage_group.channel.voltage_phase3.label = Voltage P3 + +# channel types + +channel-type.mecmeter.activefundpower.label = Active Fundamental Power +channel-type.mecmeter.activefundpower.description = Active fundamental power +channel-type.mecmeter.activeharmpower.label = Active Harmonic Power +channel-type.mecmeter.activeharmpower.description = Active harmonic power +channel-type.mecmeter.activepower.label = Active Power +channel-type.mecmeter.activepower.description = Active power consumed +channel-type.mecmeter.appenergy_consumption.label = Apparent Energy Consumption +channel-type.mecmeter.appenergy_consumption.description = Apparent Energy Consumption in VArh +channel-type.mecmeter.apppower.label = Apparent Power +channel-type.mecmeter.apppower.description = Apparent power consumed +channel-type.mecmeter.avg_neutral_phase_voltage.label = Average Voltage +channel-type.mecmeter.avg_neutral_phase_voltage.description = Average N – Phase Voltage in Volt +channel-type.mecmeter.avg_phase_phase_voltage.label = Average Phase – Phase Voltage +channel-type.mecmeter.avg_phase_phase_voltage.description = Average Phase – Phase Voltage in Volt +channel-type.mecmeter.current.label = Current +channel-type.mecmeter.current.description = Current in Ampere +channel-type.mecmeter.frequency.label = Main Frequency +channel-type.mecmeter.frequency.description = Frequency in Hertz +channel-type.mecmeter.fwd_active_energy.label = Forward Active Energy +channel-type.mecmeter.fwd_active_energy.description = Forward Active Energy in kWh +channel-type.mecmeter.fwd_active_energy_all.label = Forward Active Energy +channel-type.mecmeter.fwd_active_energy_all.description = Forward Active Energy in kWh +channel-type.mecmeter.fwd_active_energy_allphase.label = Forward Active Energy +channel-type.mecmeter.fwd_active_energy_allphase.description = Forward Active Energy all phase in kWh +channel-type.mecmeter.fwd_active_fund_energy.label = Forward Active Fund. Energy +channel-type.mecmeter.fwd_active_fund_energy.description = Forward Active Fundamental Energy in kWh +channel-type.mecmeter.fwd_active_harm_energy.label = Forward Active Harm. Energy +channel-type.mecmeter.fwd_active_harm_energy.description = Forward Active Harmonic Energy in kWh +channel-type.mecmeter.fwd_reactive_energy.label = Forward Reactive Energy +channel-type.mecmeter.fwd_reactive_energy.description = Forward Reactive Energy in VArh +channel-type.mecmeter.op_time.label = Time in Operation +channel-type.mecmeter.op_time.description = Time in Operation +channel-type.mecmeter.phase_angle.label = Angle Voltage to Voltage +channel-type.mecmeter.phase_angle.description = Angle Voltage to Voltage in Degree +channel-type.mecmeter.phase_angle_currvolt.label = Angle Current to Voltage +channel-type.mecmeter.phase_angle_currvolt.description = Angle Current to Voltage in Degree +channel-type.mecmeter.powerFactor.label = Power Factor +channel-type.mecmeter.powerFactor.description = Power Factor +channel-type.mecmeter.reactivepower.label = Reactive Power +channel-type.mecmeter.reactivepower.description = Reactive power consumed +channel-type.mecmeter.rev_active_energy.label = Reverse Active Energy +channel-type.mecmeter.rev_active_energy.description = Reverse Active Energy in kWh +channel-type.mecmeter.rev_active_energy_all.label = Reverse Active Energy +channel-type.mecmeter.rev_active_energy_all.description = Reverse Active Energy in kWh +channel-type.mecmeter.rev_active_fund_energy.label = Reverse Active Fund. Energy +channel-type.mecmeter.rev_active_fund_energy.description = Reverse Active Fundamental Energy in kWh +channel-type.mecmeter.rev_active_harm_energy.label = Reverse Active Harm. Energy +channel-type.mecmeter.rev_active_harm_energy.description = Reverse Active Harmonic Energy in kWh +channel-type.mecmeter.rev_reactive_energy.label = Reverse Reactive Energy +channel-type.mecmeter.rev_reactive_energy.description = Reverse Reactive Energy in VArh +channel-type.mecmeter.temperature.label = Internal Temperature +channel-type.mecmeter.temperature.description = Internal Temperature of the energy meter +channel-type.mecmeter.voltage.label = Voltage +channel-type.mecmeter.voltage.description = Voltage in Volt diff --git a/bundles/org.openhab.binding.melcloud/src/main/resources/OH-INF/i18n/melcloud.properties b/bundles/org.openhab.binding.melcloud/src/main/resources/OH-INF/i18n/melcloud.properties new file mode 100644 index 0000000000000..5ee7dfecb2855 --- /dev/null +++ b/bundles/org.openhab.binding.melcloud/src/main/resources/OH-INF/i18n/melcloud.properties @@ -0,0 +1,118 @@ +# binding + +binding.melcloud.name = MELCloud Binding +binding.melcloud.description = Binding for Mitsubishi MELCloud connected A.C. devices. + +# thing types + +thing-type.melcloud.acdevice.label = A.C. Device +thing-type.melcloud.acdevice.description = Air conditioning device +thing-type.melcloud.heatpumpdevice.label = Heatpump Device +thing-type.melcloud.heatpumpdevice.description = Heatpump device +thing-type.melcloud.melcloudaccount.label = MELCloud Account +thing-type.melcloud.melcloudaccount.description = MELCloud cloud service account + +# thing types config + +thing-type.config.melcloud.acdevice.buildingID.label = Building ID +thing-type.config.melcloud.acdevice.buildingID.description = Building ID of the A.C. device. +thing-type.config.melcloud.acdevice.deviceID.label = Device ID +thing-type.config.melcloud.acdevice.deviceID.description = Device ID of the A.C. device +thing-type.config.melcloud.acdevice.pollingInterval.label = Polling Interval +thing-type.config.melcloud.acdevice.pollingInterval.description = Time interval how often poll data from MELCloud +thing-type.config.melcloud.heatpumpdevice.buildingID.label = Building ID +thing-type.config.melcloud.heatpumpdevice.buildingID.description = Building ID of the Heatpump device. +thing-type.config.melcloud.heatpumpdevice.deviceID.label = Device ID +thing-type.config.melcloud.heatpumpdevice.deviceID.description = Device ID of the Heatpump device +thing-type.config.melcloud.heatpumpdevice.pollingInterval.label = Polling Interval +thing-type.config.melcloud.heatpumpdevice.pollingInterval.description = Time interval how often poll data from MELCloud +thing-type.config.melcloud.melcloudaccount.language.label = Language +thing-type.config.melcloud.melcloudaccount.language.description = Language +thing-type.config.melcloud.melcloudaccount.language.option.0 = English +thing-type.config.melcloud.melcloudaccount.language.option.1 = Bulgarian +thing-type.config.melcloud.melcloudaccount.language.option.2 = Czech +thing-type.config.melcloud.melcloudaccount.language.option.3 = Danish +thing-type.config.melcloud.melcloudaccount.language.option.4 = German +thing-type.config.melcloud.melcloudaccount.language.option.5 = Estonian +thing-type.config.melcloud.melcloudaccount.language.option.6 = Spanish +thing-type.config.melcloud.melcloudaccount.language.option.7 = French +thing-type.config.melcloud.melcloudaccount.language.option.8 = Armenian +thing-type.config.melcloud.melcloudaccount.language.option.9 = Latvian +thing-type.config.melcloud.melcloudaccount.language.option.10 = Lithuanian +thing-type.config.melcloud.melcloudaccount.language.option.11 = Hungarian +thing-type.config.melcloud.melcloudaccount.language.option.12 = Dutch +thing-type.config.melcloud.melcloudaccount.language.option.13 = Norwegian +thing-type.config.melcloud.melcloudaccount.language.option.14 = Polish +thing-type.config.melcloud.melcloudaccount.language.option.15 = Portuguese +thing-type.config.melcloud.melcloudaccount.language.option.16 = Russian +thing-type.config.melcloud.melcloudaccount.language.option.17 = Finnish +thing-type.config.melcloud.melcloudaccount.language.option.18 = Swedish +thing-type.config.melcloud.melcloudaccount.language.option.19 = Italian +thing-type.config.melcloud.melcloudaccount.language.option.20 = Ukrainian +thing-type.config.melcloud.melcloudaccount.language.option.21 = Turkish +thing-type.config.melcloud.melcloudaccount.language.option.22 = Greek +thing-type.config.melcloud.melcloudaccount.language.option.23 = Croatian +thing-type.config.melcloud.melcloudaccount.language.option.24 = Romanian +thing-type.config.melcloud.melcloudaccount.language.option.25 = Slovenian +thing-type.config.melcloud.melcloudaccount.password.label = Password +thing-type.config.melcloud.melcloudaccount.password.description = MELCloud password +thing-type.config.melcloud.melcloudaccount.username.label = Username +thing-type.config.melcloud.melcloudaccount.username.description = MELCloud email address + +# channel types + +channel-type.melcloud.fanSpeed-channel.label = Fan Speed +channel-type.melcloud.fanSpeed-channel.description = Fan speed +channel-type.melcloud.fanSpeed-channel.state.option.0 = Auto +channel-type.melcloud.fanSpeed-channel.state.option.1 = 1 +channel-type.melcloud.fanSpeed-channel.state.option.2 = 2 +channel-type.melcloud.fanSpeed-channel.state.option.3 = 3 +channel-type.melcloud.fanSpeed-channel.state.option.4 = 4 +channel-type.melcloud.fanSpeed-channel.state.option.5 = 5 +channel-type.melcloud.forcedHotWaterMode-channel.label = Forced Hot Water Mode +channel-type.melcloud.forcedHotWaterMode-channel.description = If water mode is Heat Now (true) or Auto (false) +channel-type.melcloud.hasPendingCommand-channel.label = Pending Command +channel-type.melcloud.hasPendingCommand-channel.description = Device has a pending command(s) +channel-type.melcloud.lastCommunication-channel.label = Last Communication +channel-type.melcloud.lastCommunication-channel.description = Last communication time between device and MELCloud +channel-type.melcloud.nextCommunication-channel.label = Next Communication +channel-type.melcloud.nextCommunication-channel.description = Next communication time between device and MELCloud +channel-type.melcloud.offline-channel.label = Is Offline +channel-type.melcloud.offline-channel.description = Is device in offline state. +channel-type.melcloud.operationMode-channel.label = Operation Mode +channel-type.melcloud.operationMode-channel.description = Operation mode +channel-type.melcloud.operationMode-channel.state.option.1 = Heat +channel-type.melcloud.operationMode-channel.state.option.2 = Dry +channel-type.melcloud.operationMode-channel.state.option.3 = Cool +channel-type.melcloud.operationMode-channel.state.option.7 = Fan +channel-type.melcloud.operationMode-channel.state.option.8 = Auto +channel-type.melcloud.power-channel.label = Power +channel-type.melcloud.power-channel.description = Power status of device +channel-type.melcloud.roomTemperature-channel.label = Room Temperature +channel-type.melcloud.roomTemperature-channel.description = Room temperature +channel-type.melcloud.roomTemperatureZone1-channel.label = Room Temperature Zone 1 +channel-type.melcloud.roomTemperatureZone1-channel.description = Room temperature for zone 1 +channel-type.melcloud.setTemperature-channel.label = Set Temperature +channel-type.melcloud.setTemperature-channel.description = Set temperature +channel-type.melcloud.setTemperatureZone1-channel.label = Set Temperature Zone 1 +channel-type.melcloud.setTemperatureZone1-channel.description = Set temperature for zone 1 +channel-type.melcloud.tankWaterTemperature-channel.label = Tank Temperature +channel-type.melcloud.tankWaterTemperature-channel.description = Temperature of water i +channel-type.melcloud.vaneHorizontal-channel.label = Vane Horizontal +channel-type.melcloud.vaneHorizontal-channel.description = Vane horizontal +channel-type.melcloud.vaneHorizontal-channel.state.option.0 = Auto +channel-type.melcloud.vaneHorizontal-channel.state.option.1 = 1 +channel-type.melcloud.vaneHorizontal-channel.state.option.2 = 2 +channel-type.melcloud.vaneHorizontal-channel.state.option.3 = 3 +channel-type.melcloud.vaneHorizontal-channel.state.option.4 = 4 +channel-type.melcloud.vaneHorizontal-channel.state.option.5 = 5 +channel-type.melcloud.vaneHorizontal-channel.state.option.12 = Swing +channel-type.melcloud.vaneVertical-channel.label = Vane Vertical +channel-type.melcloud.vaneVertical-channel.description = Vane vertical +channel-type.melcloud.vaneVertical-channel.state.option.0 = Auto +channel-type.melcloud.vaneVertical-channel.state.option.1 = 1 +channel-type.melcloud.vaneVertical-channel.state.option.2 = 2 +channel-type.melcloud.vaneVertical-channel.state.option.3 = 3 +channel-type.melcloud.vaneVertical-channel.state.option.4 = 4 +channel-type.melcloud.vaneVertical-channel.state.option.5 = 5 +channel-type.melcloud.vaneVertical-channel.state.option.7 = Swing diff --git a/bundles/org.openhab.binding.meteostick/src/main/resources/OH-INF/i18n/meteostick.properties b/bundles/org.openhab.binding.meteostick/src/main/resources/OH-INF/i18n/meteostick.properties new file mode 100644 index 0000000000000..3126ff7d28a8b --- /dev/null +++ b/bundles/org.openhab.binding.meteostick/src/main/resources/OH-INF/i18n/meteostick.properties @@ -0,0 +1,65 @@ +# binding + +binding.meteostick.name = MeteoStick Binding +binding.meteostick.description = This is the binding for MeteoStick USB weather station receiver. + +# thing types + +thing-type.meteostick.meteostick_bridge.label = Meteostick USB Receiver +thing-type.meteostick.meteostick_bridge.description = Meteostick USB Receiver +thing-type.meteostick.meteostick_davis_iss.label = Davis Vantage Vue ISS +thing-type.meteostick.meteostick_davis_iss.description = Davis Integrated Sensor Suite + +# thing types config + +thing-type.config.meteostick.meteostick_bridge.mode.label = Frequency Band +thing-type.config.meteostick.meteostick_bridge.mode.description = Specifies the frequency mode including device, region and frequency that Meteostick will use +thing-type.config.meteostick.meteostick_bridge.mode.option.0 = Davis - North America (915MHz) +thing-type.config.meteostick.meteostick_bridge.mode.option.1 = Davis - Europe (868MHz) +thing-type.config.meteostick.meteostick_bridge.mode.option.2 = Davis - Australia (915Mhz) +thing-type.config.meteostick.meteostick_bridge.mode.option.3 = Fine Offset - North America (915MHz) +thing-type.config.meteostick.meteostick_bridge.mode.option.4 = Fine Offset - Europe (868MHz) +thing-type.config.meteostick.meteostick_bridge.mode.option.5 = Davis - New Zealand (931.5Mhz) +thing-type.config.meteostick.meteostick_bridge.port.label = Serial Port +thing-type.config.meteostick.meteostick_bridge.port.description = Serial port that the Meteostick is plugged into +thing-type.config.meteostick.meteostick_davis_iss.channel.label = Channel +thing-type.config.meteostick.meteostick_davis_iss.channel.description = Specifies the channel the sensor is using +thing-type.config.meteostick.meteostick_davis_iss.channel.option.1 = Channel 1 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.2 = Channel 2 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.3 = Channel 3 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.4 = Channel 4 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.5 = Channel 5 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.6 = Channel 6 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.7 = Channel 7 +thing-type.config.meteostick.meteostick_davis_iss.channel.option.8 = Channel 8 +thing-type.config.meteostick.meteostick_davis_iss.spoon.label = Spoon +thing-type.config.meteostick.meteostick_davis_iss.spoon.description = Specifies the amount of rain needed to tip spoon + +# channel types + +channel-type.meteostick.humidity.label = Outdoor Humidity +channel-type.meteostick.humidity.description = Current humidity in percent +channel-type.meteostick.indoor-temperature.label = Indoor Temperature +channel-type.meteostick.indoor-temperature.description = Current indoor temperature +channel-type.meteostick.outdoor-temperature.label = Outdoor Temperature +channel-type.meteostick.outdoor-temperature.description = Current outdoor temperature +channel-type.meteostick.pressure.label = Pressure +channel-type.meteostick.pressure.description = Current atmospheric pressure +channel-type.meteostick.rain-currenthour.label = Rainfall (60 Minutes) +channel-type.meteostick.rain-currenthour.description = Rainfall in the last 60 minutes +channel-type.meteostick.rain-lasthour.label = Rainfall (previous Hour) +channel-type.meteostick.rain-lasthour.description = Rainfall in the previous hour +channel-type.meteostick.rain-raw.label = Rainfall (Raw) +channel-type.meteostick.rain-raw.description = A counter between 0 and 255 in spoon-sized steps +channel-type.meteostick.solar-power.label = Solar Power +channel-type.meteostick.solar-power.description = Solar panel power percentage +channel-type.meteostick.wind-direction-last2min-average.label = Wind Direction (Average) +channel-type.meteostick.wind-direction-last2min-average.description = Wind direction average over last two minutes +channel-type.meteostick.wind-direction.label = Wind Direction +channel-type.meteostick.wind-direction.description = Wind direction +channel-type.meteostick.wind-speed-last2min-average.label = Wind Speed (Average) +channel-type.meteostick.wind-speed-last2min-average.description = Wind speed average over last two minutes +channel-type.meteostick.wind-speed-last2min-maximum.label = Wind Speed (Maximum) +channel-type.meteostick.wind-speed-last2min-maximum.description = Wind speed maximum over last two minutes +channel-type.meteostick.wind-speed.label = Wind Speed +channel-type.meteostick.wind-speed.description = Wind speed diff --git a/bundles/org.openhab.binding.mihome/src/main/resources/OH-INF/i18n/mihome.properties b/bundles/org.openhab.binding.mihome/src/main/resources/OH-INF/i18n/mihome.properties new file mode 100644 index 0000000000000..ed99edd0e7f8e --- /dev/null +++ b/bundles/org.openhab.binding.mihome/src/main/resources/OH-INF/i18n/mihome.properties @@ -0,0 +1,156 @@ +# binding + +binding.mihome.name = Xiaomi Mi Smart Home Binding +binding.mihome.description = Connects to Xiaomi Smart Gateway v2 and allows to communicate with Xiaomi Mi Smart Home suite (also called Xiaomi Aqara). The Gateway connects with a range of Xiaomi Zigbee sensors such as Wireless Switches, Wall Plugs or Temperature Sensors. + +# thing types + +thing-type.mihome.86sw1.label = Xiaomi Aqara 1 Channel Smart Light Control +thing-type.mihome.86sw1.description = Battery powered Aqara Switch with 1 Channel +thing-type.mihome.86sw1.channel.ch1.label = Button +thing-type.mihome.86sw1.channel.ch1.description = The pushbutton on the switch +thing-type.mihome.86sw2.label = Xiaomi Aqara 2 Channel Smart Light Control +thing-type.mihome.86sw2.description = Battery powered Aqara Switch with 2 channels +thing-type.mihome.86sw2.channel.ch1.label = First Button +thing-type.mihome.86sw2.channel.ch1.description = The first pushbutton on the switch +thing-type.mihome.86sw2.channel.ch2.label = Second Button +thing-type.mihome.86sw2.channel.ch2.description = The second pushbutton on the switch +thing-type.mihome.86sw2.channel.dual_ch.label = Both Buttons Pressed +thing-type.mihome.86sw2.channel.dual_ch.description = Fires when both buttons are pressed simultaneously +thing-type.mihome.basic.label = Basic Xiaomi MiHome Device +thing-type.mihome.basic.description = This device is not supported by the binding but you can still add it to your openHAB configuration. All messages from the device are available as channels providing values to String Items. Please open an issue on the openhab-addons2 GitHub page to get this device added to the binding in the future. Meanwhile you can parse the messages with rules and/or JSONPATH transformations. +thing-type.mihome.basic.channel.heartbeatMessage.label = Last Heartbeat Message +thing-type.mihome.basic.channel.heartbeatMessage.description = Alive signal (up to every 60 minutes) +thing-type.mihome.basic.channel.lastMessage.label = Last Raw Message +thing-type.mihome.basic.channel.lastMessage.description = Last raw message from the device +thing-type.mihome.basic.channel.readAckMessage.label = Last Read Acknowledgement Message +thing-type.mihome.basic.channel.readAckMessage.description = Answer to an active read request +thing-type.mihome.basic.channel.reportMessage.label = Last Report Message +thing-type.mihome.basic.channel.reportMessage.description = Report state or sensor values +thing-type.mihome.basic.channel.writeAckMessage.label = Last Write Acknowledgement Message +thing-type.mihome.basic.channel.writeAckMessage.description = Answer to a command +thing-type.mihome.basic.channel.writeMessage.label = Last Command Parameters +thing-type.mihome.basic.channel.writeMessage.description = Channel to write command parameters - Example: \"join_permission\":\"yes\" +thing-type.mihome.bridge.label = Xiaomi Mi Smart Home Bridge +thing-type.mihome.bridge.description = Multifunctional Gateway - a bridge for the sensors +thing-type.mihome.ctrl_ln1.label = Xiaomi "zero-fire" 1 Channel Wall Switch +thing-type.mihome.ctrl_ln1.channel.ch1.description = The pushbutton on the switch. +thing-type.mihome.ctrl_ln2.label = Xiaomi "zero-fire" 2 Channel Wall Switch +thing-type.mihome.ctrl_ln2.channel.ch1.label = Button 1 +thing-type.mihome.ctrl_ln2.channel.ch1.description = The first pushbutton on the switch. +thing-type.mihome.ctrl_ln2.channel.ch2.label = Button 2 +thing-type.mihome.ctrl_ln2.channel.ch2.description = The second pushbutton on the switch. +thing-type.mihome.ctrl_neutral1.label = Xiaomi Aqara 1 Channel Wall Switch +thing-type.mihome.ctrl_neutral1.description = Mains powered Aqara Switch with 1 controllable Channel +thing-type.mihome.ctrl_neutral1.channel.ch1.description = The pushbutton on the switch. +thing-type.mihome.ctrl_neutral2.label = Xiaomi Aqara 2 Channel Wall Switch +thing-type.mihome.ctrl_neutral2.description = Mains powered Aqara Switch with 2 controllable Channels +thing-type.mihome.ctrl_neutral2.channel.ch1.label = Button 1 +thing-type.mihome.ctrl_neutral2.channel.ch1.description = The first pushbutton on the switch. +thing-type.mihome.ctrl_neutral2.channel.ch2.label = Button 2 +thing-type.mihome.ctrl_neutral2.channel.ch2.description = The second pushbutton on the switch. +thing-type.mihome.curtain.label = Xiaomi Aqara Intelligent Curtain Motor +thing-type.mihome.curtain.description = Smart curtain controller for drawing back and forth fabric curtains. It has manual and remote operation modes. +thing-type.mihome.gateway.label = Xiaomi Mi Smart Home Gateway +thing-type.mihome.gateway.description = Multifunctional Gateway with a built in light, ambient light sensor and capability to play sounds. +thing-type.mihome.natgas.label = Xiaomi Gas Sensor +thing-type.mihome.sensor_cube.label = Xiaomi Mi Smart Cube +thing-type.mihome.sensor_cube.description = Multifunctional controller equipped with an accelerometer and a gyroscope. Triggers the following actions: move, rotate right, rotate left, flip 90, flip 180, tap twice, shake air, free fall, alert. +thing-type.mihome.sensor_ht.label = Xiaomi Mi Temperature & Humidity Sensor +thing-type.mihome.sensor_ht.description = Reports temperature and humidity. Operating temperature: −20°C to 60°C. Operating humidity: 0 to 100%. Sensor reports the temperature when there's a difference of around 0.5°C. If there is no significant temperature change then the sensor reports temperature once every 50 minutes. +thing-type.mihome.sensor_lock_aq1.label = Aqara Fingerprint Door Lock +thing-type.mihome.sensor_lock_aq1.description = Live fingerprint unlock, password unlock, proximity card unlock, key unlock. +thing-type.mihome.sensor_lock_aq1.channel.isOpen.label = Open Alarm +thing-type.mihome.sensor_lock_aq1.channel.wrongAccess.label = Wrong Access Alarm +thing-type.mihome.sensor_magnet.label = Xiaomi Door/Window Sensor +thing-type.mihome.sensor_magnet.description = Contact sensor mounted on doors or windows. Detects states: open and closed. +thing-type.mihome.sensor_magnet_aq2.label = Xiaomi Aqara Door/Window Sensor +thing-type.mihome.sensor_magnet_aq2.description = Contact sensor mounted on doors or windows. Detects states: open and closed. +thing-type.mihome.sensor_motion.label = Xiaomi Mi Motion Sensor +thing-type.mihome.sensor_motion.description = Sensor that detects movement. Also called Occupancy Sensor or Human Body Sensor. After it detects motion, it goes to sleep for 1 minute. +thing-type.mihome.sensor_motion_aq2.label = Xiaomi Aqara Motion Sensor +thing-type.mihome.sensor_motion_aq2.description = Sensor that detects movement. Also called Occupancy Sensor or Human Body Sensor. After it detects motion, it goes to sleep for 1 minute. +thing-type.mihome.sensor_plug.label = Xiaomi Mi Smart Socket Plug +thing-type.mihome.sensor_plug.description = Allows you to enable or disable the socket, read voltage, current and power consumption. +thing-type.mihome.sensor_switch.label = Xiaomi Mi Wireless Switch +thing-type.mihome.sensor_switch.description = Round-shaped mini wireless switch that allows to trigger four types of event: single click, double click, long click press and long click release. +thing-type.mihome.sensor_switch_aq2.label = Xiaomi Aqara Wireless Switch +thing-type.mihome.sensor_switch_aq2.description = Square-shaped mini wireless switch that allows to trigger four types of event: single click, double click, long click press and long click release. +thing-type.mihome.sensor_vibration.label = Aqara Vibration Sensor +thing-type.mihome.sensor_vibration.description = Incorporates high-precision six-axis acceleration and gyroscopes, used for collecting external vibration and motion data. Used to monitor the door and windows with status, important items alarmed, and can also monitor user's bed activity, to help determine the quality of sleep. Installation: Click the reset button on the sensor in the selected sensor installation location. +thing-type.mihome.sensor_weather_v1.label = Xiaomi Aqara Temperature, Humidity & Pressure Sensor +thing-type.mihome.sensor_weather_v1.description = Reports temperature and humidity. Operating temperature: −20°C to 60°C. Operating humidity: 0 to 100%. Sensor reports the temperature when there's a difference of around 0.5°C. If there is no significant temperature change then the sensor reports temperature once every 50 minutes. +thing-type.mihome.sensor_wleak_aq1.label = Xiaomi Water Leak Sensor +thing-type.mihome.smoke.label = Xiaomi Smoke Sensor + +# thing types config + +bridge-type.config.mihome.bridge.interface.label = Interface +bridge-type.config.mihome.bridge.interface.description = Interface to bind to for the MiHome communication channel +bridge-type.config.mihome.bridge.ipAddress.label = Network Address +bridge-type.config.mihome.bridge.ipAddress.description = Network address of this Xiaomi bridge +bridge-type.config.mihome.bridge.key.label = Developer Key +bridge-type.config.mihome.bridge.key.description = Developer key extracted from Xiaomi's app +bridge-type.config.mihome.bridge.port.label = Port +bridge-type.config.mihome.bridge.port.description = Port of the MiHome communication channel +bridge-type.config.mihome.bridge.serialNumber.label = Serial Number +bridge-type.config.mihome.bridge.serialNumber.description = Serial number of this Xiaomi bridge +thing-type.config.mihome.device.itemId.label = MiHome Device ID +thing-type.config.mihome.device.itemId.description = The identifier of this MiHome device + +# channel types + +channel-type.mihome.alarm.label = Alarm Trigger +channel-type.mihome.alarm.description = Triggers ALARM event +channel-type.mihome.bedActivity.label = Bed Activity Index +channel-type.mihome.brightness.label = Brightness +channel-type.mihome.brightness.description = The brightness channel allows to control the brightness of a light. It is also possible to switch the light on and off. +channel-type.mihome.button.label = Button Event +channel-type.mihome.button.description = Fires when the button is pressed, double pressed or pressed for a long time (press/release) +channel-type.mihome.color.label = Color +channel-type.mihome.color.description = Control the color of light. +channel-type.mihome.colorTemperature.label = Color Temperature +channel-type.mihome.colorTemperature.description = Allows to control the color temperature of light. +channel-type.mihome.cubeAction.label = Cube Event +channel-type.mihome.curtainControl.label = Curtain +channel-type.mihome.density.label = Particle Density +channel-type.mihome.enableSound.label = Switch to Turn Sound Off When Playing +channel-type.mihome.gas_alarm.label = Gas Detected +channel-type.mihome.humidity.label = Humidity +channel-type.mihome.idNumber.label = ID +channel-type.mihome.illumination.label = Illumination +channel-type.mihome.illumination.description = This channel shows the brightness of the environment of the device. +channel-type.mihome.inUse.label = In Use +channel-type.mihome.isOpen.label = Open Status +channel-type.mihome.isOpenAlarmTimer.label = Alarm Timer +channel-type.mihome.isOpenAlarmTimer.description = Time in seconds, after which ALARM event is triggered, when open (Default 300 sec, Min 30 sec) +channel-type.mihome.lastAction.label = Last Activity (Date/Time) +channel-type.mihome.lastAction.description = Date/time when last action was detected +channel-type.mihome.lastMotion.label = Last Activity (Date/Time) +channel-type.mihome.lastMotion.description = Date/time when last motion was detected +channel-type.mihome.lastOpened.label = Last Time Opened (Date/Time) +channel-type.mihome.lastOpened.description = Date/time when last opened +channel-type.mihome.leak.label = Leak Detected +channel-type.mihome.loadPower.label = Provided Power +channel-type.mihome.motion.label = Motion Status +channel-type.mihome.motionOffTimer.label = Motion Off Timer +channel-type.mihome.motionOffTimer.description = Time in seconds, after which the Motion Switch is set to "OFF" (Default 120 sec, Min 5 sec) +channel-type.mihome.orientationX.label = X Orientation of the Device +channel-type.mihome.orientationY.label = Y Orientation of the Device +channel-type.mihome.orientationZ.label = Z Orientation of the Device +channel-type.mihome.power.label = Power +channel-type.mihome.powerConsumed.label = Power Consumed +channel-type.mihome.pressure.label = Pressure +channel-type.mihome.rawMessage.label = Raw Message +channel-type.mihome.rawMessage.description = Channel for raw messages. No parsing is done on these messages. +channel-type.mihome.rotationAngle.label = Cube Rotation Angle +channel-type.mihome.rotationTime.label = Cube Rotation Time +channel-type.mihome.smoke_alarm.label = Smoke Detected +channel-type.mihome.sound.label = Sound Selector +channel-type.mihome.status.label = Status +channel-type.mihome.sw-btn.label = Button Switch +channel-type.mihome.temperature.label = Temperature +channel-type.mihome.tiltAngle.label = Tilt Angle +channel-type.mihome.vibrationAction.label = Vibration Sensor Action +channel-type.mihome.volume.label = Sound Volume +channel-type.mihome.volume.description = This channel controls the volume of the gateway for playing sounds diff --git a/bundles/org.openhab.binding.mikrotik/src/main/resources/OH-INF/i18n/mikrotik.properties b/bundles/org.openhab.binding.mikrotik/src/main/resources/OH-INF/i18n/mikrotik.properties new file mode 100644 index 0000000000000..6d81401abf2f6 --- /dev/null +++ b/bundles/org.openhab.binding.mikrotik/src/main/resources/OH-INF/i18n/mikrotik.properties @@ -0,0 +1,111 @@ +# binding + +binding.mikrotik.name = Mikrotik Binding +binding.mikrotik.description = This is the binding for integrating Mikrotik RouterOS powered devices (routers, access points, switches, etc) to facilitate WiFi clients and network interface tracking. + +# thing types + +thing-type.mikrotik.interface.label = RouterOS Interface +thing-type.mikrotik.interface.description = A network interface from RouterOS system (ethernet, wifi, vpn, etc.) +thing-type.mikrotik.routeros.label = Mikrotik RouterOS +thing-type.mikrotik.routeros.description = A connection to RouterOS device +thing-type.mikrotik.wifiRegistration.label = RouterOS Wireless Client +thing-type.mikrotik.wifiRegistration.description = A wireless client connected to a RouterOS wireless network (direct or CAPsMAN-managed) + +# thing types config + +thing-type.config.mikrotik.interface.name.label = Interface Name +thing-type.config.mikrotik.interface.name.description = RouterOS Interface name (i.e. ether1) +thing-type.config.mikrotik.routeros.host.label = Hostname +thing-type.config.mikrotik.routeros.host.description = Hostname or IP address of the RouterOS device +thing-type.config.mikrotik.routeros.login.label = Username +thing-type.config.mikrotik.routeros.login.description = The username to access the the RouterOS device +thing-type.config.mikrotik.routeros.password.label = Password +thing-type.config.mikrotik.routeros.password.description = The user password to access the RouterOS device +thing-type.config.mikrotik.routeros.port.label = API Port +thing-type.config.mikrotik.routeros.port.description = API Port number of the RouterOS device +thing-type.config.mikrotik.routeros.refresh.label = Refresh Interval +thing-type.config.mikrotik.routeros.refresh.description = The refresh interval in seconds to poll the RouterOS device +thing-type.config.mikrotik.wifiRegistration.considerContinuous.label = Consider Home Interval +thing-type.config.mikrotik.wifiRegistration.considerContinuous.description = The interval in seconds to treat the client as connected permanently +thing-type.config.mikrotik.wifiRegistration.mac.label = Client MAC +thing-type.config.mikrotik.wifiRegistration.mac.description = WiFi client MAC address +thing-type.config.mikrotik.wifiRegistration.ssid.label = SSID +thing-type.config.mikrotik.wifiRegistration.ssid.description = Constraining SSID for the WiFi client (optional). If client will connect to another SSID, this thing will stay offline until client reconnects to specified SSID. + +# channel types + +channel-type.mikrotik.authorizedClients.label = Authorized Clients +channel-type.mikrotik.authorizedClients.description = Amount of clients authorized by WiFi interface +channel-type.mikrotik.comment.label = Comment +channel-type.mikrotik.comment.description = User-defined comment +channel-type.mikrotik.connected.label = Connected +channel-type.mikrotik.connected.description = Reflects connected or disconnected state +channel-type.mikrotik.continuous.label = Continuous +channel-type.mikrotik.continuous.description = Connection is considered long-running +channel-type.mikrotik.cpuLoad.label = CPU Load % +channel-type.mikrotik.cpuLoad.description = CPU load percentage +channel-type.mikrotik.defaultName.label = Default Name +channel-type.mikrotik.defaultName.description = Interface factory name +channel-type.mikrotik.enabled.label = Enabled +channel-type.mikrotik.enabled.description = Reflects enabled or disabled state +channel-type.mikrotik.ethernetRate.label = Link Rate +channel-type.mikrotik.ethernetRate.description = Ethernet link rate +channel-type.mikrotik.freeMemory.label = Free RAM +channel-type.mikrotik.freeMemory.description = Amount of free memory left on device in bytes +channel-type.mikrotik.freeSpace.label = Free Space +channel-type.mikrotik.freeSpace.description = Amount of free storage left on device in bytes +channel-type.mikrotik.interfaceName.label = Interface Name +channel-type.mikrotik.interfaceName.description = Network interface name +channel-type.mikrotik.interfaceType.label = Interface Type +channel-type.mikrotik.interfaceType.description = Network interface type +channel-type.mikrotik.lastLinkDownTime.label = Last Link Down +channel-type.mikrotik.lastLinkDownTime.description = Last time when link went down +channel-type.mikrotik.lastLinkUpTime.label = Last Link Up +channel-type.mikrotik.lastLinkUpTime.description = Last time when link went up +channel-type.mikrotik.lastSeen.label = Last Seen +channel-type.mikrotik.lastSeen.description = Time of when the client was last seen connected +channel-type.mikrotik.linkDowns.label = Link Downs +channel-type.mikrotik.linkDowns.description = Amount of link downs +channel-type.mikrotik.macAddress.label = MAC Address +channel-type.mikrotik.macAddress.description = MAC address of the client or interface +channel-type.mikrotik.registeredClients.label = Registered Clients +channel-type.mikrotik.registeredClients.description = Amount of clients registered to WiFi interface +channel-type.mikrotik.rxBytes.label = Received Bytes +channel-type.mikrotik.rxBytes.description = Amount of bytes received +channel-type.mikrotik.rxDrops.label = Receiving Drops +channel-type.mikrotik.rxDrops.description = Amount of packets dropped during receiving +channel-type.mikrotik.rxErrors.label = Receiving Errors +channel-type.mikrotik.rxErrors.description = Amount of errors during receiving +channel-type.mikrotik.rxPacketRate.label = Receiving Packet Rate +channel-type.mikrotik.rxPacketRate.description = Rate of data receiving in packets per second +channel-type.mikrotik.rxPackets.label = Received Packets +channel-type.mikrotik.rxPackets.description = Amount of packets received +channel-type.mikrotik.rxRate.label = Receiving Rate +channel-type.mikrotik.rxRate.description = Rate of data receiving in megabits per second +channel-type.mikrotik.ssid.label = WiFi Network +channel-type.mikrotik.ssid.description = Wireless Network (SSID) the wireless client is connected to +channel-type.mikrotik.state.label = State +channel-type.mikrotik.state.description = WiFi interface state +channel-type.mikrotik.totalMemory.label = Total RAM +channel-type.mikrotik.totalMemory.description = Amount of total memory available on device in bytes +channel-type.mikrotik.totalSpace.label = Total Space +channel-type.mikrotik.totalSpace.description = Amount of total storage available on device in bytes +channel-type.mikrotik.txBytes.label = Transmitted Bytes +channel-type.mikrotik.txBytes.description = Amount of bytes transmitted +channel-type.mikrotik.txDrops.label = Transmission Drops +channel-type.mikrotik.txDrops.description = Amount of packets dropped during transmission +channel-type.mikrotik.txErrors.label = Transmission Errors +channel-type.mikrotik.txErrors.description = Amount of errors during transmission +channel-type.mikrotik.txPacketRate.label = Transmission Packet Rate +channel-type.mikrotik.txPacketRate.description = Rate of data transmission in packets per second +channel-type.mikrotik.txPackets.label = Transmitted Packets +channel-type.mikrotik.txPackets.description = Amount of packets transmitted +channel-type.mikrotik.txRate.label = Transmission Rate +channel-type.mikrotik.txRate.description = Rate of data transmission in megabits per second +channel-type.mikrotik.upSince.label = Up since +channel-type.mikrotik.upSince.description = Time when thing got up +channel-type.mikrotik.usedMemory.label = Used RAM % +channel-type.mikrotik.usedMemory.description = Percentage of used device memory +channel-type.mikrotik.usedSpace.label = Used Space % +channel-type.mikrotik.usedSpace.description = Percentage of used device storage space diff --git a/bundles/org.openhab.binding.milight/src/main/resources/OH-INF/i18n/milight.properties b/bundles/org.openhab.binding.milight/src/main/resources/OH-INF/i18n/milight.properties new file mode 100644 index 0000000000000..918d9b26be0fd --- /dev/null +++ b/bundles/org.openhab.binding.milight/src/main/resources/OH-INF/i18n/milight.properties @@ -0,0 +1,102 @@ +# binding + +binding.milight.name = Milight Binding +binding.milight.description = A binding for Milight/Easybulb/compatible white, color and color+white bulbs. + +# thing types + +thing-type.milight.bridgeV3.label = Milight Bridge (first Edition) +thing-type.milight.bridgeV3.description = A Milight/Easybulb bridge. This bridge cannot handle newer light bulbs (2016+) of the aforementioned manufacturers. +thing-type.milight.bridgeV6.label = Milight Bridge (iBox) +thing-type.milight.bridgeV6.description = A bridge for all newer light bulbs (2016+) of the Milight/Easybulb system. +thing-type.milight.rgbLed.label = Color Bulb (first Edition) +thing-type.milight.rgbLed.description = RGB bulb with white channel. No saturation control. If the set saturation is below a threshold of 50%, the bulb turns into white mode. +thing-type.milight.rgbiboxLed.label = Integrated Bulb (iBox) +thing-type.milight.rgbiboxLed.description = Integrated bulb of the ibox bridge with no dedicated white channel and therefore no saturation control +thing-type.milight.rgbv2Led.label = Color Bulb (old) +thing-type.milight.rgbv2Led.description = The oldest produced color bulb. Without a white channel. No saturation support. +thing-type.milight.rgbwLed.label = Color Bulb with Cold White (iBox) +thing-type.milight.rgbwLed.description = Color bulb with white channel for the new Milight/Easybulb system. +thing-type.milight.rgbwwLed.label = Color Bulb with Cold/warm White (iBox) +thing-type.milight.rgbwwLed.description = Color bulb with warm and cold white support for the new Milight/Easybulb system. +thing-type.milight.whiteLed.label = Cold/warm White Bulb (first Edition) +thing-type.milight.whiteLed.description = White bulb for the older bridge (up to 2016) + +# thing types config + +thing-type.config.milight.bridgeV3.bridgeid.label = Bridge ID +thing-type.config.milight.bridgeV3.bridgeid.description = The mac address of the bridge in upper case letters without delimiter. Use this parameter and leave the IP/Hostname empty for DHCP environments where IPs may often change over time. The Bridge ID is also used to check if a given IP corresponds to the right device. The bridge is set offline if the device does not respond with the correct Bridge ID and a re-detection is started. +thing-type.config.milight.bridgeV3.delayTime.label = Wait Between Commands (ms) +thing-type.config.milight.bridgeV3.delayTime.description = Time to wait before sending another command to the bridge. It is safe to have a wait time of 1/10s but usually sufficient to just wait 50ms. If the value is too high, commands queue up. +thing-type.config.milight.bridgeV3.host.label = IP or Host Name +thing-type.config.milight.bridgeV3.host.description = You either need an IP/Hostname or the Bridge ID. +thing-type.config.milight.bridgeV3.port.label = Custom Port +thing-type.config.milight.bridgeV3.port.description = You can set a custom port that will take precedence over the default port which is selected depending on the bridge version: Version 6 uses 5987, Version 3/4/5 uses 8899. Version 2 uses 50000. +thing-type.config.milight.bridgeV3.refreshTime.label = Refresh Interval +thing-type.config.milight.bridgeV3.refreshTime.description = Interval in seconds to check for device presence. The Bridge ID is used to check if the IP is still the right one. +thing-type.config.milight.bridgeV3.repeat.label = Repeat Commands +thing-type.config.milight.bridgeV3.repeat.description = Usually the bridge receives all commands albeit UDP is used. But the actual bulbs might be slightly out of bridge radio range and it sometimes helps to send commands multiple times. +thing-type.config.milight.bridgeV6.bridgeid.label = Bridge ID +thing-type.config.milight.bridgeV6.bridgeid.description = The mac address of the bridge in upper case letters without delimiter. This is used to check if the given IP corresponds to the right device. The bridge is set offline if the device does not respond with the correct Bride ID and a re-detection is started. Useful for DHCP environments where IPs may change over time, after power outage etc. Will be resolved by discovery if auto configured. +thing-type.config.milight.bridgeV6.delayTime.label = Wait Between Commands (ms) +thing-type.config.milight.bridgeV6.delayTime.description = Time to wait before sending another command to the bridge. It is safe to have a wait time of 1/10s but usually sufficient to just wait 50ms. If the value is too high, commands queue up. +thing-type.config.milight.bridgeV6.host.label = IP or Host Name +thing-type.config.milight.bridgeV6.host.description = Will be resolved by discovery if auto configured +thing-type.config.milight.bridgeV6.passwordByte1.label = Password Byte 1 +thing-type.config.milight.bridgeV6.passwordByte1.description = Bridge V6 allows to set two password bytes. A value from 0-255 is allowed. +thing-type.config.milight.bridgeV6.passwordByte2.label = Password Byte 2 +thing-type.config.milight.bridgeV6.passwordByte2.description = Bridge V6 allows to set two password bytes. A value from 0-255 is allowed. +thing-type.config.milight.bridgeV6.port.label = Custom Port +thing-type.config.milight.bridgeV6.port.description = You can set a custom port that will take precedence over the default port which is selected depending on the bridge version: Version 6 uses 5987, Version 3/4/5 uses 8899. Version 2 uses 50000. +thing-type.config.milight.bridgeV6.refreshTime.label = Keep Alive Interval +thing-type.config.milight.bridgeV6.refreshTime.description = Interval in milliseconds to send a keep alive ping. If the value is too high, a session may expire and the bridge and all devices could go offline for a few seconds. +thing-type.config.milight.bridgeV6.repeat.label = Repeat Commands +thing-type.config.milight.bridgeV6.repeat.description = Usually the bridge receives all commands albeit UDP is used. But the actual bulbs might be slightly out of bridge radio range and it sometimes helps to send commands multiple times. +thing-type.config.milight.rgbLed.zone.label = Zone +thing-type.config.milight.rgbLed.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. +thing-type.config.milight.rgbiboxLed.zone.label = Zone +thing-type.config.milight.rgbiboxLed.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. +thing-type.config.milight.rgbv2Led.zone.label = Zone +thing-type.config.milight.rgbv2Led.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. +thing-type.config.milight.rgbwLed.zone.label = Zone +thing-type.config.milight.rgbwLed.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. +thing-type.config.milight.rgbwwLed.zone.label = Zone +thing-type.config.milight.rgbwwLed.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. +thing-type.config.milight.whiteLed.zone.label = Zone +thing-type.config.milight.whiteLed.zone.description = A milight bulb can be assigned to zone 0-4. zone 0 controls all bulbs of that type. + +# channel types + +channel-type.milight.animation_mode.label = Animation Mode +channel-type.milight.animation_mode.description = Animation mode of your LED. RGBWW leds support 9 animation modes. +channel-type.milight.animation_mode.state.option.1 = Animation 1 +channel-type.milight.animation_mode.state.option.2 = Animation 2 +channel-type.milight.animation_mode.state.option.3 = Animation 3 +channel-type.milight.animation_mode.state.option.4 = Animation 4 +channel-type.milight.animation_mode.state.option.5 = Animation 5 +channel-type.milight.animation_mode.state.option.6 = Animation 6 +channel-type.milight.animation_mode.state.option.7 = Animation 7 +channel-type.milight.animation_mode.state.option.8 = Animation 8 +channel-type.milight.animation_mode.state.option.9 = Animation 9 +channel-type.milight.animation_mode_relative.label = Animation Mode +channel-type.milight.animation_mode_relative.description = Switch to the next/previous animation mode of your RGBW or white LED. Bind this to a Next/Previous channel type. +channel-type.milight.animation_speed_relative.label = Animation Speed +channel-type.milight.animation_speed_relative.description = The speed of some animations can be increased or decreased +channel-type.milight.ledbrightness.label = Brightness +channel-type.milight.ledbrightness.description = The brightness can be set in 16 steps for RGBW/White leds and in 64 steps for RGBWW leds +channel-type.milight.ledcolor.label = Color +channel-type.milight.ledcolor.description = Color of the LED. Bind to a Dimmer to just set the brightness, bind to a Color chooser for the full control and bind to a Switch for turning the led on or off. +channel-type.milight.ledlink.label = Link Bulb +channel-type.milight.ledlink.description = Sync bulb to this zone within 3 seconds of light bulb socket power on +channel-type.milight.lednightmode.label = Nightmode +channel-type.milight.lednightmode.description = Switch to night mode, a very dimmed brightness mode +channel-type.milight.lednightmode.state.option.ON = Nightmode +channel-type.milight.ledsaturation.label = Saturation +channel-type.milight.ledsaturation.description = The saturation can be set in 64 steps for RGBWW leds +channel-type.milight.ledtemperature.label = Color Temperature +channel-type.milight.ledtemperature.description = White leds and RGBWW allow to change between a cold and a warm color temperature. White support 16, RGBWW support 64 steps +channel-type.milight.ledunlink.label = Unlink Bulb +channel-type.milight.ledunlink.description = Clear bulb from this zone within 3 seconds of light bulb socket power on +channel-type.milight.ledwhitemode.label = Whitemode +channel-type.milight.ledwhitemode.description = Switch to white mode, which basically sets the saturation to 0 (turns off the color leds) +channel-type.milight.ledwhitemode.state.option.ON = Whitemode diff --git a/bundles/org.openhab.binding.millheat/src/main/resources/OH-INF/i18n/millheat.properties b/bundles/org.openhab.binding.millheat/src/main/resources/OH-INF/i18n/millheat.properties new file mode 100644 index 0000000000000..58b7063f73efa --- /dev/null +++ b/bundles/org.openhab.binding.millheat/src/main/resources/OH-INF/i18n/millheat.properties @@ -0,0 +1,66 @@ +# binding + +binding.millheat.name = Millheat Binding +binding.millheat.description = This is the binding for Mill Heat Wi-Fi enabled heaters. See https://www.millheat.com/mill-wifi/ + +# thing types + +thing-type.millheat.account.label = Mill Heating API +thing-type.millheat.account.description = This bridge represents the gateway to Mill Heating API +thing-type.millheat.heater.label = Wi-Fi Enabled Heater +thing-type.millheat.home.label = Home +thing-type.millheat.room.label = Room with one or more Wi-Fi enabled heaters + +# thing types config + +thing-type.config.millheat.account.password.label = Password +thing-type.config.millheat.account.password.description = Your Millheat app password +thing-type.config.millheat.account.refreshInterval.label = Refresh Interval +thing-type.config.millheat.account.refreshInterval.description = Specifies the refresh time in seconds for polling temperature updates from Millheat service +thing-type.config.millheat.account.username.label = Username +thing-type.config.millheat.account.username.description = Your Millheat app username (email) +thing-type.config.millheat.heater.heaterId.label = Heater ID +thing-type.config.millheat.heater.heaterId.description = Either MAC address or heaterId is required +thing-type.config.millheat.heater.macAddress.label = MAC Address +thing-type.config.millheat.heater.macAddress.description = Either MAC address or heaterId is required +thing-type.config.millheat.heater.power.label = Heating Power +thing-type.config.millheat.heater.power.description = Number of watts this heater is consuming when it is heating. This value is sent to the currentPower channel when the heater is heating in order to track energy usage +thing-type.config.millheat.home.homeId.label = Home ID +thing-type.config.millheat.room.roomId.label = Room ID + +# channel types + +channel-type.millheat.awayTemperature.label = Temperature Away Mode +channel-type.millheat.awayTemperature.description = Set temperature away mode +channel-type.millheat.comfortTemperature.label = Temperature Comfort Mode +channel-type.millheat.currentEnergy.label = Energy Usage +channel-type.millheat.currentEnergy.description = Actual energy usage in watts +channel-type.millheat.currentMode.label = Current Room Program Mode +channel-type.millheat.currentMode.state.option.Comfort = Comfort +channel-type.millheat.currentMode.state.option.Sleep = Sleep +channel-type.millheat.currentMode.state.option.Away = Away +channel-type.millheat.currentMode.state.option.Off = Off +channel-type.millheat.currentMode.state.option.AdvancedAway = Vacation away +channel-type.millheat.currentTemperature.label = Current Temperature +channel-type.millheat.fanActive.label = Fan Active +channel-type.millheat.fanActive.description = Current state of heater fan (if available, OFF if not found) +channel-type.millheat.heatingActive.label = Heating Active +channel-type.millheat.heatingActive.description = Current state of the heater or heaters in room +channel-type.millheat.independent.label = Independent Heater +channel-type.millheat.independent.description = ON if heater is an independent heater and not connected to a room +channel-type.millheat.masterSwitch.label = Master Switch +channel-type.millheat.masterSwitch.description = Master ON/OFF switch for independent heater +channel-type.millheat.program.label = Program +channel-type.millheat.program.description = Program associated with room +channel-type.millheat.sleepTemperature.label = Temperature Sleep Mode +channel-type.millheat.targetTemperatureHeater.label = Target Temperature +channel-type.millheat.targetTemperatureRoom.label = Target Temperature +channel-type.millheat.vacationMode.label = Vacation Mode +channel-type.millheat.vacationMode.description = Toggles vacation mode. Start and end time must be preset before activating +channel-type.millheat.vacationModeAdvanced.label = Advanced Vacation Mode +channel-type.millheat.vacationModeAdvanced.description = Use room Away mode temperatures instead of home global temperature +channel-type.millheat.vacationModeEnd.label = End of Vacation +channel-type.millheat.vacationModeStart.label = Start of Vacation +channel-type.millheat.vacationModeTargetTemperature.label = Target Temperature Vacation +channel-type.millheat.window.label = Window State +channel-type.millheat.window.description = Open window/cold air flow detection diff --git a/bundles/org.openhab.binding.minecraft/src/main/resources/OH-INF/i18n/minecraft.properties b/bundles/org.openhab.binding.minecraft/src/main/resources/OH-INF/i18n/minecraft.properties new file mode 100644 index 0000000000000..d2b74dcc71dfd --- /dev/null +++ b/bundles/org.openhab.binding.minecraft/src/main/resources/OH-INF/i18n/minecraft.properties @@ -0,0 +1,57 @@ +# binding + +binding.minecraft.name = Minecraft Binding +binding.minecraft.description = This binding can integrate Minecraft servers. + +# thing types + +thing-type.minecraft.player.label = Player +thing-type.minecraft.player.description = A connected player connected to the Minecraft server. +thing-type.minecraft.player.channel.playerOnline.label = Online +thing-type.minecraft.player.channel.playerOnline.description = Online status of the player. +thing-type.minecraft.redstoneSign.label = Sign +thing-type.minecraft.redstoneSign.description = A sign with a redstone path under it. +thing-type.minecraft.server.label = Minecraft Bukkit Server +thing-type.minecraft.server.description = Server from which data is being fetched. + +# thing types config + +thing-type.config.minecraft.player.playerName.label = Player Name +thing-type.config.minecraft.player.playerName.description = The name of the player. +thing-type.config.minecraft.redstoneSign.signName.label = Sign Name +thing-type.config.minecraft.redstoneSign.signName.description = The text on the sign. +thing-type.config.minecraft.server.hostname.label = Hostname or IP +thing-type.config.minecraft.server.hostname.description = Hostname or IP of the server. +thing-type.config.minecraft.server.port.label = Port +thing-type.config.minecraft.server.port.description = The port on which the server can be accessed. + +# channel types + +channel-type.minecraft.location.label = Location +channel-type.minecraft.location.description = The location of the player. +channel-type.minecraft.maxPlayers.label = Max Players +channel-type.minecraft.maxPlayers.description = The maxumum number of players on the server. +channel-type.minecraft.online.label = Online +channel-type.minecraft.online.description = Online status of the thing. +channel-type.minecraft.online.state.option.ON = Online +channel-type.minecraft.online.state.option.OFF = Offline +channel-type.minecraft.playerExperiencePercentage.label = Experience +channel-type.minecraft.playerExperiencePercentage.description = Percentage of the experience bar filled for the next level. +channel-type.minecraft.playerGameMode.label = Game Mode +channel-type.minecraft.playerGameMode.description = The players current game mode. +channel-type.minecraft.playerGameMode.state.option.CREATIVE = creative +channel-type.minecraft.playerGameMode.state.option.SURVIVAL = survival +channel-type.minecraft.playerGameMode.state.option.ADVENTURE = adventure +channel-type.minecraft.playerGameMode.state.option.SPECTATOR = spectator +channel-type.minecraft.playerHealth.label = Health +channel-type.minecraft.playerHealth.description = The health of player. +channel-type.minecraft.playerLevel.label = Level +channel-type.minecraft.playerLevel.description = The players current level. +channel-type.minecraft.playerTotalExperience.label = Total Experience +channel-type.minecraft.playerTotalExperience.description = The total experience of the player. +channel-type.minecraft.playerWalkSpeed.label = Speed +channel-type.minecraft.playerWalkSpeed.description = The speed of player. +channel-type.minecraft.players.label = Players +channel-type.minecraft.players.description = The number of players on the server. +channel-type.minecraft.signActive.label = Online +channel-type.minecraft.signActive.description = Shows if the sign has powered redstone below it. diff --git a/bundles/org.openhab.binding.modbus.sbc/src/main/resources/OH-INF/i18n/modbus-sbc.properties b/bundles/org.openhab.binding.modbus.sbc/src/main/resources/OH-INF/i18n/modbus-sbc.properties new file mode 100644 index 0000000000000..f140450e50633 --- /dev/null +++ b/bundles/org.openhab.binding.modbus.sbc/src/main/resources/OH-INF/i18n/modbus-sbc.properties @@ -0,0 +1,2 @@ +thing-type.config.modbus-sbc.ald1.pollInterval.label = Poll Interval +thing-type.config.modbus-sbc.ald1.pollInterval.description = Time between polling the data in ms. diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/OH-INF/i18n/stiebeleltron.properties b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/OH-INF/i18n/stiebeleltron.properties new file mode 100644 index 0000000000000..c703f1c56882c --- /dev/null +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/src/main/resources/OH-INF/i18n/stiebeleltron.properties @@ -0,0 +1,4 @@ +thing-type.config.stiebeleltron.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.stiebeleltron.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.stiebeleltron.modbusconfig.refresh.label = Polling Interval +thing-type.config.stiebeleltron.modbusconfig.refresh.description = Poll interval in seconds. Use zero to disable automatic polling. diff --git a/bundles/org.openhab.binding.modbus.sunspec/src/main/resources/OH-INF/i18n/sunspec.properties b/bundles/org.openhab.binding.modbus.sunspec/src/main/resources/OH-INF/i18n/sunspec.properties new file mode 100644 index 0000000000000..44eba8a60effd --- /dev/null +++ b/bundles/org.openhab.binding.modbus.sunspec/src/main/resources/OH-INF/i18n/sunspec.properties @@ -0,0 +1,8 @@ +thing-type.config.sunspec.modbusconfig.address.label = Start Address +thing-type.config.sunspec.modbusconfig.address.description = Start address of the model block +thing-type.config.sunspec.modbusconfig.length.label = Block Length +thing-type.config.sunspec.modbusconfig.length.description = Length of the model block in 2 byte words +thing-type.config.sunspec.modbusconfig.maxTries.label = Maximum Tries When Reading +thing-type.config.sunspec.modbusconfig.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.sunspec.modbusconfig.refresh.label = Refresh Interval +thing-type.config.sunspec.modbusconfig.refresh.description = Poll interval. Use zero to disable automatic polling. diff --git a/bundles/org.openhab.binding.modbus/src/main/resources/OH-INF/i18n/modbus.properties b/bundles/org.openhab.binding.modbus/src/main/resources/OH-INF/i18n/modbus.properties new file mode 100644 index 0000000000000..99c8761ca1ff0 --- /dev/null +++ b/bundles/org.openhab.binding.modbus/src/main/resources/OH-INF/i18n/modbus.properties @@ -0,0 +1,184 @@ +# binding + +binding.modbus.name = Modbus Binding +binding.modbus.description = Binding for Modbus + +# thing types + +thing-type.modbus.data.label = Modbus Data +thing-type.modbus.data.description = Data thing extracts values from binary data received from Modbus slave. Similarly, it it responsible of tranlating openHAB commands to Modbus write requests +thing-type.modbus.poller.label = Regular Poll +thing-type.modbus.poller.description = Regular poll of data from Modbus slaves +thing-type.modbus.serial.label = Modbus Serial Slave +thing-type.modbus.serial.description = Endpoint for Modbus serial slaves +thing-type.modbus.tcp.label = Modbus TCP Slave +thing-type.modbus.tcp.description = Endpoint for Modbus TCP slaves + +# thing types config + +thing-type.config.modbus.data.readStart.label = Read Address +thing-type.config.modbus.data.readStart.description = Start address to start reading the value. Use empty for write-only things.

Input as zero-based index number, e.g. in place of 400001 (first holding register), use the address 0. Must be between (poller start) and (poller start + poller length - 1) (inclusive).

With registers and value type less than 16 bits, you must use X.Y format where Y specifies the sub-element to read from the 16 bit register:
  • For example, 3.1 would mean pick second bit from register index 3 with bit value type.
  • With int8 valuetype, it would pick the high byte of register index 3.
+thing-type.config.modbus.data.readTransform.label = Read Transform +thing-type.config.modbus.data.readTransform.description = Transformation to apply to polled data, after it has been converted to number using readValueType

Use "default" to communicate that no transformation is done and value should be passed as is.
Use SERVICENAME(ARG) or SERVICENAME:ARG to use transformation service.
Any other value than the above types will be interpreted as static text, in which case the actual content of the polled value is ignored.
You can chain many transformations with ∩, for example SERVICE1:ARG1∩SERVICE2:ARG2 +thing-type.config.modbus.data.readValueType.label = Read Value Type +thing-type.config.modbus.data.readValueType.description = How data is read from modbus. Use empty for write-only things.

With registers all value types are applicable. +thing-type.config.modbus.data.readValueType.option.int64 = 64bit signed integer (int64) +thing-type.config.modbus.data.readValueType.option.uint64 = 64bit unsigned integer (uint64) +thing-type.config.modbus.data.readValueType.option.int64_swap = 64bit signed integer, 16bit words in reverse order (dcba) (int64_swap) +thing-type.config.modbus.data.readValueType.option.uint64_swap = 64bit unsigned integer, 16bit words in reverse order (dcba) (uint64_swap) +thing-type.config.modbus.data.readValueType.option.float32 = 32bit floating point (float32) +thing-type.config.modbus.data.readValueType.option.float32_swap = 32bit floating point, 16bit words swapped (float32_swap) +thing-type.config.modbus.data.readValueType.option.int32 = 32bit signed integer (int32) +thing-type.config.modbus.data.readValueType.option.uint32 = 32bit unsigned integer (uint32) +thing-type.config.modbus.data.readValueType.option.int32_swap = 32bit signed integer, 16bit words swapped (int32_swap) +thing-type.config.modbus.data.readValueType.option.uint32_swap = 32bit unsigned integer, 16bit words swapped (uint32_swap) +thing-type.config.modbus.data.readValueType.option.int16 = 16bit signed integer (int16) +thing-type.config.modbus.data.readValueType.option.uint16 = 16bit unsigned integer (uint16) +thing-type.config.modbus.data.readValueType.option.int8 = 8bit signed integer (int8) +thing-type.config.modbus.data.readValueType.option.uint8 = 8bit unsigned integer (uint8) +thing-type.config.modbus.data.readValueType.option.bit = individual bit (bit) +thing-type.config.modbus.data.updateUnchangedValuesEveryMillis.label = Interval for Updating Unchanged Values +thing-type.config.modbus.data.updateUnchangedValuesEveryMillis.description = Interval to update unchanged values. Normally unchanged values are not updated. In milliseconds. +thing-type.config.modbus.data.writeMaxTries.label = Maximum Tries When Writing +thing-type.config.modbus.data.writeMaxTries.description = Number of tries when writing data, if some of the writes fail. For single try, enter 1. +thing-type.config.modbus.data.writeMultipleEvenWithSingleRegisterOrCoil.label = Write Multiple Even with Single Register or Coil +thing-type.config.modbus.data.writeMultipleEvenWithSingleRegisterOrCoil.description = Whether single register / coil of data is written using FC16 ("Write Multiple Holding Registers") / FC15 ("Write Multiple Coils"), respectively.

If false, FC6/FC5 are used with single register and single coil, respectively. +thing-type.config.modbus.data.writeStart.label = Write Address +thing-type.config.modbus.data.writeStart.description = Start address of the first holding register or coil in the write. Use empty for read-only things.
Use zero based address, e.g. in place of 400001 (first holding register), use the address 0. This address is passed to data frame as is.
One can write individual bits of an register using X.Y format where X is the register and Y is the bit (0 refers to least significant bit). +thing-type.config.modbus.data.writeTransform.label = Write Transform +thing-type.config.modbus.data.writeTransform.description = Transformation to apply to received commands.

Use "default" to communicate that no transformation is done and value should be passed as is.
Use SERVICENAME(ARG) or SERVICENAME:ARG to use transformation service.
Any other value than the above types will be interpreted as static text, in which case the actual content of the command
You can chain many transformations with ∩, for example SERVICE1:ARG1∩SERVICE2:ARG2 value is ignored. +thing-type.config.modbus.data.writeType.label = Write Type +thing-type.config.modbus.data.writeType.description = Type of data to write. Leave empty for read-only things.

Coil uses function code (FC) FC05 or FC15. Holding register uses FC06 or FC16. See writeMultipleEvenWithSingleRegisterOrCoil parameter. +thing-type.config.modbus.data.writeType.option.coil = coil, or digital out (DO) +thing-type.config.modbus.data.writeType.option.holding = holding register +thing-type.config.modbus.data.writeValueType.label = Write Value Type +thing-type.config.modbus.data.writeValueType.description = How data is written to modbus. Only applicable to registers, you can leave this undefined for coil.

Negative integers are encoded with two's complement, while positive integers are encoded as is. +thing-type.config.modbus.data.writeValueType.option.int64 = 64bit positive or negative integer, 4 registers (int64, uint64) +thing-type.config.modbus.data.writeValueType.option.int64_swap = 64bit positive or negative integer, 4 registers but with 16bit words/registers in reverse order (dcba) (int64_swap, uint64_swap) +thing-type.config.modbus.data.writeValueType.option.float32 = 32bit floating point (float32) +thing-type.config.modbus.data.writeValueType.option.float32_swap = 32bit floating point, 16bit words swapped (float32_swap) +thing-type.config.modbus.data.writeValueType.option.int32 = 32bit positive or negative integer, 2 registers (int32, uint32) +thing-type.config.modbus.data.writeValueType.option.int32_swap = 32bit positive or negative integer, 2 registers but with 16bit words/registers in reverse order (ba) (int32_swap, uint32_swap) +thing-type.config.modbus.data.writeValueType.option.int16 = 16bit positive or negative integer, 1 register (int16, uint16) +thing-type.config.modbus.data.writeValueType.option.bit = individual bit (bit) +thing-type.config.modbus.poller.cacheMillis.label = Cache Duration +thing-type.config.modbus.poller.cacheMillis.description = Duration for data cache to be valid, in milliseconds. This cache is used only to serve REFRESH commands.

Use zero to disable the caching. +thing-type.config.modbus.poller.length.label = Length +thing-type.config.modbus.poller.length.description = Number of registers, coils or discrete inputs to read.

Maximum number of registers is 125 while 2000 is maximum for coils and discrete inputs. +thing-type.config.modbus.poller.maxTries.label = Maximum Tries When Reading +thing-type.config.modbus.poller.maxTries.description = Number of tries when reading data, if some of the reading fail. For single try, enter 1. +thing-type.config.modbus.poller.refresh.label = Poll Interval +thing-type.config.modbus.poller.refresh.description = Poll interval in milliseconds. Use zero to disable automatic polling. +thing-type.config.modbus.poller.start.label = Start +thing-type.config.modbus.poller.start.description = Address of the first register, coil, or discrete input to poll.

Input as zero-based index number, e.g. in place of 400001 (first holding register), use the address 0. +thing-type.config.modbus.poller.type.label = Type +thing-type.config.modbus.poller.type.description = Type of modbus items to poll +thing-type.config.modbus.poller.type.option.coil = coil, or digital out (DO) +thing-type.config.modbus.poller.type.option.discrete = discrete input, or digital in (DI) +thing-type.config.modbus.poller.type.option.holding = holding register +thing-type.config.modbus.poller.type.option.input = input register +thing-type.config.modbus.serial.baud.label = Baud +thing-type.config.modbus.serial.baud.description = Baud of the connection +thing-type.config.modbus.serial.baud.option.75 = 75 +thing-type.config.modbus.serial.baud.option.110 = 110 +thing-type.config.modbus.serial.baud.option.300 = 300 +thing-type.config.modbus.serial.baud.option.1200 = 1200 +thing-type.config.modbus.serial.baud.option.2400 = 2400 +thing-type.config.modbus.serial.baud.option.4800 = 4800 +thing-type.config.modbus.serial.baud.option.9600 = 9600 +thing-type.config.modbus.serial.baud.option.19200 = 19200 +thing-type.config.modbus.serial.baud.option.38400 = 38400 +thing-type.config.modbus.serial.baud.option.57600 = 57600 +thing-type.config.modbus.serial.baud.option.115200 = 115200 +thing-type.config.modbus.serial.connectMaxTries.label = Maximum Connection Tries +thing-type.config.modbus.serial.connectMaxTries.description = How many times we try to establish the connection. Should be at least 1. +thing-type.config.modbus.serial.connectTimeoutMillis.label = Timeout for Establishing the Connection +thing-type.config.modbus.serial.connectTimeoutMillis.description = The maximum time that is waited when establishing the connection. Value of zero means that system/OS default is respected. In milliseconds. +thing-type.config.modbus.serial.dataBits.label = Data Bits +thing-type.config.modbus.serial.dataBits.description = Data bits +thing-type.config.modbus.serial.dataBits.option.5 = 5 +thing-type.config.modbus.serial.dataBits.option.6 = 6 +thing-type.config.modbus.serial.dataBits.option.7 = 7 +thing-type.config.modbus.serial.dataBits.option.8 = 8 +thing-type.config.modbus.serial.echo.label = RS485 Echo Mode +thing-type.config.modbus.serial.echo.description = Flag for setting the RS485 echo mode

This controls whether we should try to read back whatever we send on the line, before reading the response. +thing-type.config.modbus.serial.enableDiscovery.label = Discovery Enabled +thing-type.config.modbus.serial.enableDiscovery.description = When enabled we try to find a device specific handler. Turn this on if you're using one of the supported devices. +thing-type.config.modbus.serial.encoding.label = Encoding +thing-type.config.modbus.serial.encoding.description = Encoding +thing-type.config.modbus.serial.encoding.option.ascii = ASCII +thing-type.config.modbus.serial.encoding.option.rtu = RTU +thing-type.config.modbus.serial.encoding.option.bin = BIN +thing-type.config.modbus.serial.flowControlIn.label = Flow Control In +thing-type.config.modbus.serial.flowControlIn.description = Type of flow control for receiving +thing-type.config.modbus.serial.flowControlIn.option.none = None +thing-type.config.modbus.serial.flowControlIn.option.xon/xoff in = XON/XOFF +thing-type.config.modbus.serial.flowControlIn.option.rts/cts in = RTS/CTS +thing-type.config.modbus.serial.flowControlOut.label = Flow Control Out +thing-type.config.modbus.serial.flowControlOut.description = Type of flow control for sending +thing-type.config.modbus.serial.flowControlOut.option.none = None +thing-type.config.modbus.serial.flowControlOut.option.xon/xoff out = XON/XOFF +thing-type.config.modbus.serial.flowControlOut.option.rts/cts out = RTS/CTS +thing-type.config.modbus.serial.id.label = Id +thing-type.config.modbus.serial.id.description = Slave id. Also known as station address or unit identifier. +thing-type.config.modbus.serial.parity.label = Parity +thing-type.config.modbus.serial.parity.description = Parity +thing-type.config.modbus.serial.parity.option.none = None +thing-type.config.modbus.serial.parity.option.even = Even +thing-type.config.modbus.serial.parity.option.odd = Odd +thing-type.config.modbus.serial.port.label = Serial Port +thing-type.config.modbus.serial.port.description = Serial port to use, for example /dev/ttyS0 or COM1 +thing-type.config.modbus.serial.receiveTimeoutMillis.label = Read Operation Timeout +thing-type.config.modbus.serial.receiveTimeoutMillis.description = Timeout for read operations. In milliseconds. +thing-type.config.modbus.serial.stopBits.label = Stop Bits +thing-type.config.modbus.serial.stopBits.description = Stop bits +thing-type.config.modbus.serial.stopBits.option.1.0 = 1 +thing-type.config.modbus.serial.stopBits.option.1.5 = 1.5 +thing-type.config.modbus.serial.stopBits.option.2.0 = 2 +thing-type.config.modbus.serial.timeBetweenTransactionsMillis.label = Time Between Transactions +thing-type.config.modbus.serial.timeBetweenTransactionsMillis.description = How long to delay we must have at minimum between two consecutive MODBUS transactions. In milliseconds. +thing-type.config.modbus.tcp.connectMaxTries.label = Maximum Connection Tries +thing-type.config.modbus.tcp.connectMaxTries.description = How many times we try to establish the connection. Should be at least 1. +thing-type.config.modbus.tcp.connectTimeoutMillis.label = Timeout for Establishing the Connection +thing-type.config.modbus.tcp.connectTimeoutMillis.description = The maximum time that is waited when establishing the connection. Value of zero means that system/OS default is respected. In milliseconds. +thing-type.config.modbus.tcp.enableDiscovery.label = Discovery Enabled +thing-type.config.modbus.tcp.enableDiscovery.description = When enabled we try to find a device specific handler. Turn this on if you're using one of the supported devices. +thing-type.config.modbus.tcp.host.label = IP Address or Hostname +thing-type.config.modbus.tcp.host.description = Network address of the device +thing-type.config.modbus.tcp.id.label = Id +thing-type.config.modbus.tcp.id.description = Slave id. Also known as station address or unit identifier. +thing-type.config.modbus.tcp.port.label = Port +thing-type.config.modbus.tcp.port.description = Port of the slave +thing-type.config.modbus.tcp.reconnectAfterMillis.label = Reconnect Again After +thing-type.config.modbus.tcp.reconnectAfterMillis.description = The connection is kept open at least the time specified here. Value of zero means that connection is disconnected after every MODBUS transaction. In milliseconds. +thing-type.config.modbus.tcp.rtuEncoded.label = RTU Encoding +thing-type.config.modbus.tcp.rtuEncoded.description = Use RTU Encoding over IP +thing-type.config.modbus.tcp.timeBetweenReconnectMillis.label = Time Between Reconnections +thing-type.config.modbus.tcp.timeBetweenReconnectMillis.description = How long to wait to before trying to establish a new connection after the previous one has been disconnected. In milliseconds. +thing-type.config.modbus.tcp.timeBetweenTransactionsMillis.label = Time Between Transactions +thing-type.config.modbus.tcp.timeBetweenTransactionsMillis.description = How long to delay we must have at minimum between two consecutive MODBUS transactions. In milliseconds. + +# channel types + +channel-type.modbus.contact-type.label = Value as Contact +channel-type.modbus.contact-type.description = Contact item channel +channel-type.modbus.datetime-type.label = Value as DateTime +channel-type.modbus.datetime-type.description = DateTime item channel +channel-type.modbus.dimmer-type.label = Value as Dimmer +channel-type.modbus.dimmer-type.description = Dimmer item channel +channel-type.modbus.last-erroring-read-type.label = Last Erroring Read +channel-type.modbus.last-erroring-read-type.description = Date of last read error +channel-type.modbus.last-erroring-write-type.label = Last Erroring Write +channel-type.modbus.last-erroring-write-type.description = Date of last write error +channel-type.modbus.last-successful-read-type.label = Last Successful Read +channel-type.modbus.last-successful-read-type.description = Date of last read +channel-type.modbus.last-successful-write-type.label = Last Successful Write +channel-type.modbus.last-successful-write-type.description = Date of last write +channel-type.modbus.number-type.label = Value as Number +channel-type.modbus.number-type.description = Number item channel +channel-type.modbus.rollershutter-type.label = Value as Rollershutter +channel-type.modbus.rollershutter-type.description = Rollershutter item channel +channel-type.modbus.string-type.label = Value as String +channel-type.modbus.string-type.description = String item channel +channel-type.modbus.switch-type.label = Value as Switch +channel-type.modbus.switch-type.description = Switch item channel diff --git a/bundles/org.openhab.binding.monopriceaudio/src/main/resources/OH-INF/i18n/monopriceaudio.properties b/bundles/org.openhab.binding.monopriceaudio/src/main/resources/OH-INF/i18n/monopriceaudio.properties new file mode 100644 index 0000000000000..1b163efe4fed3 --- /dev/null +++ b/bundles/org.openhab.binding.monopriceaudio/src/main/resources/OH-INF/i18n/monopriceaudio.properties @@ -0,0 +1,106 @@ +# binding + +binding.monopriceaudio.name = Monoprice Whole House Audio Binding +binding.monopriceaudio.description = Controls Monoprice and Dayton Audio Whole House Amplifiers. + +# thing types + +thing-type.monopriceaudio.amplifier.label = Monoprice 10761 Amplifier, 39261 Matrix or Dayton DAX66 Amplifier +thing-type.monopriceaudio.amplifier.description = A Multi-zone Whole House Amplifier System +thing-type.monopriceaudio.amplifier.group.all.label = All Zones +thing-type.monopriceaudio.amplifier.group.all.description = Control All Zones Simultaneously +thing-type.monopriceaudio.amplifier.group.zone1.label = Zone 1 +thing-type.monopriceaudio.amplifier.group.zone1.description = The Controls for Zone 1 +thing-type.monopriceaudio.amplifier.group.zone2.label = Zone 2 +thing-type.monopriceaudio.amplifier.group.zone2.description = The Controls for Zone 2 +thing-type.monopriceaudio.amplifier.group.zone3.label = Zone 3 +thing-type.monopriceaudio.amplifier.group.zone3.description = The Controls for Zone 3 +thing-type.monopriceaudio.amplifier.group.zone4.label = Zone 4 +thing-type.monopriceaudio.amplifier.group.zone4.description = The Controls for Zone 4 +thing-type.monopriceaudio.amplifier.group.zone5.label = Zone 5 +thing-type.monopriceaudio.amplifier.group.zone5.description = The Controls for Zone 5 +thing-type.monopriceaudio.amplifier.group.zone6.label = Zone 6 +thing-type.monopriceaudio.amplifier.group.zone6.description = The Controls for Zone 6 +thing-type.monopriceaudio.amplifier.group.zone7.label = Zone 7 +thing-type.monopriceaudio.amplifier.group.zone7.description = The Controls for Zone 7 +thing-type.monopriceaudio.amplifier.group.zone8.label = Zone 8 +thing-type.monopriceaudio.amplifier.group.zone8.description = The Controls for Zone 8 +thing-type.monopriceaudio.amplifier.group.zone9.label = Zone 9 +thing-type.monopriceaudio.amplifier.group.zone9.description = The Controls for Zone 9 +thing-type.monopriceaudio.amplifier.group.zone10.label = Zone 10 +thing-type.monopriceaudio.amplifier.group.zone10.description = The Controls for Zone 10 +thing-type.monopriceaudio.amplifier.group.zone11.label = Zone 11 +thing-type.monopriceaudio.amplifier.group.zone11.description = The Controls for Zone 11 +thing-type.monopriceaudio.amplifier.group.zone12.label = Zone 12 +thing-type.monopriceaudio.amplifier.group.zone12.description = The Controls for Zone 12 +thing-type.monopriceaudio.amplifier.group.zone13.label = Zone 13 +thing-type.monopriceaudio.amplifier.group.zone13.description = The Controls for Zone 13 +thing-type.monopriceaudio.amplifier.group.zone14.label = Zone 14 +thing-type.monopriceaudio.amplifier.group.zone14.description = The Controls for Zone 14 +thing-type.monopriceaudio.amplifier.group.zone15.label = Zone 15 +thing-type.monopriceaudio.amplifier.group.zone15.description = The Controls for Zone 15 +thing-type.monopriceaudio.amplifier.group.zone16.label = Zone 16 +thing-type.monopriceaudio.amplifier.group.zone16.description = The Controls for Zone 16 +thing-type.monopriceaudio.amplifier.group.zone17.label = Zone 17 +thing-type.monopriceaudio.amplifier.group.zone17.description = The Controls for Zone 17 +thing-type.monopriceaudio.amplifier.group.zone18.label = Zone 18 +thing-type.monopriceaudio.amplifier.group.zone18.description = The Controls for Zone 18 + +# thing types config + +thing-type.config.monopriceaudio.amplifier.host.label = Address +thing-type.config.monopriceaudio.amplifier.host.description = Host Name or IP Address of the Amplifier or Serial over IP device +thing-type.config.monopriceaudio.amplifier.ignoreZones.label = Ignore Zones +thing-type.config.monopriceaudio.amplifier.ignoreZones.description = (Optional) A Comma Seperated List of Zone Numbers That Will Ignore the 'All Zone' (Except All Off) Commands (ie: 1,6,10) +thing-type.config.monopriceaudio.amplifier.initialAllVolume.label = Initial All Volume +thing-type.config.monopriceaudio.amplifier.initialAllVolume.description = When 'All' Zones Are Activated, the Volume Will Reset to This Value (1-30; default 10) to Prevent Excessive Blaring of Sound ;) +thing-type.config.monopriceaudio.amplifier.inputLabel1.label = Source 1 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel1.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.inputLabel2.label = Source 2 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel2.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.inputLabel3.label = Source 3 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel3.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.inputLabel4.label = Source 4 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel4.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.inputLabel5.label = Source 5 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel5.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.inputLabel6.label = Source 6 Input Label +thing-type.config.monopriceaudio.amplifier.inputLabel6.description = Friendly Name for the Input Source to Be Displayed in the UI (ie: Chromecast, Radio, CD, etc.) +thing-type.config.monopriceaudio.amplifier.numZones.label = Number of Zones +thing-type.config.monopriceaudio.amplifier.numZones.description = Number of Zones on the Amplifier to Utilize in the Binding (Up to 18 Zones With 3 Amplifiers Connected Together) +thing-type.config.monopriceaudio.amplifier.pollingInterval.label = Polling Interval +thing-type.config.monopriceaudio.amplifier.pollingInterval.description = Configures How Often to Poll the Controller to Check for Zone Updates (5-60; Default 15) +thing-type.config.monopriceaudio.amplifier.port.label = Port +thing-type.config.monopriceaudio.amplifier.port.description = Communication Port for Serial over IP connection to the Amplifier (Default 8080 for amps with built-in Serial over IP) +thing-type.config.monopriceaudio.amplifier.serialPort.label = Serial Port +thing-type.config.monopriceaudio.amplifier.serialPort.description = Serial Port to Use for Connecting to the Monoprice Amplifier + +# channel group types + +channel-group-type.monopriceaudio.all.label = All Zones +channel-group-type.monopriceaudio.all.description = Control All Zones Simultaneously +channel-group-type.monopriceaudio.zone.label = Zone Controls +channel-group-type.monopriceaudio.zone.description = The Controls for the Zone + +# channel types + +channel-type.monopriceaudio.allpower.label = All On +channel-type.monopriceaudio.allpower.description = Turn All Zones On or Off +channel-type.monopriceaudio.balance.label = Balance Adjustment +channel-type.monopriceaudio.balance.description = Adjust the Balance +channel-type.monopriceaudio.bass.label = Bass Adjustment +channel-type.monopriceaudio.bass.description = Adjust the Bass +channel-type.monopriceaudio.dnd.label = Do Not Disturb +channel-type.monopriceaudio.dnd.description = Controls if the Zone Should Ignore an Incoming Audio Page +channel-type.monopriceaudio.keypad.label = Keypad Connected +channel-type.monopriceaudio.keypad.description = Indicates if a Physical Keypad is Attached to This Zone +channel-type.monopriceaudio.keypad.state.option.CLOSED = Disconnected +channel-type.monopriceaudio.keypad.state.option.OPEN = Connected +channel-type.monopriceaudio.page.label = Page Active +channel-type.monopriceaudio.page.description = Indicates if the Page Mode is Active for This Zone +channel-type.monopriceaudio.page.state.option.CLOSED = Inactive +channel-type.monopriceaudio.page.state.option.OPEN = Active +channel-type.monopriceaudio.source.label = Source Input +channel-type.monopriceaudio.source.description = Select the Source Input +channel-type.monopriceaudio.treble.label = Treble Adjustment +channel-type.monopriceaudio.treble.description = Adjust the Treble diff --git a/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd.properties b/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd.properties new file mode 100644 index 0000000000000..763b6d8863579 --- /dev/null +++ b/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd.properties @@ -0,0 +1,33 @@ +# binding + +binding.mpd.name = MPD Binding +binding.mpd.description = This is the binding for the Music Player Daemon. + +# thing types + +thing-type.mpd.mpd.label = Music Player Daemon +thing-type.mpd.mpd.description = Music Player Daemon Binding + +# thing types config + +thing-type.config.mpd.mpd.ipAddress.label = Network Address +thing-type.config.mpd.mpd.ipAddress.description = The IP or host name of the Music Player Daemon. +thing-type.config.mpd.mpd.password.label = Password +thing-type.config.mpd.mpd.password.description = Password to access the Music Player Daemon. +thing-type.config.mpd.mpd.port.label = Port +thing-type.config.mpd.mpd.port.description = Port for the Music Player Daemon + +# channel types + +channel-type.mpd.currentalbum.label = Current Album +channel-type.mpd.currentalbum.description = Name of the album currently playing. +channel-type.mpd.currentname.label = Current Name +channel-type.mpd.currentname.description = Name for current song. This is not the song title. The exact meaning of this tag is not well-defined. It is often used by badly configured internet radio stations with broken tags to squeeze both the artist name and the song title in one tag. +channel-type.mpd.currentsong.label = Current Song +channel-type.mpd.currentsong.description = The current song number. +channel-type.mpd.currentsongid.label = Current Song Id +channel-type.mpd.currentsongid.description = The current song id. +channel-type.mpd.currenttrack.label = Current Track +channel-type.mpd.currenttrack.description = The current track number. +channel-type.mpd.stop.label = Stop +channel-type.mpd.stop.description = Stop the Music Player Daemon. ON if the player is stopped. diff --git a/bundles/org.openhab.binding.mqtt.espmilighthub/src/main/resources/OH-INF/i18n/mqtt.properties b/bundles/org.openhab.binding.mqtt.espmilighthub/src/main/resources/OH-INF/i18n/mqtt.properties new file mode 100644 index 0000000000000..9736943568d0d --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.espmilighthub/src/main/resources/OH-INF/i18n/mqtt.properties @@ -0,0 +1,32 @@ +thing-type.config.mqtt.cct.dimmedCT.label = Dimmed Colour Temp +thing-type.config.mqtt.cct.dimmedCT.description = Traditional globes grow warmer the more they are dimmed. Set this to 370, or leave blank to disable. +thing-type.config.mqtt.cct.oneTriggersNightMode.label = 1% Triggers Night Mode +thing-type.config.mqtt.cct.oneTriggersNightMode.description = 1% on a slider will trigger the Night Mode. +thing-type.config.mqtt.rgb.oneTriggersNightMode.label = 1% Triggers Night Mode +thing-type.config.mqtt.rgb.oneTriggersNightMode.description = 1% on a slider will trigger the Night Mode. +thing-type.config.mqtt.rgb.powerFailsToMinimum.label = Dimmed on Power Fail +thing-type.config.mqtt.rgb.powerFailsToMinimum.description = If lights loose power when soft off, the lights will default back to the minimum brightness. +thing-type.config.mqtt.rgbandcct.dimmedCT.label = Dimmed Colour Temp +thing-type.config.mqtt.rgbandcct.dimmedCT.description = Traditional globes grow warmer the more they are dimmed. Set this to 370, or leave blank to disable. +thing-type.config.mqtt.rgbandcct.favouriteWhite.label = Favourite White +thing-type.config.mqtt.rgbandcct.favouriteWhite.description = When a shortcut triggers white mode, use this for the colour white. +thing-type.config.mqtt.rgbandcct.oneTriggersNightMode.label = 1% Triggers Night Mode +thing-type.config.mqtt.rgbandcct.oneTriggersNightMode.description = 1% on a slider will trigger the Night Mode. +thing-type.config.mqtt.rgbandcct.powerFailsToMinimum.label = Dimmed on Power Fail +thing-type.config.mqtt.rgbandcct.powerFailsToMinimum.description = If lights loose power, the lights will turn on to the minimum brightness. +thing-type.config.mqtt.rgbandcct.whiteHue.label = White Hue +thing-type.config.mqtt.rgbandcct.whiteHue.description = When both the whiteHue and whiteSat values are seen by the binding it will trigger the white LEDS. +thing-type.config.mqtt.rgbandcct.whiteSat.label = White Saturation +thing-type.config.mqtt.rgbandcct.whiteSat.description = When both the whiteHue and whiteSat values are seen by the binding it will trigger the white LEDS. +thing-type.config.mqtt.rgbandcct.whiteThreshold.label = White Threshold +thing-type.config.mqtt.rgbandcct.whiteThreshold.description = Saturation values at or below this value on a RGBW color control will trigger the white mode. -1 will disable this feature. +thing-type.config.mqtt.rgbw.oneTriggersNightMode.label = 1% Triggers Night Mode +thing-type.config.mqtt.rgbw.oneTriggersNightMode.description = 1% on a slider will trigger the Night Mode. +thing-type.config.mqtt.rgbw.powerFailsToMinimum.label = Dimmed on Power Fail +thing-type.config.mqtt.rgbw.powerFailsToMinimum.description = If lights loose power, the lights will turn on to the minimum brightness. +thing-type.config.mqtt.rgbw.whiteHue.label = White Hue +thing-type.config.mqtt.rgbw.whiteHue.description = When both the whiteHue and whiteSat values are seen by the binding it will trigger the white LEDS. +thing-type.config.mqtt.rgbw.whiteSat.label = White Saturation +thing-type.config.mqtt.rgbw.whiteSat.description = When both the whiteHue and whiteSat values are seen by the binding it will trigger the white LEDS. +thing-type.config.mqtt.rgbw.whiteThreshold.label = White Threshold +thing-type.config.mqtt.rgbw.whiteThreshold.description = Saturation values at or below this value on a RGBW color control will trigger the white mode. -1 will disable this feature. diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/resources/OH-INF/i18n/mqtt.properties b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/resources/OH-INF/i18n/mqtt.properties new file mode 100644 index 0000000000000..7ab2c165eccfb --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/resources/OH-INF/i18n/mqtt.properties @@ -0,0 +1,8 @@ +channel-type.config.mqtt.ha-channel.component.label = Component +channel-type.config.mqtt.ha-channel.component.description = HomeAssistant component type (e.g. binary_sensor, switch, light) +channel-type.config.mqtt.ha-channel.config.label = Json Configuration +channel-type.config.mqtt.ha-channel.config.description = The json configuration string received by the component via MQTT. +channel-type.config.mqtt.ha-channel.nodeid.label = Node ID +channel-type.config.mqtt.ha-channel.nodeid.description = Optional node name of the component +channel-type.config.mqtt.ha-channel.objectid.label = Object ID +channel-type.config.mqtt.ha-channel.objectid.description = Object id of the component diff --git a/bundles/org.openhab.binding.mqtt.homie/src/main/resources/OH-INF/i18n/mqtt.properties b/bundles/org.openhab.binding.mqtt.homie/src/main/resources/OH-INF/i18n/mqtt.properties new file mode 100644 index 0000000000000..fcbe137d35210 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.homie/src/main/resources/OH-INF/i18n/mqtt.properties @@ -0,0 +1,18 @@ +channel-type.config.mqtt.homie-channel.datatype.label = Data Type +channel-type.config.mqtt.homie-channel.datatype.description = The data type of this channel. +channel-type.config.mqtt.homie-channel.datatype.option.integer_ = Integer +channel-type.config.mqtt.homie-channel.datatype.option.float_ = Float +channel-type.config.mqtt.homie-channel.datatype.option.boolean_ = Boolean +channel-type.config.mqtt.homie-channel.datatype.option.string_ = String +channel-type.config.mqtt.homie-channel.datatype.option.enum_ = Enumeration +channel-type.config.mqtt.homie-channel.datatype.option.color_ = Colour +channel-type.config.mqtt.homie-channel.format.label = Format +channel-type.config.mqtt.homie-channel.format.description = The output format. +channel-type.config.mqtt.homie-channel.name.label = Name +channel-type.config.mqtt.homie-channel.name.description = The channel name +channel-type.config.mqtt.homie-channel.retained.label = Retained +channel-type.config.mqtt.homie-channel.retained.description = If set to false, the resulting channel will be a trigger channel (stateless), useful for non-permanent events. This flag corresponds to the retained option for MQTT publish. +channel-type.config.mqtt.homie-channel.settable.label = Settable +channel-type.config.mqtt.homie-channel.settable.description = Is this channel writable? +channel-type.config.mqtt.homie-channel.unit.label = Unit +channel-type.config.mqtt.homie-channel.unit.description = The channels unit diff --git a/bundles/org.openhab.binding.myq/src/main/resources/OH-INF/i18n/myq.properties b/bundles/org.openhab.binding.myq/src/main/resources/OH-INF/i18n/myq.properties new file mode 100644 index 0000000000000..74cc4cc7d514b --- /dev/null +++ b/bundles/org.openhab.binding.myq/src/main/resources/OH-INF/i18n/myq.properties @@ -0,0 +1,42 @@ +# binding + +binding.myq.name = MyQ Binding +binding.myq.description = The MyQ binding allows monitoring and control of garage doors that are MyQ enabled. + +# thing types + +thing-type.myq.account.label = MyQ Account +thing-type.myq.account.description = MyQ Cloud Account +thing-type.myq.garagedoor.label = MyQ Garage Door +thing-type.myq.garagedoor.description = MyQ Garage Door +thing-type.myq.lamp.label = MyQ Lamp +thing-type.myq.lamp.description = MyQ Lamp + +# thing types config + +thing-type.config.myq.account.password.label = password +thing-type.config.myq.account.password.description = Account password +thing-type.config.myq.account.refreshInterval.label = Refresh Interval +thing-type.config.myq.account.refreshInterval.description = Specifies the refresh interval in seconds +thing-type.config.myq.account.username.label = User Name +thing-type.config.myq.account.username.description = Account username +thing-type.config.myq.garagedoor.serialNumber.label = Serial Number +thing-type.config.myq.garagedoor.serialNumber.description = Serial number of the garage door +thing-type.config.myq.lamp.serialNumber.label = Serial Number +thing-type.config.myq.lamp.serialNumber.description = Serial number of the lamp + +# channel types + +channel-type.myq.doorcloseerror.label = Garage Door Close Error +channel-type.myq.dooropenerror.label = Garage Door Open Error +channel-type.myq.doorrollershutter.label = Garage Door Rollershutter +channel-type.myq.doorstatus.label = Garage Door Status +channel-type.myq.doorstatus.state.option.open = Open +channel-type.myq.doorstatus.state.option.opening = Opening +channel-type.myq.doorstatus.state.option.closed = Closed +channel-type.myq.doorstatus.state.option.closing = Closing +channel-type.myq.doorstatus.state.option.stopped = Stopped +channel-type.myq.doorstatus.state.option.transition = Transitioning +channel-type.myq.doorstatus.state.option.unknown = Unknown +channel-type.myq.doorswitch.label = Garage Door Switch +channel-type.myq.lampswitch.label = Lamp Switch diff --git a/bundles/org.openhab.binding.mystrom/src/main/resources/OH-INF/i18n/mystrom.properties b/bundles/org.openhab.binding.mystrom/src/main/resources/OH-INF/i18n/mystrom.properties new file mode 100644 index 0000000000000..23f72e7cb1ca4 --- /dev/null +++ b/bundles/org.openhab.binding.mystrom/src/main/resources/OH-INF/i18n/mystrom.properties @@ -0,0 +1,36 @@ +# binding + +binding.mystrom.name = myStrom Binding +binding.mystrom.description = This is the binding for myStrom devices. + +# thing types + +thing-type.mystrom.mystrombulb.label = myStrom Bulb +thing-type.mystrom.mystrombulb.description = Controls the myStrom bulb +thing-type.mystrom.mystromplug.label = myStrom Smart Plug +thing-type.mystrom.mystromplug.description = Controls the myStrom smart plug + +# thing types config + +thing-type.config.mystrom.mystrombulb.hostname.label = Hostname +thing-type.config.mystrom.mystrombulb.hostname.description = The host name or IP address of the myStrom bulb. +thing-type.config.mystrom.mystrombulb.refresh.label = Refresh Interval +thing-type.config.mystrom.mystrombulb.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.mystrom.mystromplug.hostname.label = Hostname +thing-type.config.mystrom.mystromplug.hostname.description = The host name or IP address of the myStrom plug. +thing-type.config.mystrom.mystromplug.refresh.label = Refresh Interval +thing-type.config.mystrom.mystromplug.refresh.description = Specifies the refresh interval in seconds. + +# channel types + +channel-type.mystrom.mode-channel.label = Mode +channel-type.mystrom.mode-channel.description = The color mode we want the Bulb to set to +channel-type.mystrom.mode-channel.command.option.rgb = RGB +channel-type.mystrom.mode-channel.command.option.hsv = HSB (HSV) +channel-type.mystrom.mode-channel.command.option.mono = MONO +channel-type.mystrom.power-channel.label = Power Consumption +channel-type.mystrom.power-channel.description = The current power delivered by the plug +channel-type.mystrom.ramp-channel.label = Ramp +channel-type.mystrom.ramp-channel.description = Transition time from the light’s current state to the new state. +channel-type.mystrom.temperature-channel.label = Temperature +channel-type.mystrom.temperature-channel.description = The current temperature at the plug diff --git a/bundles/org.openhab.binding.neato/src/main/resources/OH-INF/i18n/neato.properties b/bundles/org.openhab.binding.neato/src/main/resources/OH-INF/i18n/neato.properties new file mode 100644 index 0000000000000..dd91726fbc0ea --- /dev/null +++ b/bundles/org.openhab.binding.neato/src/main/resources/OH-INF/i18n/neato.properties @@ -0,0 +1,89 @@ +# binding + +binding.neato.name = Neato Binding +binding.neato.description = This is the binding for Neato. + +# thing types + +thing-type.neato.neatoaccount.label = Neato Account +thing-type.neato.neatoaccount.description = Access to Neato Account. Used to discover robots tied to account. +thing-type.neato.vacuumcleaner.label = Neato Vacuum Cleaner +thing-type.neato.vacuumcleaner.description = Provides communication with Neato Vacuum cleaner. + +# thing types config + +thing-type.config.neato.neatoaccount.email.label = E-mail Address +thing-type.config.neato.neatoaccount.email.description = E-mail address for your Neato Cloud account. +thing-type.config.neato.neatoaccount.password.label = Password +thing-type.config.neato.neatoaccount.password.description = Password for your Neato Cloud account. +thing-type.config.neato.vacuumcleaner.refresh.label = Refresh Time Interval +thing-type.config.neato.vacuumcleaner.refresh.description = Refresh time interval in seconds for updates from the Neato Web Service. +thing-type.config.neato.vacuumcleaner.secret.label = Neato Vacuum Secret +thing-type.config.neato.vacuumcleaner.secret.description = Secret for accessing Neato web services. +thing-type.config.neato.vacuumcleaner.serial.label = Neato Vacuum Serial +thing-type.config.neato.vacuumcleaner.serial.description = Serial number of the vacuum cleaner + +# channel types + +channel-type.neato.action.label = Current Action +channel-type.neato.action.description = Current action of the vacuum cleaner. +channel-type.neato.action.state.option.INVALID = Invalid +channel-type.neato.action.state.option.HOUSE_CLEANING = House Cleaning +channel-type.neato.action.state.option.SPOT_CLEANING = Spot Cleaning +channel-type.neato.action.state.option.MANUAL_CLEANING = Manual Cleaning +channel-type.neato.action.state.option.DOCKING = Docking +channel-type.neato.action.state.option.USER_MENU_ACTIVE = User Menu Active +channel-type.neato.action.state.option.SUSPENDED_CLEANING = Suspended Cleaning +channel-type.neato.action.state.option.UPDATING = Updating +channel-type.neato.action.state.option.COPYING_LOGS = Copying Logs +channel-type.neato.action.state.option.RECOVERING_LOCATION = Recovering Location +channel-type.neato.action.state.option.IEC_TEST = Iec Test +channel-type.neato.action.state.option.MAP_CLEANING = Map Cleaning +channel-type.neato.action.state.option.EXPLORING_MAP = Exploring map (creating a persistent map) +channel-type.neato.action.state.option.AQUIRING_MAP_IDS = Acquiring Persistent Map IDs +channel-type.neato.action.state.option.CREATING_MAP = Creating & Uploading Map +channel-type.neato.action.state.option.SUSPENDED_EXPLORATION = Suspended Exploration +channel-type.neato.cleaning-category.label = Cleaning Category +channel-type.neato.cleaning-category.description = Current or last category of the cleaning. +channel-type.neato.cleaning-category.state.option.MANUAL = Manual Cleaning +channel-type.neato.cleaning-category.state.option.SPOT = Spot Cleaning +channel-type.neato.cleaning-category.state.option.HOUSE = House Cleaning +channel-type.neato.cleaning-category.state.option.MAP = Map Cleaning +channel-type.neato.cleaning-mode.label = Cleaning Mode +channel-type.neato.cleaning-mode.description = Current or last cleaning mode. +channel-type.neato.cleaning-mode.state.option.ECO = Eco +channel-type.neato.cleaning-mode.state.option.TURBO = Turbo +channel-type.neato.cleaning-modifier.label = Cleaning Modifier +channel-type.neato.cleaning-modifier.description = Modifier of current or last cleaning. +channel-type.neato.cleaning-modifier.state.option.NORMAL = Normal +channel-type.neato.cleaning-modifier.state.option.DOUBLE = Double +channel-type.neato.cleaning-modifier.state.option.DEEP = Deep +channel-type.neato.cleaning-spotheight.label = Spot Height +channel-type.neato.cleaning-spotheight.description = Current or Last cleaning, height of spot. 100-400cm. +channel-type.neato.cleaning-spotwidth.label = Spot Width +channel-type.neato.cleaning-spotwidth.description = Current or Last cleaning, width of spot. 100-400cm. +channel-type.neato.command.label = Send Command +channel-type.neato.command.description = Send Commands to Vacuum Cleaner. (clean with map, clean, pause, resume, stop, dock) +channel-type.neato.command.state.option.clean = Clean +channel-type.neato.command.state.option.cleanWithMap = Clean with Map +channel-type.neato.command.state.option.pause = Pause +channel-type.neato.command.state.option.resume = Resume +channel-type.neato.command.state.option.stop = Stop +channel-type.neato.command.state.option.dock = Go to Dock +channel-type.neato.dock-has-been-seen.label = Dock Has Been Seen +channel-type.neato.dock-has-been-seen.description = True or False value if the dock has been seen +channel-type.neato.error.label = Error +channel-type.neato.error.description = Last error message in system. +channel-type.neato.is-charging.label = Is Charging +channel-type.neato.is-charging.description = Is the vacuum cleaner currently charging? +channel-type.neato.is-docked.label = Is Docked +channel-type.neato.is-docked.description = Is the vacuum cleaner in the docking station? +channel-type.neato.is-scheduled.label = Is Scheduled Enabled +channel-type.neato.is-scheduled.description = True or False value if the vacuum cleaner is scheduled for cleaning. +channel-type.neato.state.label = Current State +channel-type.neato.state.description = Current state of the vacuum cleaner. +channel-type.neato.state.state.option.INVALID = Invalid +channel-type.neato.state.state.option.IDLE = Idle +channel-type.neato.state.state.option.BUSY = Busy +channel-type.neato.state.state.option.PAUSED = Paused +channel-type.neato.state.state.option.ERROR = Error diff --git a/bundles/org.openhab.binding.neeo/src/main/resources/OH-INF/i18n/neeo.properties b/bundles/org.openhab.binding.neeo/src/main/resources/OH-INF/i18n/neeo.properties new file mode 100644 index 0000000000000..c922aa63a317a --- /dev/null +++ b/bundles/org.openhab.binding.neeo/src/main/resources/OH-INF/i18n/neeo.properties @@ -0,0 +1,68 @@ +# binding + +binding.neeo.name = Neeo Binding +binding.neeo.description = This binding allows you to discover NEEO Brain(s), discover the Rooms within and the Devices within those Rooms. The binding then will expose that information to openHAB and allow you to execute Recipes/Scenarios and Macros on the Devices + +# thing types + +thing-type.neeo.brain.label = Neeo Brain +thing-type.neeo.brain.description = The NEEO Brain +thing-type.neeo.device.label = Neeo Device +thing-type.neeo.device.description = Neeo Device +thing-type.neeo.room.label = Neeo Room +thing-type.neeo.room.description = Neeo Room + +# thing types config + +thing-type.config.neeo.brain.checkStatusInterval.label = Check Status Interval +thing-type.config.neeo.brain.checkStatusInterval.description = The interval (in seconds) to check the status of the brain (specify <=0 to disable) +thing-type.config.neeo.brain.discoverEmptyRooms.label = Discover Empty Rooms +thing-type.config.neeo.brain.discoverEmptyRooms.description = Whether to discover rooms with no devices or not +thing-type.config.neeo.brain.enableForwardActions.label = Enable Forward Actions +thing-type.config.neeo.brain.enableForwardActions.description = Whether to have the NEEO Brain forward actions to openHAB +thing-type.config.neeo.brain.forwardChain.label = Forward Chaining +thing-type.config.neeo.brain.forwardChain.description = Comma delimited list of URLs to forward NEEO brain actions to +thing-type.config.neeo.brain.ipAddress.label = IP or Host Name +thing-type.config.neeo.brain.ipAddress.description = The IP or host name of the NEEO Brain +thing-type.config.neeo.device.deviceKey.label = Device Key +thing-type.config.neeo.device.deviceKey.description = Unique key of the device +thing-type.config.neeo.room.excludeThings.label = Exclude Things +thing-type.config.neeo.room.excludeThings.description = Exclude openHAB things (from NEEO transport) +thing-type.config.neeo.room.refreshPolling.label = Refresh Polling +thing-type.config.neeo.room.refreshPolling.description = The time (in seconds) to refresh state (<= 0 to disable) +thing-type.config.neeo.room.roomKey.label = Room Key +thing-type.config.neeo.room.roomKey.description = Unique key of the room + +# channel group types + +channel-group-type.neeo.device-macros.label = Macros +channel-group-type.neeo.device-macros.description = Executable macros +channel-group-type.neeo.room-recipe.label = Recipes +channel-group-type.neeo.room-recipe.description = The room recipes +channel-group-type.neeo.room-scenario.label = Scenarios +channel-group-type.neeo.room-scenario.description = The room scenarios +channel-group-type.neeo.room-state.label = Room State +channel-group-type.neeo.room-state.description = The room's state + +# channel types + +channel-type.neeo.brain-forwardactions.label = Forward Actions +channel-type.neeo.brain-forwardactions.description = The forward Actions +channel-type.neeo.device-macros-status.label = Label Dynamically Generated +channel-type.neeo.device-macros-status.description = Send ON to trigger the macro +channel-type.neeo.room-recipe-enabled.label = Label Dynamically Generated +channel-type.neeo.room-recipe-enabled.description = Whether the recipe is enabled or not. +channel-type.neeo.room-recipe-name.label = Label Dynamically Generated +channel-type.neeo.room-recipe-name.description = The recipe name +channel-type.neeo.room-recipe-status.label = Label Dynamically Generated +channel-type.neeo.room-recipe-status.description = Send ON to execute the recipe +channel-type.neeo.room-recipe-type.label = Label Dynamically Generated +channel-type.neeo.room-recipe-type.description = The type of recipe +channel-type.neeo.room-scenario-configured.label = Label Dynamically Generated +channel-type.neeo.room-scenario-configured.description = Whether the scenario is configured or not +channel-type.neeo.room-scenario-name.label = Label Dynamically Generated +channel-type.neeo.room-scenario-name.description = The scenario name +channel-type.neeo.room-scenario-status.label = Label Dynamically Generated +channel-type.neeo.room-scenario-status.description = Whether the scenario is running or not (send ON to turn on the scenario, OFF to turn off the scenario) +channel-type.neeo.room-state-currentstep.label = Current Step +channel-type.neeo.room-state-currentstep.description = The current step executing diff --git a/bundles/org.openhab.binding.neohub/src/main/resources/OH-INF/i18n/neohub.properties b/bundles/org.openhab.binding.neohub/src/main/resources/OH-INF/i18n/neohub.properties new file mode 100644 index 0000000000000..dddda2cf9d342 --- /dev/null +++ b/bundles/org.openhab.binding.neohub/src/main/resources/OH-INF/i18n/neohub.properties @@ -0,0 +1,84 @@ +# binding + +binding.neohub.name = NeoHub Binding +binding.neohub.description = This is the binding for Heatmiser NeoHub devices + +# thing types + +thing-type.neohub.neocontact.label = Heatmiser Contact Sensor +thing-type.neohub.neocontact.description = Heatmiser (wireless) Window or Door Contact +thing-type.neohub.neocontact.channel.batteryLowAlarm.label = Battery Low Alarm +thing-type.neohub.neocontact.channel.batteryLowAlarm.description = ON if the device has a low battery +thing-type.neohub.neohub.label = NeoHub +thing-type.neohub.neohub.description = Heatmiser NeoHub bridge to NeoStat and NeoPlug devices +thing-type.neohub.neoplug.label = Heatmiser NeoPlug +thing-type.neohub.neoplug.description = Heatmiser Neo Smart Plug +thing-type.neohub.neostat.label = Heatmiser NeoStat +thing-type.neohub.neostat.description = Heatmiser Neo Smart Thermostat +thing-type.neohub.neostat.channel.floorTemperature.label = Floor Temperature +thing-type.neohub.neostat.channel.floorTemperature.description = Actual floor temperature +thing-type.neohub.neostat.channel.roomTemperature.label = Room Temperature +thing-type.neohub.neostat.channel.roomTemperature.description = Actual room temperature +thing-type.neohub.neotemperaturesensor.label = Heatmiser Wireless Air Sensor +thing-type.neohub.neotemperaturesensor.description = Heatmiser (wireless) Temperature Sensor +thing-type.neohub.neotemperaturesensor.channel.batteryLowAlarm.label = Battery Low Alarm +thing-type.neohub.neotemperaturesensor.channel.batteryLowAlarm.description = ON if the device has a low battery +thing-type.neohub.neotemperaturesensor.channel.sensorTemperature.label = Temperature +thing-type.neohub.neotemperaturesensor.channel.sensorTemperature.description = Measured temperature value (Read-Only) + +# thing types config + +thing-type.config.neohub.neocontact.deviceNameInHub.label = Device Name +thing-type.config.neohub.neocontact.deviceNameInHub.description = Device Name that identifies the Contact in the NeoHub and Heatmiser App +thing-type.config.neohub.neohub.hostName.label = Host Name +thing-type.config.neohub.neohub.hostName.description = Host name (IP address) of the NeoHub +thing-type.config.neohub.neohub.pollingInterval.label = Polling Interval +thing-type.config.neohub.neohub.pollingInterval.description = Time (seconds) between polling the NeoHub (min=4, max/default=60) +thing-type.config.neohub.neohub.portNumber.label = Port Number +thing-type.config.neohub.neohub.portNumber.description = Port number of the NeoHub +thing-type.config.neohub.neohub.preferLegacyApi.label = Prefer Legacy API +thing-type.config.neohub.neohub.preferLegacyApi.description = Use the legacy API instead of the new API (if available) +thing-type.config.neohub.neohub.socketTimeout.label = Socket Timeout +thing-type.config.neohub.neohub.socketTimeout.description = Time (seconds) to wait for connections to the Hub (min/default=5, max=20) +thing-type.config.neohub.neoplug.deviceNameInHub.label = Device Name +thing-type.config.neohub.neoplug.deviceNameInHub.description = Device Name that identifies the NeoPlug device in the NeoHub and Heatmiser App +thing-type.config.neohub.neostat.deviceNameInHub.label = Device Name +thing-type.config.neohub.neostat.deviceNameInHub.description = Device Name that identifies the NeoStat device in the NeoHub and Heatmiser App +thing-type.config.neohub.neotemperaturesensor.deviceNameInHub.label = Device Name +thing-type.config.neohub.neotemperaturesensor.deviceNameInHub.description = Device Name that identifies the Temperature Sensor in the NeoHub and Heatmiser App + +# channel types + +channel-type.neohub.contactState.label = Contact State +channel-type.neohub.contactState.description = The state of the contact +channel-type.neohub.meshNetworkQoS.label = Mesh Network QoS +channel-type.neohub.meshNetworkQoS.description = Quality of Service: percentage of configured devices currently connected to the RF mesh network +channel-type.neohub.occupancyModePresent.label = Occupancy Mode Present +channel-type.neohub.occupancyModePresent.description = The Thermostat is in the Present Occupancy Mode (Off=Absent, On=Present) +channel-type.neohub.plugAutoMode.label = Plug Auto Mode +channel-type.neohub.plugAutoMode.description = The Plug is in Automatic Mode (Off=Manual, On=Automatic) +channel-type.neohub.plugOutputState.label = Plug Output State +channel-type.neohub.plugOutputState.description = The state of the Plug switch, Off or On +channel-type.neohub.targetTemperature.label = Target Temperature +channel-type.neohub.targetTemperature.description = Target temperature setting of the room +channel-type.neohub.temperature.label = Temperature +channel-type.neohub.temperature.description = Measured temperature value (Read-Only) +channel-type.neohub.thermostatOutputState.label = Thermostat Output State +channel-type.neohub.thermostatOutputState.description = Status of whether the thermostat is Off, or calling for Heat + +# channel types config + +channel-type.config.neohub.contactState.holdOnlineState.label = Hold Online State +channel-type.config.neohub.contactState.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.occupancyModePresent.holdOnlineState.label = Hold Online State +channel-type.config.neohub.occupancyModePresent.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.plugAutoMode.holdOnlineState.label = Hold Online State +channel-type.config.neohub.plugAutoMode.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.plugOutputState.holdOnlineState.label = Hold Online State +channel-type.config.neohub.plugOutputState.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.targetTemperature.holdOnlineState.label = Hold Online State +channel-type.config.neohub.targetTemperature.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.temperature.holdOnlineState.label = Hold Online State +channel-type.config.neohub.temperature.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value +channel-type.config.neohub.thermostatOutputState.holdOnlineState.label = Hold Online State +channel-type.config.neohub.thermostatOutputState.holdOnlineState.description = If the device loses its RF mesh connection, hold the last known state display value diff --git a/bundles/org.openhab.binding.nest/src/main/resources/OH-INF/i18n/nest.properties b/bundles/org.openhab.binding.nest/src/main/resources/OH-INF/i18n/nest.properties new file mode 100644 index 0000000000000..2dc4b7a026892 --- /dev/null +++ b/bundles/org.openhab.binding.nest/src/main/resources/OH-INF/i18n/nest.properties @@ -0,0 +1,310 @@ +# binding + +binding.nest.name = Nest Binding +binding.nest.description = Nest connects to the Nest cloud and allows control of the various Nest devices. + +# thing types + +thing-type.nest.sdm_account.label = Nest SDM Account +thing-type.nest.sdm_account.description = An account for using the Smart Device Management (SDM) API +thing-type.nest.sdm_camera.label = Nest Camera +thing-type.nest.sdm_camera.description = A Nest Camera registered with your SDM account +thing-type.nest.sdm_display.label = Nest Display +thing-type.nest.sdm_display.description = A Nest Display registered with your SDM account +thing-type.nest.sdm_doorbell.label = Nest Doorbell +thing-type.nest.sdm_doorbell.description = A Nest Doorbell registered with your SDM account +thing-type.nest.sdm_thermostat.label = Nest Thermostat +thing-type.nest.sdm_thermostat.description = A Thermostat to control the various aspects of the house's HVAC system +thing-type.nest.wwn_account.label = Nest WWN Account +thing-type.nest.wwn_account.description = An account for using the Works with Nest (WWN) API +thing-type.nest.wwn_camera.label = Nest Cam +thing-type.nest.wwn_camera.description = A Nest Camera registered with your WWN account +thing-type.nest.wwn_camera.group.last_event.label = Last Event +thing-type.nest.wwn_camera.group.last_event.description = Information about the last camera event (requires Nest Aware subscription) +thing-type.nest.wwn_smoke_detector.label = Nest Protect +thing-type.nest.wwn_smoke_detector.description = The smoke detector/Nest Protect for the account +thing-type.nest.wwn_structure.label = Nest Structure +thing-type.nest.wwn_structure.description = The Nest structure defines the house the account has setup on Nest. You will only have more than one structure if you have more than one house +thing-type.nest.wwn_thermostat.label = Nest Thermostat +thing-type.nest.wwn_thermostat.description = A Thermostat to control the various aspects of the house's HVAC system + +# thing types config + +thing-type.config.nest.sdm_account.group.pubsub.label = Pub/Sub +thing-type.config.nest.sdm_account.group.pubsub.description = The parameters used when communicating with the Pub/Sub API +thing-type.config.nest.sdm_account.group.sdm.label = SDM +thing-type.config.nest.sdm_account.group.sdm.description = The parameters used when communicating with the SDM API +thing-type.config.nest.sdm_account.pubsubAuthorizationCode.label = Authorization Code +thing-type.config.nest.sdm_account.pubsubAuthorizationCode.description = The one time authorization code used to retrieve the refresh and access token used with the Pub/Sub API. The code is obtained by following the instructions at the following URL in your browser:

https://accounts.google.com/o/oauth2/auth?client_id={{ClientID}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/pubsub +thing-type.config.nest.sdm_account.pubsubClientId.label = Client ID +thing-type.config.nest.sdm_account.pubsubClientId.description = Identifies the OAuth 2.0 client used for accessing the Pub/Sub subscription +thing-type.config.nest.sdm_account.pubsubClientSecret.label = Client Secret +thing-type.config.nest.sdm_account.pubsubClientSecret.description = The OAuth 2.0 client secret used for accessing the Pub/Sub subscription +thing-type.config.nest.sdm_account.pubsubProjectId.label = Project ID +thing-type.config.nest.sdm_account.pubsubProjectId.description = Identifies the Google Cloud Platform project where the Pub/Sub subscription is created +thing-type.config.nest.sdm_account.pubsubSubscriptionId.label = Subscription ID +thing-type.config.nest.sdm_account.pubsubSubscriptionId.description = Identifies the subscription that is created for subscribing to SDM Pub/Sub events +thing-type.config.nest.sdm_account.sdmAuthorizationCode.label = Authorization Code +thing-type.config.nest.sdm_account.sdmAuthorizationCode.description = The one time authorization code used to retrieve the refresh and access token used with the SDM API. The code is obtained by following the instructions at the following URL in your browser:

https://nestservices.google.com/partnerconnections/{{ProjectID}}/auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&prompt=consent&client_id={{ClientID}}&response_type=code&scope=https://www.googleapis.com/auth/sdm.service +thing-type.config.nest.sdm_account.sdmClientId.label = Client ID +thing-type.config.nest.sdm_account.sdmClientId.description = Identifies the OAuth 2.0 client used for accessing the SDM project +thing-type.config.nest.sdm_account.sdmClientSecret.label = Client Secret +thing-type.config.nest.sdm_account.sdmClientSecret.description = The OAuth 2.0 client secret used for accessing the SDM project +thing-type.config.nest.sdm_account.sdmProjectId.label = Project ID +thing-type.config.nest.sdm_account.sdmProjectId.description = The UUID that identifies the SDM project in the SDM "Device Access Console" +thing-type.config.nest.sdm_device.deviceId.label = Device ID +thing-type.config.nest.sdm_device.refreshInterval.label = Refresh Interval +thing-type.config.nest.sdm_device.refreshInterval.description = This is refresh interval in seconds to update the Nest device information +thing-type.config.nest.wwn_account.accessToken.label = Access Token +thing-type.config.nest.wwn_account.accessToken.description = The access token used for authenticating to the WWN API +thing-type.config.nest.wwn_account.group.oauth.label = WWN API OAuth +thing-type.config.nest.wwn_account.group.oauth.description = The OAuth parameters used when communicating with the WWN API +thing-type.config.nest.wwn_account.productId.label = Product ID +thing-type.config.nest.wwn_account.productId.description = The product ID from the Nest product page +thing-type.config.nest.wwn_account.productSecret.label = Product Secret +thing-type.config.nest.wwn_account.productSecret.description = The product secret from the Nest product page +thing-type.config.nest.wwn_device.deviceId.label = Device ID +thing-type.config.nest.wwn_structure.structureId.label = Structure ID + +# channel group types + +channel-group-type.nest.SDMChimeEvent.label = Chime Event +channel-group-type.nest.SDMChimeEvent.description = Information about the last chime event +channel-group-type.nest.SDMChimeEvent.channel.image.label = Chime Event Image +channel-group-type.nest.SDMChimeEvent.channel.image.description = Static image based on a chime event +channel-group-type.nest.SDMChimeEvent.channel.timestamp.label = Chime Event Timestamp +channel-group-type.nest.SDMChimeEvent.channel.timestamp.description = The last time that the door chime was pressed +channel-group-type.nest.SDMLiveStream.label = Live Stream +channel-group-type.nest.SDMLiveStream.description = Information for accessing the live stream +channel-group-type.nest.SDMMotionEvent.label = Motion Event +channel-group-type.nest.SDMMotionEvent.description = Information about the last motion event +channel-group-type.nest.SDMMotionEvent.channel.image.label = Motion Event Image +channel-group-type.nest.SDMMotionEvent.channel.image.description = Static image based on a motion event +channel-group-type.nest.SDMMotionEvent.channel.timestamp.label = Motion Event Timestamp +channel-group-type.nest.SDMMotionEvent.channel.timestamp.description = The last time that motion was detected +channel-group-type.nest.SDMPersonEvent.label = Person Event +channel-group-type.nest.SDMPersonEvent.description = Information about the last person event +channel-group-type.nest.SDMPersonEvent.channel.image.label = Person Event Image +channel-group-type.nest.SDMPersonEvent.channel.image.description = Static image based on a person event +channel-group-type.nest.SDMPersonEvent.channel.timestamp.label = Person Event Timestamp +channel-group-type.nest.SDMPersonEvent.channel.timestamp.description = The last time that a person was detected +channel-group-type.nest.SDMSoundEvent.label = Sound Event +channel-group-type.nest.SDMSoundEvent.description = Information about the last sound event +channel-group-type.nest.SDMSoundEvent.channel.image.label = Sound Event Image +channel-group-type.nest.SDMSoundEvent.channel.image.description = Static image based on a sound event +channel-group-type.nest.SDMSoundEvent.channel.timestamp.label = Sound Event Timestamp +channel-group-type.nest.SDMSoundEvent.channel.timestamp.description = The last time that a sound was detected +channel-group-type.nest.WWNCamera.label = Camera +channel-group-type.nest.WWNCamera.description = Information about the camera +channel-group-type.nest.WWNCameraEvent.label = Camera Event +channel-group-type.nest.WWNCameraEvent.description = Information about the camera event + +# channel types + +channel-type.nest.SDMAmbientHumidity.label = Ambient Humidity +channel-type.nest.SDMAmbientHumidity.description = Lists the current ambient humidity percentage from the thermostat +channel-type.nest.SDMAmbientTemperature.label = Ambient Temperature +channel-type.nest.SDMAmbientTemperature.description = Lists the current ambient temperature from the thermostat +channel-type.nest.SDMCameraEventImage.label = Image +channel-type.nest.SDMCameraEventImage.description = Static image based on a event +channel-type.nest.SDMCameraEventTimestamp.label = Timestamp +channel-type.nest.SDMCameraEventTimestamp.description = The time that the event occurred +channel-type.nest.SDMCurrentEcoMode.label = Current Eco Mode +channel-type.nest.SDMCurrentEcoMode.description = Lists the current eco mode from the thermostat +channel-type.nest.SDMCurrentEcoMode.state.option.OFF = off +channel-type.nest.SDMCurrentEcoMode.state.option.MANUAL_ECO = manual eco +channel-type.nest.SDMCurrentMode.label = Current Mode +channel-type.nest.SDMCurrentMode.description = Lists the current mode from the thermostat +channel-type.nest.SDMCurrentMode.state.option.OFF = off +channel-type.nest.SDMCurrentMode.state.option.HEAT = heating +channel-type.nest.SDMCurrentMode.state.option.COOL = cooling +channel-type.nest.SDMCurrentMode.state.option.HEATCOOL = heat/cool +channel-type.nest.SDMFanTimerMode.label = Fan Timer Mode +channel-type.nest.SDMFanTimerMode.description = Lists the current fan timer mode +channel-type.nest.SDMFanTimerTimeout.label = Fan Timer Timeout +channel-type.nest.SDMFanTimerTimeout.description = Timestamp at which timer mode turns OFF +channel-type.nest.SDMHVACStatus.label = HVAC Status +channel-type.nest.SDMHVACStatus.description = Provides the thermostat HVAC Status +channel-type.nest.SDMHVACStatus.state.option.OFF = off +channel-type.nest.SDMHVACStatus.state.option.HEATING = heating +channel-type.nest.SDMHVACStatus.state.option.COOLING = cooling +channel-type.nest.SDMLiveStreamCurrentToken.label = Live Stream Current Token +channel-type.nest.SDMLiveStreamCurrentToken.description = Live stream current token value +channel-type.nest.SDMLiveStreamExpirationTimestamp.label = Live Stream Expiration Timestamp +channel-type.nest.SDMLiveStreamExpirationTimestamp.description = Live stream token expiration time +channel-type.nest.SDMLiveStreamExtensionToken.label = Live Stream Extension Token +channel-type.nest.SDMLiveStreamExtensionToken.description = Live stream token extension value +channel-type.nest.SDMLiveStreamUrl.label = Live Stream URL +channel-type.nest.SDMLiveStreamUrl.description = The RTSP video stream URL for the most recent event +channel-type.nest.SDMMaximumTemperature.label = Maximum Temperature Setting +channel-type.nest.SDMMaximumTemperature.description = Lists the maximum temperature setting from the thermostat +channel-type.nest.SDMMinimumTemperature.label = Minimum Temperature Setting +channel-type.nest.SDMMinimumTemperature.description = Lists the minimum temperature setting from the thermostat +channel-type.nest.SDMTargetTemperature.label = Target Temperature +channel-type.nest.SDMTargetTemperature.description = Lists the target temperature setting from the thermostat +channel-type.nest.SDMTemperatureCool.label = Cool Temperature +channel-type.nest.SDMTemperatureCool.description = Lists the cool temperature setting from the thermostat +channel-type.nest.SDMTemperatureHeat.label = Heat Temperature +channel-type.nest.SDMTemperatureHeat.description = Lists the heat temperature setting from the thermostat +channel-type.nest.WWNAppUrl.label = App URL +channel-type.nest.WWNAppUrl.description = The app URL for the camera, allows you to see the camera in an app +channel-type.nest.WWNAudioInputEnabled.label = Audio Input Enabled +channel-type.nest.WWNAudioInputEnabled.description = If the audio input is enabled for this camera +channel-type.nest.WWNAway.label = Away +channel-type.nest.WWNAway.description = Away state of the structure +channel-type.nest.WWNAway.state.option.AWAY = Away +channel-type.nest.WWNAway.state.option.HOME = Home +channel-type.nest.WWNCameraEventActivityZones.label = Activity Zones +channel-type.nest.WWNCameraEventActivityZones.description = Identifiers for activity zones that detected the event (comma separated) +channel-type.nest.WWNCameraEventAnimatedImageUrl.label = Animated Image URL +channel-type.nest.WWNCameraEventAnimatedImageUrl.description = The URL showing an animated image for the camera event +channel-type.nest.WWNCameraEventAppUrl.label = App URL +channel-type.nest.WWNCameraEventAppUrl.description = The app URL for the camera event, allows you to see the camera event in an app +channel-type.nest.WWNCameraEventEndTime.label = End Time +channel-type.nest.WWNCameraEventEndTime.description = Timestamp when the camera event ended +channel-type.nest.WWNCameraEventHasMotion.label = Has Motion +channel-type.nest.WWNCameraEventHasMotion.description = If motion was detected in the camera event +channel-type.nest.WWNCameraEventHasPerson.label = Has Person +channel-type.nest.WWNCameraEventHasPerson.description = If a person was detected in the camera event +channel-type.nest.WWNCameraEventHasSound.label = Has Sound +channel-type.nest.WWNCameraEventHasSound.description = If sound was detected in the camera event +channel-type.nest.WWNCameraEventImageUrl.label = Image URL +channel-type.nest.WWNCameraEventImageUrl.description = The URL showing an image for the camera event +channel-type.nest.WWNCameraEventStartTime.label = Start Time +channel-type.nest.WWNCameraEventStartTime.description = Timestamp when the camera event started +channel-type.nest.WWNCameraEventUrlsExpireTime.label = URLs Expire Time +channel-type.nest.WWNCameraEventUrlsExpireTime.description = Timestamp when the camera event URLs expire +channel-type.nest.WWNCameraEventWebUrl.label = Web URL +channel-type.nest.WWNCameraEventWebUrl.description = The web URL for the camera event, allows you to see the camera event in a web page +channel-type.nest.WWNCanCool.label = Can Cool +channel-type.nest.WWNCanCool.description = If the thermostat can actually turn on cooling +channel-type.nest.WWNCanHeat.label = Can Heat +channel-type.nest.WWNCanHeat.description = If the thermostat can actually turn on heating +channel-type.nest.WWNCoAlarmState.label = CO Alarm State +channel-type.nest.WWNCoAlarmState.description = Carbon monoxide alarm state +channel-type.nest.WWNCoAlarmState.state.option.OK = ok +channel-type.nest.WWNCoAlarmState.state.option.EMERGENCY = emergency +channel-type.nest.WWNCoAlarmState.state.option.WARNING = warning +channel-type.nest.WWNCountryCode.label = Country Code +channel-type.nest.WWNCountryCode.description = Country code of the structure +channel-type.nest.WWNEcoMaxSetPoint.label = Eco Max Set Point +channel-type.nest.WWNEcoMaxSetPoint.description = The eco range max set point temperature +channel-type.nest.WWNEcoMinSetPoint.label = Eco Min Set Point +channel-type.nest.WWNEcoMinSetPoint.description = The eco range min set point temperature +channel-type.nest.WWNEtaBegin.label = ETA +channel-type.nest.WWNEtaBegin.description = Estimated time of arrival at home, will setup the heat to turn on and be warm by the time you arrive +channel-type.nest.WWNFanTimerActive.label = Fan Timer Active +channel-type.nest.WWNFanTimerActive.description = If the fan timer is engaged +channel-type.nest.WWNFanTimerDuration.label = Fan Timer Duration +channel-type.nest.WWNFanTimerDuration.description = Length of time that the fan is set to run +channel-type.nest.WWNFanTimerDuration.state.option.15 = 15 min +channel-type.nest.WWNFanTimerDuration.state.option.30 = 30 min +channel-type.nest.WWNFanTimerDuration.state.option.45 = 45 min +channel-type.nest.WWNFanTimerDuration.state.option.60 = 1 h +channel-type.nest.WWNFanTimerDuration.state.option.120 = 2 h +channel-type.nest.WWNFanTimerDuration.state.option.240 = 4 h +channel-type.nest.WWNFanTimerDuration.state.option.480 = 8 h +channel-type.nest.WWNFanTimerDuration.state.option.960 = 16 h +channel-type.nest.WWNFanTimerTimeout.label = Fan Timer Timeout +channel-type.nest.WWNFanTimerTimeout.description = Timestamp when the fan stops running +channel-type.nest.WWNHasFan.label = Has Fan +channel-type.nest.WWNHasFan.description = If the thermostat can control the fan +channel-type.nest.WWNHasLeaf.label = Has Leaf +channel-type.nest.WWNHasLeaf.description = If the thermostat is currently in a leaf mode +channel-type.nest.WWNHumidity.label = Humidity +channel-type.nest.WWNHumidity.description = Indicates the current relative humidity +channel-type.nest.WWNLastConnection.label = Last Connection +channel-type.nest.WWNLastConnection.description = Timestamp of the last successful interaction with Nest +channel-type.nest.WWNLastManualTestTime.label = Last Manual Test Time +channel-type.nest.WWNLastManualTestTime.description = Timestamp of the last successful manual test +channel-type.nest.WWNLastOnlineChange.label = Last Online Change +channel-type.nest.WWNLastOnlineChange.description = Timestamp of the last online status change +channel-type.nest.WWNLocked.label = Locked +channel-type.nest.WWNLocked.description = If the thermostat has the temperature locked to only be within a set range +channel-type.nest.WWNLockedMaxSetPoint.label = Locked Max Set Point +channel-type.nest.WWNLockedMaxSetPoint.description = The locked range max set point temperature +channel-type.nest.WWNLockedMinSetPoint.label = Locked Min Set Point +channel-type.nest.WWNLockedMinSetPoint.description = The locked range min set point temperature +channel-type.nest.WWNManualTestActive.label = Manual Test Active +channel-type.nest.WWNManualTestActive.description = If the manual test is currently active +channel-type.nest.WWNMaxSetPoint.label = Max Set Point +channel-type.nest.WWNMaxSetPoint.description = The max set point temperature +channel-type.nest.WWNMinSetPoint.label = Min Set Point +channel-type.nest.WWNMinSetPoint.description = The min set point temperature +channel-type.nest.WWNMode.label = Mode +channel-type.nest.WWNMode.description = Current mode of the Nest thermostat +channel-type.nest.WWNMode.state.option.OFF = off +channel-type.nest.WWNMode.state.option.ECO = eco +channel-type.nest.WWNMode.state.option.HEAT = heating +channel-type.nest.WWNMode.state.option.COOL = cooling +channel-type.nest.WWNMode.state.option.HEAT_COOL = heat/cool +channel-type.nest.WWNPeakPeriodEndTime.label = Peak Period End Time +channel-type.nest.WWNPeakPeriodEndTime.description = Peak period end for the Rush Hour Rewards program +channel-type.nest.WWNPeakPeriodStartTime.label = Peak Period Start Time +channel-type.nest.WWNPeakPeriodStartTime.description = Peak period start for the Rush Hour Rewards program +channel-type.nest.WWNPostalCode.label = Postal Code +channel-type.nest.WWNPostalCode.description = Postal code of the structure +channel-type.nest.WWNPreviousMode.label = Previous Mode +channel-type.nest.WWNPreviousMode.description = The previous mode of the Nest thermostat +channel-type.nest.WWNPreviousMode.state.option.OFF = off +channel-type.nest.WWNPreviousMode.state.option.ECO = eco +channel-type.nest.WWNPreviousMode.state.option.HEAT = heating +channel-type.nest.WWNPreviousMode.state.option.COOL = cooling +channel-type.nest.WWNPreviousMode.state.option.HEAT_COOL = heat/cool +channel-type.nest.WWNPublicShareEnabled.label = Public Share Enabled +channel-type.nest.WWNPublicShareEnabled.description = If the public sharing of this camera is enabled +channel-type.nest.WWNPublicShareUrl.label = Public Share URL +channel-type.nest.WWNPublicShareUrl.description = The publicly available URL for the camera +channel-type.nest.WWNRushHourRewardsEnrollment.label = Rush Hour Rewards +channel-type.nest.WWNRushHourRewardsEnrollment.description = If rush hour rewards system is enabled or not +channel-type.nest.WWNSecurityState.label = Security State +channel-type.nest.WWNSecurityState.description = Security state of the structure +channel-type.nest.WWNSecurityState.state.option.OK = ok +channel-type.nest.WWNSecurityState.state.option.DETER = deter +channel-type.nest.WWNSetPoint.label = Set Point +channel-type.nest.WWNSetPoint.description = The set point temperature +channel-type.nest.WWNSmokeAlarmState.label = Smoke Alarm State +channel-type.nest.WWNSmokeAlarmState.description = Smoke alarm state +channel-type.nest.WWNSmokeAlarmState.state.option.OK = ok +channel-type.nest.WWNSmokeAlarmState.state.option.EMERGENCY = emergency +channel-type.nest.WWNSmokeAlarmState.state.option.WARNING = warning +channel-type.nest.WWNSnapshotUrl.label = Snapshot URL +channel-type.nest.WWNSnapshotUrl.description = The URL showing a snapshot of the camera +channel-type.nest.WWNState.label = State +channel-type.nest.WWNState.description = The active state of the Nest thermostat +channel-type.nest.WWNState.state.option.OFF = off +channel-type.nest.WWNState.state.option.HEATING = heating +channel-type.nest.WWNState.state.option.COOLING = cooling +channel-type.nest.WWNStreaming.label = Streaming +channel-type.nest.WWNStreaming.description = If the camera is currently streaming +channel-type.nest.WWNSunlightCorrectionActive.label = Sunlight Correction Active +channel-type.nest.WWNSunlightCorrectionActive.description = If sunlight correction is active +channel-type.nest.WWNSunlightCorrectionEnabled.label = Sunlight Correction Enabled +channel-type.nest.WWNSunlightCorrectionEnabled.description = If sunlight correction is enabled +channel-type.nest.WWNTemperature.label = Temperature +channel-type.nest.WWNTemperature.description = Current temperature +channel-type.nest.WWNTimeToTarget.label = Time to Target +channel-type.nest.WWNTimeToTarget.description = Time left to the target temperature approximately +channel-type.nest.WWNTimeZone.label = Time Zone +channel-type.nest.WWNTimeZone.description = The time zone for the structure +channel-type.nest.WWNUiColorState.label = UI Color State +channel-type.nest.WWNUiColorState.description = Current color state of the protect +channel-type.nest.WWNUiColorState.state.option.GRAY = gray +channel-type.nest.WWNUiColorState.state.option.GREEN = green +channel-type.nest.WWNUiColorState.state.option.YELLOW = yellow +channel-type.nest.WWNUiColorState.state.option.RED = red +channel-type.nest.WWNUsingEmergencyHeat.label = Using Emergency Heat +channel-type.nest.WWNUsingEmergencyHeat.description = If the system is currently using emergency heat +channel-type.nest.WWNVideoHistoryEnabled.label = Video History Enabled +channel-type.nest.WWNVideoHistoryEnabled.description = If the video history is enabled for this camera +channel-type.nest.WWNWebUrl.label = Web URL +channel-type.nest.WWNWebUrl.description = The web URL for the camera, allows you to see the camera in a web page + +# channel types config + +channel-type.config.nest.sdm_camera_image.imageHeight.label = Image Height +channel-type.config.nest.sdm_camera_image.imageHeight.description = The height in pixels used for generating event images. This parameter is ignored when the image width parameter is also configured. +channel-type.config.nest.sdm_camera_image.imageWidth.label = Image Width +channel-type.config.nest.sdm_camera_image.imageWidth.description = The width in pixels used for generating event images. A default value of 480 pixels is used if not configured. +channel-type.config.nest.sdm_fan_timer_mode.fanTimerDuration.label = Fan Timer Duration +channel-type.config.nest.sdm_fan_timer_mode.fanTimerDuration.description = Specifies the length of time in seconds that the timer is set to run. diff --git a/bundles/org.openhab.binding.network/src/main/resources/OH-INF/i18n/network.properties b/bundles/org.openhab.binding.network/src/main/resources/OH-INF/i18n/network.properties new file mode 100644 index 0000000000000..425e67c94e299 --- /dev/null +++ b/bundles/org.openhab.binding.network/src/main/resources/OH-INF/i18n/network.properties @@ -0,0 +1,84 @@ +# binding + +binding.network.name = Network Binding +binding.network.description = The Network Binding can be used for device presence detection and to determine network device health + +# binding config + +binding.config.network.allowDHCPlisten.label = Listen for DHCP Requests +binding.config.network.allowDHCPlisten.description = Usually a device requests an IP address in an IPv4 network with the help of DHCP as soon as it enters a network. If we listen to those packets, we can detect a device presence even faster. You need elevated access rights (see readme) for this to work. +binding.config.network.allowSystemPings.label = Allow System Pings +binding.config.network.allowSystemPings.description = Allows or disallows to use system pings next to the java integrated ping functionality. On windows the system ping works more reliable most of the time. +binding.config.network.arpPingToolPath.label = ARP Ping Tool Path +binding.config.network.arpPingToolPath.description = If your arp ping tool is not called arping and cannot be found in the PATH environment, you can configure the absolute path / tool name here. +binding.config.network.cacheDeviceStateTimeInMS.label = Cache Time +binding.config.network.cacheDeviceStateTimeInMS.description = The result of a device presence detection is cached for a small amount of time. Be aware that no new pings will be issued within this time frame, even if explicitly requested. +binding.config.network.preferResponseTimeAsLatency.label = Use Response Time as Latency +binding.config.network.preferResponseTimeAsLatency.description = If enabled, an attempt will be made to extract the latency from the output of the ping command. If no such latency value is found in the ping command output, the time to execute the ping command is used as fallback latency. If disabled, the time to execute the ping command is always used as latency value. + +# thing types + +thing-type.network.pingdevice.label = Pingable Network Device +thing-type.network.pingdevice.description = The presence detection is performed by using ICMP and, if available, ARP pings. You can change the arping tool path in the binding configuration. DHCP sniffing is performed for faster network reentry discovery. +thing-type.network.servicedevice.label = Network Device with Running Service +thing-type.network.servicedevice.description = A device which reachable state is detected by connecting to a TCP port. DHCP sniffing is performed for faster network reentry discovery. +thing-type.network.speedtest.label = SpeedTest +thing-type.network.speedtest.description = Provides information about bandwidth speed. +thing-type.network.speedtest.channel.testEnd.label = Test End +thing-type.network.speedtest.channel.testStart.label = Test Start + +# thing types config + +thing-type.config.network.pingdevice.hostname.label = Hostname or IP +thing-type.config.network.pingdevice.hostname.description = Hostname or IP of the device +thing-type.config.network.pingdevice.macAddress.label = MAC Address +thing-type.config.network.pingdevice.macAddress.description = MAC address used for waking the device by the Wake-on-LAN action +thing-type.config.network.pingdevice.refreshInterval.label = Refresh Interval +thing-type.config.network.pingdevice.refreshInterval.description = States how long to wait after a device state update before the next refresh shall occur (in ms) +thing-type.config.network.pingdevice.retry.label = Retry +thing-type.config.network.pingdevice.retry.description = How many refresh interval cycles should a presence detection should take place, before the device is stated as offline +thing-type.config.network.pingdevice.timeout.label = Timeout +thing-type.config.network.pingdevice.timeout.description = States how long to wait for a response (in ms), before if a device is stated as offline +thing-type.config.network.servicedevice.hostname.label = Hostname or IP +thing-type.config.network.servicedevice.hostname.description = Hostname or IP of the device +thing-type.config.network.servicedevice.macAddress.label = MAC Address +thing-type.config.network.servicedevice.macAddress.description = MAC address used for waking the device by the Wake-on-LAN action +thing-type.config.network.servicedevice.port.label = Port +thing-type.config.network.servicedevice.port.description = The port on which the device can be accessed. Windows systems usually have the 445 port open. Webservers are on port 80. +thing-type.config.network.servicedevice.refreshInterval.label = Refresh Interval +thing-type.config.network.servicedevice.refreshInterval.description = States how long to wait after a device state update before the next refresh shall occur (in ms) +thing-type.config.network.servicedevice.retry.label = Retry +thing-type.config.network.servicedevice.retry.description = Defines how many times a connection attempt shall occur, before the device is stated as offline +thing-type.config.network.servicedevice.timeout.label = Timeout +thing-type.config.network.servicedevice.timeout.description = States how long to wait for a response (in ms), before if a device is stated as offline +thing-type.config.network.speedtest.fileName.label = File Name +thing-type.config.network.speedtest.fileName.description = Name of the file to download from test server +thing-type.config.network.speedtest.initialDelay.label = Initial Delay +thing-type.config.network.speedtest.initialDelay.description = Delay before starting the first speed test (minutes) after initialization of the binding. +thing-type.config.network.speedtest.maxTimeout.label = Timeouts +thing-type.config.network.speedtest.maxTimeout.description = Number of timeout that can happend before the device is stated as offline +thing-type.config.network.speedtest.refreshInterval.label = Refresh Time Interval +thing-type.config.network.speedtest.refreshInterval.description = Refresh time interval in minutes. +thing-type.config.network.speedtest.uploadSize.label = Upload Size +thing-type.config.network.speedtest.uploadSize.description = Size of the file to be uploaded (bytes). +thing-type.config.network.speedtest.url.label = Test Server URL +thing-type.config.network.speedtest.url.description = Url of the speed test server + +# channel types + +channel-type.network.Timestamp.label = Timestamp +channel-type.network.Timestamp.description = Status timestamp +channel-type.network.isRunning.label = Test Running +channel-type.network.isRunning.description = Indicates if a test is currently ongoing +channel-type.network.lastseen.label = Last Seen +channel-type.network.lastseen.description = States the last seen date/time +channel-type.network.latency.label = Latency +channel-type.network.latency.description = States the latency time +channel-type.network.online.label = Online +channel-type.network.online.description = States whether a device is online or offline +channel-type.network.progress.label = Progress +channel-type.network.progress.description = Current Test progression +channel-type.network.rateDown.label = Download Rate +channel-type.network.rateDown.description = Current download rate +channel-type.network.rateUp.label = Upload Rate +channel-type.network.rateUp.description = Current upload rate diff --git a/bundles/org.openhab.binding.networkupstools/src/main/resources/OH-INF/i18n/networkupstools.properties b/bundles/org.openhab.binding.networkupstools/src/main/resources/OH-INF/i18n/networkupstools.properties new file mode 100644 index 0000000000000..050f598d81272 --- /dev/null +++ b/bundles/org.openhab.binding.networkupstools/src/main/resources/OH-INF/i18n/networkupstools.properties @@ -0,0 +1,107 @@ +# binding + +binding.networkupstools.name = Network UPS Tools Binding +binding.networkupstools.description = Binding for connecting to Network UPS Tools (NUT) servers + +# thing types + +thing-type.networkupstools.ups.label = Network UPS Tool +thing-type.networkupstools.ups.description = Network UPS Tool Thing + +# thing types config + +thing-type.config.ups.config.device.label = Device +thing-type.config.ups.config.device.description = UPS server name +thing-type.config.ups.config.host.label = Host +thing-type.config.ups.config.host.description = UPS server host or ip-address +thing-type.config.ups.config.password.label = Password +thing-type.config.ups.config.password.description = UPS server password to login +thing-type.config.ups.config.port.label = Port +thing-type.config.ups.config.port.description = UPS server port +thing-type.config.ups.config.refresh.label = Refresh +thing-type.config.ups.config.refresh.description = Refresh interval for state updates in seconds +thing-type.config.ups.config.username.label = Username +thing-type.config.ups.config.username.description = UPS server username to login + +# channel types + +channel-type.networkupstools.battery-charge.label = Battery Charge +channel-type.networkupstools.battery-charge.description = Battery charge (percent) +channel-type.networkupstools.battery-runtime.label = Battery Runtime +channel-type.networkupstools.battery-runtime.description = Battery runtime (seconds) +channel-type.networkupstools.battery-voltage.label = Battery Voltage +channel-type.networkupstools.battery-voltage.description = Battery voltage (V) +channel-type.networkupstools.input-current-status.label = Input Current Status +channel-type.networkupstools.input-current-status.description = Status relative to the thresholds +channel-type.networkupstools.input-current.label = Input Current +channel-type.networkupstools.input-current.description = Input current (A) +channel-type.networkupstools.input-load.label = Input Load +channel-type.networkupstools.input-load.description = Load on (ePDU) input (percent of full) +channel-type.networkupstools.input-quality.label = Input Quality +channel-type.networkupstools.input-quality.description = Input power quality (*** opaque) +channel-type.networkupstools.input-realpower.label = Input Realpower +channel-type.networkupstools.input-realpower.description = Current sum value of all (ePDU) phases real power (W) +channel-type.networkupstools.input-transfer-reason.label = Input Transfer Reason +channel-type.networkupstools.input-transfer-reason.description = Reason for last transfer to battery (*** opaque) +channel-type.networkupstools.input-voltage-status.label = Input Voltage Status +channel-type.networkupstools.input-voltage-status.description = Status relative to the thresholds +channel-type.networkupstools.input-voltage.label = Input Voltage +channel-type.networkupstools.input-voltage.description = Input voltage (V) +channel-type.networkupstools.number-electric-current.label = Electric Current +channel-type.networkupstools.number-electric-current.description = Electric Current channel +channel-type.networkupstools.number-electric-potential.label = Electric Potential +channel-type.networkupstools.number-electric-potential.description = Electric Potential channel +channel-type.networkupstools.number-frequency.label = Frequency +channel-type.networkupstools.number-frequency.description = Frequency channel +channel-type.networkupstools.number-power.label = Power +channel-type.networkupstools.number-power.description = Power channel +channel-type.networkupstools.number-time.label = Time +channel-type.networkupstools.number-time.description = Time channel +channel-type.networkupstools.number.label = Number +channel-type.networkupstools.number.description = Number channel +channel-type.networkupstools.output-current.label = Output Current +channel-type.networkupstools.output-current.description = Output current (A) +channel-type.networkupstools.output-voltage.label = Output Voltage +channel-type.networkupstools.output-voltage.description = Output voltage (V) +channel-type.networkupstools.string.label = String +channel-type.networkupstools.string.description = String channel +channel-type.networkupstools.switch.label = Switch +channel-type.networkupstools.switch.description = Switch channel +channel-type.networkupstools.ups-alarm.label = UPS Alarm +channel-type.networkupstools.ups-alarm.description = UPS alarms +channel-type.networkupstools.ups-load.label = UPS Load +channel-type.networkupstools.ups-load.description = Load on UPS (percent) +channel-type.networkupstools.ups-power.label = UPS Power +channel-type.networkupstools.ups-power.description = Current value of apparent power (Volt-Amps) +channel-type.networkupstools.ups-realpower.label = UPS Realpower +channel-type.networkupstools.ups-realpower.description = Current value of real power (Watts) +channel-type.networkupstools.ups-status.label = UPS Status +channel-type.networkupstools.ups-status.description = Status of the UPS: OFF, OL,OB,LB,RB,OVER,TRIM,BOOST,CAL,BYPASS,NULL +channel-type.networkupstools.ups-status.state.option.OFF = Off +channel-type.networkupstools.ups-status.state.option.OL = Online +channel-type.networkupstools.ups-status.state.option.OB = On battery +channel-type.networkupstools.ups-status.state.option.LB = Low battery +channel-type.networkupstools.ups-status.state.option.CHRG = Charging +channel-type.networkupstools.ups-status.state.option.OL CHRG = Online, charging +channel-type.networkupstools.ups-status.state.option.OL LB = Online, low battery +channel-type.networkupstools.ups-status.state.option.OL CHRG LB = Online, charging, low battery +channel-type.networkupstools.ups-status.state.option.RB = Replace battery +channel-type.networkupstools.ups-status.state.option.OVER = Overload +channel-type.networkupstools.ups-status.state.option.TRIM = Voltage trim +channel-type.networkupstools.ups-status.state.option.BOOST = Voltage boost +channel-type.networkupstools.ups-status.state.option.CAL = Calibration +channel-type.networkupstools.ups-status.state.option.BYPASS = Bypass +channel-type.networkupstools.ups-status.state.option.NULL = Null +channel-type.networkupstools.ups-temperature.label = UPS Temperature +channel-type.networkupstools.ups-temperature.description = UPS temperature (degrees C) +channel-type.networkupstools.ups-test-result.label = UPS Test Result +channel-type.networkupstools.ups-test-result.description = Results of last self test (opaque string) + +# channel types config + +channel-type.config.ups.dynamic-channel-config-quantity-type.networkupstools.label = NUT Variable +channel-type.config.ups.dynamic-channel-config-quantity-type.networkupstools.description = The name of the NUT variable +channel-type.config.ups.dynamic-channel-config-quantity-type.unit.label = Unit +channel-type.config.ups.dynamic-channel-config-quantity-type.unit.description = The unit of the data +channel-type.config.ups.dynamic-channel-config.networkupstools.label = NUT Variable +channel-type.config.ups.dynamic-channel-config.networkupstools.description = The name of the NUT variable diff --git a/bundles/org.openhab.binding.nibeheatpump/src/main/resources/OH-INF/i18n/nibeheatpump.properties b/bundles/org.openhab.binding.nibeheatpump/src/main/resources/OH-INF/i18n/nibeheatpump.properties new file mode 100644 index 0000000000000..cb1dd7530dd4e --- /dev/null +++ b/bundles/org.openhab.binding.nibeheatpump/src/main/resources/OH-INF/i18n/nibeheatpump.properties @@ -0,0 +1,7426 @@ +# binding + +binding.nibeheatpump.name = NibeHeatPump Binding +binding.nibeheatpump.description = This is the binding for Nibe heat pumps. + +# thing types + +thing-type.nibeheatpump.f1x45-serial.label = Serial Port Connected F1145 and F1245 Heat Pumps +thing-type.nibeheatpump.f1x45-simulator.label = Simulator for Nibe F1145 and F1245 Heat Pumps +thing-type.nibeheatpump.f1x45-udp.label = UDP Connected Nibe F1145 and F1245 Heat Pumps +thing-type.nibeheatpump.f1x55-serial.label = Serial Port Connected F1155 and F1255 Heat Pumps +thing-type.nibeheatpump.f1x55-simulator.label = Simulator for Nibe F1155 and F1255 Heat Pumps +thing-type.nibeheatpump.f1x55-udp.label = UDP Connected Nibe F1155 and F1255 Heat Pumps +thing-type.nibeheatpump.f470-serial.label = Serial Port Connected F470 Heat Pumps +thing-type.nibeheatpump.f470-simulator.label = Simulator for Nibe F470 Heat Pumps +thing-type.nibeheatpump.f470-udp.label = UDP Connected Nibe F470 Heat Pumps +thing-type.nibeheatpump.f750-serial.label = Serial Port Connected F750 Heat Pump +thing-type.nibeheatpump.f750-simulator.label = Simulator for Nibe F750 Heat Pump +thing-type.nibeheatpump.f750-udp.label = UDP Connected Nibe F750 Heat Pump +thing-type.nibeheatpump.smo40-serial.label = Serial Port Connected SMO40 Heat Pumps +thing-type.nibeheatpump.smo40-simulator.label = Simulator for Nibe SMO40 Heat Pumps +thing-type.nibeheatpump.smo40-udp.label = UDP Connected Nibe SMO40 Heat Pumps + +# thing types config + +thing-type.config.nibeheatpump.f1x45-serial.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x45-serial.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-serial.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x45-serial.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-serial.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f1x45-serial.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x45-serial.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x45-serial.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x45-serial.sendAckToMODBUS40.label = Enable Acknowledges to MODBUS40 Messages +thing-type.config.nibeheatpump.f1x45-serial.sendAckToMODBUS40.description = Binding emulates MODBUS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x45-serial.sendAckToRMU40.label = Enable Acknowledges to RMU40 Messages +thing-type.config.nibeheatpump.f1x45-serial.sendAckToRMU40.description = Binding emulates RMU40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x45-serial.sendAckToSMS40.label = Enable Acknowledges to SMS40 Messages +thing-type.config.nibeheatpump.f1x45-serial.sendAckToSMS40.description = Binding emulates SMS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x45-serial.serialPort.label = Serial Port +thing-type.config.nibeheatpump.f1x45-serial.serialPort.description = Serial port to connect to the heat pump. +thing-type.config.nibeheatpump.f1x45-serial.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x45-serial.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x45-simulator.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x45-simulator.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-simulator.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x45-simulator.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-simulator.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f1x45-simulator.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x45-simulator.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x45-simulator.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x45-simulator.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x45-simulator.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x45-udp.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x45-udp.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-udp.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x45-udp.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x45-udp.enableWriteCommandsToRegisters.label = Registers List for Write Commands +thing-type.config.nibeheatpump.f1x45-udp.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x45-udp.hostName.label = Host Name +thing-type.config.nibeheatpump.f1x45-udp.hostName.description = Network address of the NibeGW. +thing-type.config.nibeheatpump.f1x45-udp.port.label = UDP Port +thing-type.config.nibeheatpump.f1x45-udp.port.description = UDP port to listening data packets from the NibeGW. +thing-type.config.nibeheatpump.f1x45-udp.readCommandsPort.label = UDP Port for Read Commands +thing-type.config.nibeheatpump.f1x45-udp.readCommandsPort.description = UDP port to send read commands to the NibeGW. +thing-type.config.nibeheatpump.f1x45-udp.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x45-udp.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x45-udp.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x45-udp.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x45-udp.writeCommandsPort.label = UDP Port for Write Commands +thing-type.config.nibeheatpump.f1x45-udp.writeCommandsPort.description = UDP port to send write commands to the NibeGW. +thing-type.config.nibeheatpump.f1x55-serial.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x55-serial.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-serial.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x55-serial.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-serial.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f1x55-serial.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x55-serial.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x55-serial.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x55-serial.sendAckToMODBUS40.label = Enable Acknowledges to MODBUS40 Messages +thing-type.config.nibeheatpump.f1x55-serial.sendAckToMODBUS40.description = Binding emulates MODBUS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x55-serial.sendAckToRMU40.label = Enable Acknowledges to RMU40 Messages +thing-type.config.nibeheatpump.f1x55-serial.sendAckToRMU40.description = Binding emulates RMU40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x55-serial.sendAckToSMS40.label = Enable Acknowledges to SMS40 Messages +thing-type.config.nibeheatpump.f1x55-serial.sendAckToSMS40.description = Binding emulates SMS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f1x55-serial.serialPort.label = Serial Port +thing-type.config.nibeheatpump.f1x55-serial.serialPort.description = Serial port to connect to the heat pump. +thing-type.config.nibeheatpump.f1x55-serial.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x55-serial.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x55-simulator.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x55-simulator.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-simulator.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x55-simulator.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-simulator.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f1x55-simulator.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x55-simulator.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x55-simulator.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x55-simulator.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x55-simulator.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x55-udp.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f1x55-udp.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-udp.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f1x55-udp.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f1x55-udp.enableWriteCommandsToRegisters.label = Registers List for Write Commands +thing-type.config.nibeheatpump.f1x55-udp.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f1x55-udp.hostName.label = Host Name +thing-type.config.nibeheatpump.f1x55-udp.hostName.description = Network address of the NibeGW. +thing-type.config.nibeheatpump.f1x55-udp.port.label = UDP Port +thing-type.config.nibeheatpump.f1x55-udp.port.description = UDP port to listening data packets from the NibeGW. +thing-type.config.nibeheatpump.f1x55-udp.readCommandsPort.label = UDP Port for Read Commands +thing-type.config.nibeheatpump.f1x55-udp.readCommandsPort.description = UDP port to send read commands to the NibeGW. +thing-type.config.nibeheatpump.f1x55-udp.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f1x55-udp.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f1x55-udp.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f1x55-udp.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f1x55-udp.writeCommandsPort.label = UDP Port for Write Commands +thing-type.config.nibeheatpump.f1x55-udp.writeCommandsPort.description = UDP port to send write commands to the NibeGW. +thing-type.config.nibeheatpump.f470-serial.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f470-serial.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-serial.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f470-serial.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-serial.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f470-serial.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f470-serial.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f470-serial.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f470-serial.sendAckToMODBUS40.label = Enable Acknowledges to MODBUS40 Messages +thing-type.config.nibeheatpump.f470-serial.sendAckToMODBUS40.description = Binding emulates MODBUS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f470-serial.sendAckToRMU40.label = Enable Acknowledges to RMU40 Messages +thing-type.config.nibeheatpump.f470-serial.sendAckToRMU40.description = Binding emulates RMU40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f470-serial.sendAckToSMS40.label = Enable Acknowledges to SMS40 Messages +thing-type.config.nibeheatpump.f470-serial.sendAckToSMS40.description = Binding emulates SMS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f470-serial.serialPort.label = Serial Port +thing-type.config.nibeheatpump.f470-serial.serialPort.description = Serial port to connect to the heat pump. +thing-type.config.nibeheatpump.f470-serial.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f470-serial.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f470-simulator.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f470-simulator.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-simulator.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f470-simulator.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-simulator.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f470-simulator.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f470-simulator.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f470-simulator.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f470-simulator.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f470-simulator.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f470-udp.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f470-udp.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-udp.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f470-udp.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f470-udp.enableWriteCommandsToRegisters.label = Registers List for Write Commands +thing-type.config.nibeheatpump.f470-udp.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.f470-udp.hostName.label = Host Name +thing-type.config.nibeheatpump.f470-udp.hostName.description = Network address of the NibeGW. +thing-type.config.nibeheatpump.f470-udp.port.label = UDP Port +thing-type.config.nibeheatpump.f470-udp.port.description = UDP port to listening data packets from the NibeGW. +thing-type.config.nibeheatpump.f470-udp.readCommandsPort.label = UDP Port for Read Commands +thing-type.config.nibeheatpump.f470-udp.readCommandsPort.description = UDP port to send read commands to the NibeGW. +thing-type.config.nibeheatpump.f470-udp.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f470-udp.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f470-udp.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f470-udp.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f470-udp.writeCommandsPort.label = UDP Port for Write Commands +thing-type.config.nibeheatpump.f470-udp.writeCommandsPort.description = UDP port to send write commands to the NibeGW. +thing-type.config.nibeheatpump.f750-serial.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f750-serial.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-serial.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f750-serial.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-serial.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f750-serial.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 40940, 45171 +thing-type.config.nibeheatpump.f750-serial.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f750-serial.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f750-serial.sendAckToMODBUS40.label = Enable Acknowledges to MODBUS40 Messages +thing-type.config.nibeheatpump.f750-serial.sendAckToMODBUS40.description = Binding emulates MODBUS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f750-serial.sendAckToRMU40.label = Enable Acknowledges to RMU40 Messages +thing-type.config.nibeheatpump.f750-serial.sendAckToRMU40.description = Binding emulates RMU40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f750-serial.sendAckToSMS40.label = Enable Acknowledges to SMS40 Messages +thing-type.config.nibeheatpump.f750-serial.sendAckToSMS40.description = Binding emulates SMS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.f750-serial.serialPort.label = Serial Port +thing-type.config.nibeheatpump.f750-serial.serialPort.description = Serial port to connect to the heat pump. +thing-type.config.nibeheatpump.f750-serial.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f750-serial.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f750-simulator.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f750-simulator.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-simulator.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f750-simulator.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-simulator.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.f750-simulator.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 40940, 45171 +thing-type.config.nibeheatpump.f750-simulator.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f750-simulator.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f750-simulator.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f750-simulator.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f750-udp.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.f750-udp.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-udp.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.f750-udp.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.f750-udp.enableWriteCommandsToRegisters.label = Registers List for Write Commands +thing-type.config.nibeheatpump.f750-udp.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 40940, 45171 +thing-type.config.nibeheatpump.f750-udp.hostName.label = Host Name +thing-type.config.nibeheatpump.f750-udp.hostName.description = Network address of the NibeGW. +thing-type.config.nibeheatpump.f750-udp.port.label = UDP Port +thing-type.config.nibeheatpump.f750-udp.port.description = UDP port to listening data packets from the NibeGW. +thing-type.config.nibeheatpump.f750-udp.readCommandsPort.label = UDP Port for Read Commands +thing-type.config.nibeheatpump.f750-udp.readCommandsPort.description = UDP port to send read commands to the NibeGW. +thing-type.config.nibeheatpump.f750-udp.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.f750-udp.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.f750-udp.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.f750-udp.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.f750-udp.writeCommandsPort.label = UDP Port for Write Commands +thing-type.config.nibeheatpump.f750-udp.writeCommandsPort.description = UDP port to send write commands to the NibeGW. +thing-type.config.nibeheatpump.smo40-serial.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.smo40-serial.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-serial.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.smo40-serial.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-serial.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.smo40-serial.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.smo40-serial.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.smo40-serial.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.smo40-serial.sendAckToMODBUS40.label = Enable Acknowledges to MODBUS40 Messages +thing-type.config.nibeheatpump.smo40-serial.sendAckToMODBUS40.description = Binding emulates MODBUS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.smo40-serial.sendAckToRMU40.label = Enable Acknowledges to RMU40 Messages +thing-type.config.nibeheatpump.smo40-serial.sendAckToRMU40.description = Binding emulates RMU40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.smo40-serial.sendAckToSMS40.label = Enable Acknowledges to SMS40 Messages +thing-type.config.nibeheatpump.smo40-serial.sendAckToSMS40.description = Binding emulates SMS40 device and send protocol acknowledges to heat pump. +thing-type.config.nibeheatpump.smo40-serial.serialPort.label = Serial Port +thing-type.config.nibeheatpump.smo40-serial.serialPort.description = Serial port to connect to the heat pump. +thing-type.config.nibeheatpump.smo40-serial.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.smo40-serial.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.smo40-simulator.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.smo40-simulator.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-simulator.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.smo40-simulator.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-simulator.enableWriteCommandsToRegisters.label = Register List for Write Commands +thing-type.config.nibeheatpump.smo40-simulator.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.smo40-simulator.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.smo40-simulator.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.smo40-simulator.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.smo40-simulator.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.smo40-udp.enableReadCommands.label = Enable Read Commands +thing-type.config.nibeheatpump.smo40-udp.enableReadCommands.description = Enable read commands to read additional variable from heat pump which are not included to data readout messages. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-udp.enableWriteCommands.label = Enable Write Commands +thing-type.config.nibeheatpump.smo40-udp.enableWriteCommands.description = Enable write commands to change heat pump settings. This is experimental feature, use it at your own risk! +thing-type.config.nibeheatpump.smo40-udp.enableWriteCommandsToRegisters.label = Registers List for Write Commands +thing-type.config.nibeheatpump.smo40-udp.enableWriteCommandsToRegisters.description = Comma separated list of registers, which are allowed to write to heat pump. E.g. 44266, 47004 +thing-type.config.nibeheatpump.smo40-udp.hostName.label = Host Name +thing-type.config.nibeheatpump.smo40-udp.hostName.description = Network address of the NibeGW. +thing-type.config.nibeheatpump.smo40-udp.port.label = UDP Port +thing-type.config.nibeheatpump.smo40-udp.port.description = UDP port to listening data packets from the NibeGW. +thing-type.config.nibeheatpump.smo40-udp.readCommandsPort.label = UDP Port for Read Commands +thing-type.config.nibeheatpump.smo40-udp.readCommandsPort.description = UDP port to send read commands to the NibeGW. +thing-type.config.nibeheatpump.smo40-udp.refreshInterval.label = Refresh Interval +thing-type.config.nibeheatpump.smo40-udp.refreshInterval.description = States how often a refresh shall occur in seconds. +thing-type.config.nibeheatpump.smo40-udp.throttleTime.label = Throttle Incoming Data +thing-type.config.nibeheatpump.smo40-udp.throttleTime.description = Throttle incoming data read out messages from heat pump. 0 = throttle is disabled, otherwise throttle time in milliseconds. +thing-type.config.nibeheatpump.smo40-udp.writeCommandsPort.label = UDP Port for Write Commands +thing-type.config.nibeheatpump.smo40-udp.writeCommandsPort.description = UDP port to send write commands to the NibeGW. + +# channel group types + +channel-group-type.nibeheatpump.f1x45-sensor-group-channels.label = Sensors +channel-group-type.nibeheatpump.f1x45-setting-group-channels.label = Settings +channel-group-type.nibeheatpump.f1x55-sensor-group-channels.label = Sensors +channel-group-type.nibeheatpump.f1x55-setting-group-channels.label = Settings +channel-group-type.nibeheatpump.f470-sensor-group-channels.label = Sensors +channel-group-type.nibeheatpump.f470-setting-group-channels.label = Settings +channel-group-type.nibeheatpump.f750-sensor-group-channels.label = Sensors +channel-group-type.nibeheatpump.f750-setting-group-channels.label = Settings +channel-group-type.nibeheatpump.smo40-sensor-group-channels.label = Sensors +channel-group-type.nibeheatpump.smo40-setting-group-channels.label = Settings + +# channel types + +channel-type.nibeheatpump.f1x45-40004.label = BT1 Outdoor Temp +channel-type.nibeheatpump.f1x45-40004.description = Outdoor temperature +channel-type.nibeheatpump.f1x45-40005.label = EP23-BT2 Supply Temp S4 +channel-type.nibeheatpump.f1x45-40005.description = Supply temperature for system 4 +channel-type.nibeheatpump.f1x45-40006.label = EP22-BT2 Supply Temp S3 +channel-type.nibeheatpump.f1x45-40006.description = Supply temperature for system 3 +channel-type.nibeheatpump.f1x45-40007.label = EP21-BT2 Supply Temp S2 +channel-type.nibeheatpump.f1x45-40007.description = Supply temperature for system 2 +channel-type.nibeheatpump.f1x45-40008.label = BT2 Supply Temp S1 +channel-type.nibeheatpump.f1x45-40008.description = Supply temperature for system 1 +channel-type.nibeheatpump.f1x45-40012.label = EB100-EP14-BT3 Return Temp +channel-type.nibeheatpump.f1x45-40012.description = Return temperature +channel-type.nibeheatpump.f1x45-40013.label = BT7 Hot Water Top +channel-type.nibeheatpump.f1x45-40014.label = BT6 Hot Water Load +channel-type.nibeheatpump.f1x45-40015.label = EB100-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-40016.label = EB100-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-40017.label = EB100-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-40019.label = EB100-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-40022.label = EB100-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-40025.label = EB100-BT20 Exhaust Air Temp. 1 +channel-type.nibeheatpump.f1x45-40026.label = EB100-BT21 Vented Air Temp. 1 +channel-type.nibeheatpump.f1x45-40028.label = AZ1-BT26 Temp Collector in FLM 1 +channel-type.nibeheatpump.f1x45-40028.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40029.label = AZ1-BT27 Temp Collector out FLM 1 +channel-type.nibeheatpump.f1x45-40029.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40030.label = EP23-BT50 Room Temp S4 +channel-type.nibeheatpump.f1x45-40031.label = EP22-BT50 Room Temp S3 +channel-type.nibeheatpump.f1x45-40032.label = EP21-BT50 Room Temp S2 +channel-type.nibeheatpump.f1x45-40033.label = BT50 Room Temp S1 +channel-type.nibeheatpump.f1x45-40042.label = CL11-BT51 Pool 1 Temp +channel-type.nibeheatpump.f1x45-40043.label = EP8-BT53 Solar Panel Temp +channel-type.nibeheatpump.f1x45-40044.label = EP8-BT54 Solar Load Temp +channel-type.nibeheatpump.f1x45-40045.label = EQ1-BT64 Cool Supply Temp +channel-type.nibeheatpump.f1x45-40046.label = EQ1-BT65 Cool Return Temp +channel-type.nibeheatpump.f1x45-40054.label = EB100-FD1 Temperature Limiter +channel-type.nibeheatpump.f1x45-40067.label = BT1 Average +channel-type.nibeheatpump.f1x45-40067.description = EB100-BT1 Outdoor temperature average +channel-type.nibeheatpump.f1x45-40070.label = EM1-BT52 Boiler Temperature +channel-type.nibeheatpump.f1x45-40070.description = Temperature of Boiler +channel-type.nibeheatpump.f1x45-40071.label = BT25 External Supply Temp +channel-type.nibeheatpump.f1x45-40072.label = BF1 Flow +channel-type.nibeheatpump.f1x45-40072.description = Current flow +channel-type.nibeheatpump.f1x45-40074.label = EB100-FR1 Anode Status +channel-type.nibeheatpump.f1x45-40079.label = EB100-BE3 Current Phase 3 +channel-type.nibeheatpump.f1x45-40081.label = EB100-BE2 Current Phase 2 +channel-type.nibeheatpump.f1x45-40083.label = EB100-BE1 Current Phase 1 +channel-type.nibeheatpump.f1x45-40106.label = CL12-BT51 Pool 2 Temp +channel-type.nibeheatpump.f1x45-40107.label = EB100-BT20 Exhaust Air Temp. 4 +channel-type.nibeheatpump.f1x45-40108.label = EB100-BT20 Exhaust Air Temp. 3 +channel-type.nibeheatpump.f1x45-40109.label = EB100-BT20 Exhaust Air Temp. 2 +channel-type.nibeheatpump.f1x45-40110.label = EB100-BT21 Vented Air Temp. 4 +channel-type.nibeheatpump.f1x45-40111.label = EB100-BT21 Vented Air Temp. 3 +channel-type.nibeheatpump.f1x45-40112.label = EB100-BT21 Vented Air Temp. 2 +channel-type.nibeheatpump.f1x45-40113.label = AZ4-BT26 Temp Collector in FLM 4 +channel-type.nibeheatpump.f1x45-40113.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40114.label = AZ3-BT26 Temp Collector in FLM 3 +channel-type.nibeheatpump.f1x45-40114.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40115.label = AZ2-BT26 Temp Collector in FLM 2 +channel-type.nibeheatpump.f1x45-40115.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40116.label = AZ4-BT27 Temp Collector out FLM 4 +channel-type.nibeheatpump.f1x45-40116.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40117.label = AZ3-BT27 Temp Collector out FLM 3 +channel-type.nibeheatpump.f1x45-40117.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40118.label = AZ2-BT27 Temp Collector out FLM 2 +channel-type.nibeheatpump.f1x45-40118.description = Connected to the FLM module +channel-type.nibeheatpump.f1x45-40127.label = EP23-BT3 Return Temp S4 +channel-type.nibeheatpump.f1x45-40127.description = Return temperature for system 4 +channel-type.nibeheatpump.f1x45-40128.label = EP22-BT3 Return Temp S3 +channel-type.nibeheatpump.f1x45-40128.description = Return temperature for system 3 +channel-type.nibeheatpump.f1x45-40129.label = EP21-BT3 Return Temp S2 +channel-type.nibeheatpump.f1x45-40129.description = Return temperature for system 2 +channel-type.nibeheatpump.f1x45-40155.label = EQ1-BT57 Collector Temp. +channel-type.nibeheatpump.f1x45-40155.description = External collector temperature for ACS +channel-type.nibeheatpump.f1x45-40156.label = EQ1-BT75 Heatdump Temp. +channel-type.nibeheatpump.f1x45-40156.description = Heating medium dump temperature for ACS +channel-type.nibeheatpump.f1x45-43001.label = Software Version +channel-type.nibeheatpump.f1x45-43005.label = Degree Minutes +channel-type.nibeheatpump.f1x45-43006.label = Calculated Supply Temperature S4 +channel-type.nibeheatpump.f1x45-43007.label = Calculated Supply Temperature S3 +channel-type.nibeheatpump.f1x45-43008.label = Calculated Supply Temperature S2 +channel-type.nibeheatpump.f1x45-43009.label = Calculated Supply Temperature S1 +channel-type.nibeheatpump.f1x45-43013.label = Freeze Protection Status +channel-type.nibeheatpump.f1x45-43013.description = 1 = Freeze protection active +channel-type.nibeheatpump.f1x45-43013.state.option.1 = Freeze protection active +channel-type.nibeheatpump.f1x45-43024.label = Status Cooling +channel-type.nibeheatpump.f1x45-43024.description = 0=Off 1=On +channel-type.nibeheatpump.f1x45-43024.state.option.0 = Off +channel-type.nibeheatpump.f1x45-43024.state.option.1 = On +channel-type.nibeheatpump.f1x45-43081.label = Tot. Op.time Add. +channel-type.nibeheatpump.f1x45-43081.description = Total electric additive operation time +channel-type.nibeheatpump.f1x45-43084.label = Int. El.add. Power +channel-type.nibeheatpump.f1x45-43084.description = Current power from the internal electrical addition +channel-type.nibeheatpump.f1x45-43086.label = Prio +channel-type.nibeheatpump.f1x45-43086.description = Indicates what heating action (HW/heat/pool) currently prioritised 10=Off 20=Hot Water 30=Heat 40=Pool 41=Pool 2 50=Transfer 60=Cooling +channel-type.nibeheatpump.f1x45-43086.state.option.10 = Off +channel-type.nibeheatpump.f1x45-43086.state.option.20 = Hot Water +channel-type.nibeheatpump.f1x45-43086.state.option.30 = Heat +channel-type.nibeheatpump.f1x45-43086.state.option.40 = Pool +channel-type.nibeheatpump.f1x45-43086.state.option.41 = Pool 2 +channel-type.nibeheatpump.f1x45-43086.state.option.50 = Transfer +channel-type.nibeheatpump.f1x45-43086.state.option.60 = Cooling +channel-type.nibeheatpump.f1x45-43091.label = Int. El.add. State +channel-type.nibeheatpump.f1x45-43091.description = State of the internal electrical addition +channel-type.nibeheatpump.f1x45-43097.label = Status of the Shunt Controlled Additional Heat Accessory +channel-type.nibeheatpump.f1x45-43097.description = 10 = Off, 20 = Running, 30 = Passive +channel-type.nibeheatpump.f1x45-43097.state.option.10 = Off +channel-type.nibeheatpump.f1x45-43097.state.option.20 = Running +channel-type.nibeheatpump.f1x45-43097.state.option.30 = Passive +channel-type.nibeheatpump.f1x45-43103.label = HPAC State +channel-type.nibeheatpump.f1x45-43103.description = State of the HPAC cooling accessory. +channel-type.nibeheatpump.f1x45-43108.label = Fan Speed Current +channel-type.nibeheatpump.f1x45-43108.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f1x45-43152.label = Internal Cooling Blocked +channel-type.nibeheatpump.f1x45-43158.label = External Adjustment Activated Via Input S4 +channel-type.nibeheatpump.f1x45-43159.label = External Adjustment Activated Via Input S3 +channel-type.nibeheatpump.f1x45-43160.label = External Adjustment Activated Via Input S2 +channel-type.nibeheatpump.f1x45-43161.label = External Adjustment Activated Via Input S1 +channel-type.nibeheatpump.f1x45-43163.label = Blocking Status of the Shunt Controlled Add Heat Acc +channel-type.nibeheatpump.f1x45-43163.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.f1x45-43163.state.option.0 = Unblocked +channel-type.nibeheatpump.f1x45-43163.state.option.1 = Blocked +channel-type.nibeheatpump.f1x45-43164.label = Cooling Blocked +channel-type.nibeheatpump.f1x45-43164.description = Whether cooling is blocked +channel-type.nibeheatpump.f1x45-43171.label = Blocking Status of the Step Controlled Add Heat Acc +channel-type.nibeheatpump.f1x45-43171.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.f1x45-43171.state.option.0 = Unblocked +channel-type.nibeheatpump.f1x45-43171.state.option.1 = Blocked +channel-type.nibeheatpump.f1x45-43189.label = Ext. Heat Medium Pump +channel-type.nibeheatpump.f1x45-43189.description = 0=Off,1=On +channel-type.nibeheatpump.f1x45-43189.state.option.0 = Off +channel-type.nibeheatpump.f1x45-43189.state.option.1 = On +channel-type.nibeheatpump.f1x45-43230.label = Accumulated Energy +channel-type.nibeheatpump.f1x45-43239.label = Tot. HW Op.time Add. +channel-type.nibeheatpump.f1x45-43239.description = Total electric additive operation time in hot water mode +channel-type.nibeheatpump.f1x45-43395.label = HPAC Relays +channel-type.nibeheatpump.f1x45-43395.description = Indicates the active relays on the HPAC accessory. The information is binary encoded +channel-type.nibeheatpump.f1x45-43416.label = Compressor Starts EB100-EP14 +channel-type.nibeheatpump.f1x45-43416.description = Number of compressorer starts +channel-type.nibeheatpump.f1x45-43420.label = Tot. Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f1x45-43420.description = Total compressorer operation time +channel-type.nibeheatpump.f1x45-43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f1x45-43424.description = Total compressorer operation time in hot water mode +channel-type.nibeheatpump.f1x45-43427.label = Compressor State EP14 +channel-type.nibeheatpump.f1x45-43427.description = 20 = Stopped, 40 = Starting, 60 = Running, 100 = Stopping +channel-type.nibeheatpump.f1x45-43427.state.option.20 = Stopped +channel-type.nibeheatpump.f1x45-43427.state.option.40 = Starting +channel-type.nibeheatpump.f1x45-43427.state.option.60 = Running +channel-type.nibeheatpump.f1x45-43427.state.option.100 = Stopping +channel-type.nibeheatpump.f1x45-43431.label = Supply Pump State EP14 +channel-type.nibeheatpump.f1x45-43431.description = State of the supply pump +channel-type.nibeheatpump.f1x45-43433.label = Brine Pump State EP14 +channel-type.nibeheatpump.f1x45-43435.label = Compressor Status EP14 +channel-type.nibeheatpump.f1x45-43435.description = Indicates if the compressor is supplied with power 0=Off 1=On +channel-type.nibeheatpump.f1x45-43435.state.option.0 = Off +channel-type.nibeheatpump.f1x45-43435.state.option.1 = On +channel-type.nibeheatpump.f1x45-43437.label = HM-pump Status EP14 +channel-type.nibeheatpump.f1x45-43437.description = Status of the circ. pump +channel-type.nibeheatpump.f1x45-43439.label = Brinepump Status EP14 +channel-type.nibeheatpump.f1x45-43439.description = Status of the Brine pump +channel-type.nibeheatpump.f1x45-43473.label = Heat Compressors +channel-type.nibeheatpump.f1x45-43473.description = Number of compressors docked to heating +channel-type.nibeheatpump.f1x45-43474.label = Hot Water Compressors +channel-type.nibeheatpump.f1x45-43474.description = Number of compressors docked to hot water +channel-type.nibeheatpump.f1x45-43475.label = Pool 1 Compressors +channel-type.nibeheatpump.f1x45-43475.description = Number of compressors docked to pool 1 +channel-type.nibeheatpump.f1x45-43484.label = FLM Cooling Activated +channel-type.nibeheatpump.f1x45-43485.label = FLM Cooling Activated +channel-type.nibeheatpump.f1x45-43486.label = FLM Cooling Activated +channel-type.nibeheatpump.f1x45-43487.label = FLM Cooling Activated +channel-type.nibeheatpump.f1x45-43514.label = PCA-Base Relays EP14 +channel-type.nibeheatpump.f1x45-43514.description = Indicates the active relays on the PCA-Base card. The information is binary encoded +channel-type.nibeheatpump.f1x45-43516.label = PCA-Power Relays EP14 +channel-type.nibeheatpump.f1x45-43516.description = Indicates the active relays on the PCA-Power card. The information is binary encoded +channel-type.nibeheatpump.f1x45-43560.label = Pool 2 Blocked +channel-type.nibeheatpump.f1x45-43561.label = Pool 1 Blocked +channel-type.nibeheatpump.f1x45-43563.label = Pool 2 Valve +channel-type.nibeheatpump.f1x45-43564.label = Pool 1 Valve +channel-type.nibeheatpump.f1x45-43577.label = Pool 2 Compressors +channel-type.nibeheatpump.f1x45-43577.description = Number of compressors docked to pool 2 +channel-type.nibeheatpump.f1x45-43580.label = EB108 Version +channel-type.nibeheatpump.f1x45-43598.label = EB108 Slave Type +channel-type.nibeheatpump.f1x45-43599.label = EB108 Compressor Size +channel-type.nibeheatpump.f1x45-43600.label = EB108-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43600.description = Return temperature +channel-type.nibeheatpump.f1x45-43601.label = EB108-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43602.label = EB108-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43603.label = EB108-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43604.label = EB108-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43605.label = EB108-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43606.label = EB108-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43607.label = EB108-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43608.label = EB108-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43609.label = EB108-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43610.label = EB108-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43611.label = EB108-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43612.label = EB108-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43613.label = EB108-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43614.label = EB108-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43616.label = EB108-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43618.label = EB108-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43620.label = EB108-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43620.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43621.label = EB108-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43621.description = Return temperature +channel-type.nibeheatpump.f1x45-43622.label = EB108-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43623.label = EB108-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43624.label = EB108-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43625.label = EB108-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43626.label = EB108-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43627.label = EB108-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43628.label = EB108-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43629.label = EB108-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43630.label = EB108-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43631.label = EB108-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43632.label = EB108-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43633.label = EB108-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43634.label = EB108-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43635.label = EB108-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43637.label = EB108-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43639.label = EB108-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43641.label = EB108-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43641.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43642.label = EB107 Version +channel-type.nibeheatpump.f1x45-43660.label = EB107 Slave Type +channel-type.nibeheatpump.f1x45-43661.label = EB107 Compressor Size +channel-type.nibeheatpump.f1x45-43662.label = EB107-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43662.description = Return temperature +channel-type.nibeheatpump.f1x45-43663.label = EB107-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43664.label = EB107-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43665.label = EB107-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43666.label = EB107-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43667.label = EB107-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43668.label = EB107-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43669.label = EB107-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43670.label = EB107-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43671.label = EB107-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43672.label = EB107-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43673.label = EB107-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43674.label = EB107-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43675.label = EB107-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43676.label = EB107-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43678.label = EB107-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43680.label = EB107-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43682.label = EB107-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43682.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43683.label = EB107-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43683.description = Return temperature +channel-type.nibeheatpump.f1x45-43684.label = EB107-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43685.label = EB107-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43686.label = EB107-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43687.label = EB107-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43688.label = EB107-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43689.label = EB107-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43690.label = EB107-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43691.label = EB107-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43692.label = EB107-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43693.label = EB107-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43694.label = EB107-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43695.label = EB107-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43696.label = EB107-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43697.label = EB107-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43699.label = EB107-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43701.label = EB107-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43703.label = EB107-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43703.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43704.label = EB106 Version +channel-type.nibeheatpump.f1x45-43722.label = EB106 Slave Type +channel-type.nibeheatpump.f1x45-43723.label = EB106 Compressor Size +channel-type.nibeheatpump.f1x45-43724.label = EB106-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43724.description = Return temperature +channel-type.nibeheatpump.f1x45-43725.label = EB106-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43726.label = EB106-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43727.label = EB106-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43728.label = EB106-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43729.label = EB106-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43730.label = EB106-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43731.label = EB106-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43732.label = EB106-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43733.label = EB106-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43734.label = EB106-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43735.label = EB106-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43736.label = EB106-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43737.label = EB106-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43738.label = EB106-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43740.label = EB106-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43742.label = EB106-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43744.label = EB106-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43744.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43745.label = EB106-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43745.description = Return temperature +channel-type.nibeheatpump.f1x45-43746.label = EB106-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43747.label = EB106-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43748.label = EB106-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43749.label = EB106-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43750.label = EB106-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43751.label = EB106-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43752.label = EB106-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43753.label = EB106-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43754.label = EB106-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43755.label = EB106-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43756.label = EB106-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43757.label = EB106-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43758.label = EB106-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43759.label = EB106-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43761.label = EB106-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43763.label = EB106-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43765.label = EB106-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43765.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43766.label = EB105 Version +channel-type.nibeheatpump.f1x45-43784.label = EB105 Slave Type +channel-type.nibeheatpump.f1x45-43785.label = EB105 Compressor Size +channel-type.nibeheatpump.f1x45-43786.label = EB105-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43786.description = Return temperature +channel-type.nibeheatpump.f1x45-43787.label = EB105-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43788.label = EB105-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43789.label = EB105-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43790.label = EB105-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43791.label = EB105-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43792.label = EB105-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43793.label = EB105-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43794.label = EB105-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43795.label = EB105-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43796.label = EB105-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43797.label = EB105-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43798.label = EB105-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43799.label = EB105-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43800.label = EB105-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43802.label = EB105-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43804.label = EB105-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43806.label = EB105-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43806.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43807.label = EB105-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43807.description = Return temperature +channel-type.nibeheatpump.f1x45-43808.label = EB105-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43809.label = EB105-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43810.label = EB105-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43811.label = EB105-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43812.label = EB105-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43813.label = EB105-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43814.label = EB105-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43815.label = EB105-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43816.label = EB105-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43817.label = EB105-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43818.label = EB105-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43819.label = EB105-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43820.label = EB105-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43821.label = EB105-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43823.label = EB105-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43825.label = EB105-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43827.label = EB105-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43827.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43828.label = EB104 Version +channel-type.nibeheatpump.f1x45-43846.label = EB104 Slave Type +channel-type.nibeheatpump.f1x45-43847.label = EB104 Compressor Size +channel-type.nibeheatpump.f1x45-43848.label = EB104-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43848.description = Return temperature +channel-type.nibeheatpump.f1x45-43849.label = EB104-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43850.label = EB104-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43851.label = EB104-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43852.label = EB104-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43853.label = EB104-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43854.label = EB104-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43855.label = EB104-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43856.label = EB104-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43857.label = EB104-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43858.label = EB104-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43859.label = EB104-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43860.label = EB104-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43861.label = EB104-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43862.label = EB104-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43864.label = EB104-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43866.label = EB104-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43868.label = EB104-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43868.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43869.label = EB104-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43869.description = Return temperature +channel-type.nibeheatpump.f1x45-43870.label = EB104-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43871.label = EB104-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43872.label = EB104-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43873.label = EB104-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43874.label = EB104-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43875.label = EB104-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43876.label = EB104-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43877.label = EB104-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43878.label = EB104-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43879.label = EB104-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43880.label = EB104-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43881.label = EB104-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43882.label = EB104-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43883.label = EB104-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43885.label = EB104-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43887.label = EB104-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43889.label = EB104-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43889.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43890.label = EB103 Version +channel-type.nibeheatpump.f1x45-43908.label = EB103 Slave Type +channel-type.nibeheatpump.f1x45-43909.label = EB103 Compressor Size +channel-type.nibeheatpump.f1x45-43910.label = EB103-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43910.description = Return temperature +channel-type.nibeheatpump.f1x45-43911.label = EB103-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43912.label = EB103-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43913.label = EB103-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43914.label = EB103-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43915.label = EB103-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43916.label = EB103-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43917.label = EB103-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43918.label = EB103-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43919.label = EB103-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43920.label = EB103-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43921.label = EB103-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43922.label = EB103-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43923.label = EB103-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43924.label = EB103-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43926.label = EB103-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43928.label = EB103-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43930.label = EB103-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43930.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43931.label = EB103-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43931.description = Return temperature +channel-type.nibeheatpump.f1x45-43932.label = EB103-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43933.label = EB103-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43934.label = EB103-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43935.label = EB103-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43936.label = EB103-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43937.label = EB103-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-43938.label = EB103-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43939.label = EB103-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43940.label = EB103-EP14 Compressor State +channel-type.nibeheatpump.f1x45-43941.label = EB103-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43942.label = EB103-EP14 Relay Status +channel-type.nibeheatpump.f1x45-43943.label = EB103-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43944.label = EB103-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-43945.label = EB103-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-43947.label = EB103-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43949.label = EB103-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43951.label = EB103-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-43951.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43952.label = EB102 Version +channel-type.nibeheatpump.f1x45-43970.label = EB102 Slave Type +channel-type.nibeheatpump.f1x45-43971.label = EB102 Compressor Size +channel-type.nibeheatpump.f1x45-43972.label = EB102-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43972.description = Return temperature +channel-type.nibeheatpump.f1x45-43973.label = EB102-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43974.label = EB102-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43975.label = EB102-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43976.label = EB102-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43977.label = EB102-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43978.label = EB102-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-43979.label = EB102-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-43980.label = EB102-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-43981.label = EB102-EP15 Compressor State +channel-type.nibeheatpump.f1x45-43982.label = EB102-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-43983.label = EB102-EP15 Relay Status +channel-type.nibeheatpump.f1x45-43984.label = EB102-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-43985.label = EB102-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-43986.label = EB102-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-43988.label = EB102-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-43990.label = EB102-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-43992.label = EB102-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-43992.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-43993.label = EB102-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-43993.description = Return temperature +channel-type.nibeheatpump.f1x45-43994.label = EB102-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-43995.label = EB102-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-43996.label = EB102-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-43997.label = EB102-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-43998.label = EB102-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-43999.label = EB102-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-44000.label = EB102-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-44001.label = EB102-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-44002.label = EB102-EP14 Compressor State +channel-type.nibeheatpump.f1x45-44003.label = EB102-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-44004.label = EB102-EP14 Relay Status +channel-type.nibeheatpump.f1x45-44005.label = EB102-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-44006.label = EB102-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-44007.label = EB102-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-44009.label = EB102-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-44011.label = EB102-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-44013.label = EB102-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-44013.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-44014.label = EB101 Version +channel-type.nibeheatpump.f1x45-44032.label = EB101 Slave Type +channel-type.nibeheatpump.f1x45-44033.label = EB101 Compressor Size +channel-type.nibeheatpump.f1x45-44034.label = EB101-EP15-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-44034.description = Return temperature +channel-type.nibeheatpump.f1x45-44035.label = EB101-EP15-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-44036.label = EB101-EP15-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-44037.label = EB101-EP15-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-44038.label = EB101-EP15-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-44039.label = EB101-EP15-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-44040.label = EB101-EP15-BT17 Suction +channel-type.nibeheatpump.f1x45-44041.label = EB101-EP15-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-44042.label = EB101-EP15-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-44043.label = EB101-EP15 Compressor State +channel-type.nibeheatpump.f1x45-44044.label = EB101-EP15 Compr. Time to Start +channel-type.nibeheatpump.f1x45-44045.label = EB101-EP15 Relay Status +channel-type.nibeheatpump.f1x45-44046.label = EB101-EP15 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-44047.label = EB101-EP15 Brine Pump Status +channel-type.nibeheatpump.f1x45-44048.label = EB101-EP15 Compressor Starts +channel-type.nibeheatpump.f1x45-44050.label = EB101-EP15 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-44052.label = EB101-EP15 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-44054.label = EB101-EP15 Alarm Number +channel-type.nibeheatpump.f1x45-44054.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-44055.label = EB101-EP14-BT3 Return Temp. +channel-type.nibeheatpump.f1x45-44055.description = Return temperature +channel-type.nibeheatpump.f1x45-44056.label = EB101-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x45-44057.label = EB101-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x45-44058.label = EB101-EP14-BT12 Cond. Out +channel-type.nibeheatpump.f1x45-44059.label = EB101-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x45-44060.label = EB101-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x45-44061.label = EB101-EP14-BT17 Suction +channel-type.nibeheatpump.f1x45-44062.label = EB101-EP14-BT29 Compr. Oil. Temp. +channel-type.nibeheatpump.f1x45-44063.label = EB101-EP14-BP8 Pressure Transmitter +channel-type.nibeheatpump.f1x45-44064.label = EB101-EP14 Compressor State +channel-type.nibeheatpump.f1x45-44065.label = EB101-EP14 Compr. Time to Start +channel-type.nibeheatpump.f1x45-44066.label = EB101-EP14 Relay Status +channel-type.nibeheatpump.f1x45-44067.label = EB101-EP14 Heat Med. Pump Status +channel-type.nibeheatpump.f1x45-44068.label = EB101-EP14 Brine Pump Status +channel-type.nibeheatpump.f1x45-44069.label = EB101-EP14 Compressor Starts +channel-type.nibeheatpump.f1x45-44071.label = EB101-EP14 Tot. Op.time Compr +channel-type.nibeheatpump.f1x45-44073.label = EB101-EP14 Tot. HW Op.time Compr +channel-type.nibeheatpump.f1x45-44075.label = EB101-EP14 Alarm Number +channel-type.nibeheatpump.f1x45-44075.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-44138.label = EB108-EP15 Prio +channel-type.nibeheatpump.f1x45-44138.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44138.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44138.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44138.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44138.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44138.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44139.label = EB108-EP14 Prio +channel-type.nibeheatpump.f1x45-44139.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44139.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44139.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44139.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44139.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44139.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44151.label = EB107-EP15 Prio +channel-type.nibeheatpump.f1x45-44151.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44151.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44151.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44151.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44151.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44151.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44152.label = EB107-EP14 Prio +channel-type.nibeheatpump.f1x45-44152.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44152.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44152.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44152.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44152.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44152.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44164.label = EB106-EP15 Prio +channel-type.nibeheatpump.f1x45-44164.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44164.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44164.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44164.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44164.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44164.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44165.label = EB106-EP14 Prio +channel-type.nibeheatpump.f1x45-44165.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44165.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44165.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44165.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44165.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44165.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44177.label = EB105-EP15 Prio +channel-type.nibeheatpump.f1x45-44177.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44177.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44177.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44177.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44177.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44177.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44178.label = EB105-EP14 Prio +channel-type.nibeheatpump.f1x45-44178.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44178.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44178.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44178.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44178.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44178.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44190.label = EB104-EP15 Prio +channel-type.nibeheatpump.f1x45-44190.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44190.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44190.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44190.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44190.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44190.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44191.label = EB104-EP14 Prio +channel-type.nibeheatpump.f1x45-44191.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44191.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44191.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44191.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44191.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44191.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44203.label = EB103-EP15 Prio +channel-type.nibeheatpump.f1x45-44203.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44203.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44203.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44203.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44203.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44203.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44204.label = EB103-EP14 Prio +channel-type.nibeheatpump.f1x45-44204.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44204.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44204.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44204.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44204.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44204.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44216.label = EB102-EP15 Prio +channel-type.nibeheatpump.f1x45-44216.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44216.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44216.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44216.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44216.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44216.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44217.label = EB102-EP14 Prio +channel-type.nibeheatpump.f1x45-44217.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44217.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44217.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44217.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44217.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44217.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44229.label = EB101-EP15 Prio +channel-type.nibeheatpump.f1x45-44229.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44229.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44229.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44229.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44229.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44229.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44230.label = EB101-EP14 Prio +channel-type.nibeheatpump.f1x45-44230.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44230.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44230.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44230.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44230.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44230.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44242.label = EB100-EP15 Prio +channel-type.nibeheatpump.f1x45-44242.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44242.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44242.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44242.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44242.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44242.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44243.label = EB100-EP14 Prio +channel-type.nibeheatpump.f1x45-44243.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2 +channel-type.nibeheatpump.f1x45-44243.state.option.0 = Off +channel-type.nibeheatpump.f1x45-44243.state.option.1 = Heat +channel-type.nibeheatpump.f1x45-44243.state.option.2 = Hot water +channel-type.nibeheatpump.f1x45-44243.state.option.3 = Pool 1 +channel-type.nibeheatpump.f1x45-44243.state.option.4 = Pool2 +channel-type.nibeheatpump.f1x45-44266.label = Cool Degree Minutes +channel-type.nibeheatpump.f1x45-44267.label = Calc. Cooling Supply Temperature S4 +channel-type.nibeheatpump.f1x45-44268.label = Calc. Cooling Supply Temperature S3 +channel-type.nibeheatpump.f1x45-44269.label = Calc. Cooling Supply Temperature S2 +channel-type.nibeheatpump.f1x45-44270.label = Calc. Cooling Supply Temperature S1 +channel-type.nibeheatpump.f1x45-44276.label = State ACS +channel-type.nibeheatpump.f1x45-44276.description = The state of the ACS accessory +channel-type.nibeheatpump.f1x45-44277.label = State ACS Heatdump +channel-type.nibeheatpump.f1x45-44277.description = The state of the heatdump in the ACS accessory +channel-type.nibeheatpump.f1x45-44278.label = State ACS Cooldump +channel-type.nibeheatpump.f1x45-44278.description = The state of the cooldump in the ACS accessory +channel-type.nibeheatpump.f1x45-44282.label = Used Cprs. HW +channel-type.nibeheatpump.f1x45-44282.description = The number of compressors that's currently producing hot water +channel-type.nibeheatpump.f1x45-44283.label = Used Cprs. Heat +channel-type.nibeheatpump.f1x45-44283.description = The number of compressors that's currently producing heating +channel-type.nibeheatpump.f1x45-44284.label = Used Cprs. Pool 1 +channel-type.nibeheatpump.f1x45-44284.description = The number of compressors that's currently producing poolheating for pool 1 +channel-type.nibeheatpump.f1x45-44285.label = Used Cprs. Pool 2 +channel-type.nibeheatpump.f1x45-44285.description = The number of compressors that's currently producing poolheating for pool 2 +channel-type.nibeheatpump.f1x45-44298.label = Accumulated Energy HW Cpr and Add +channel-type.nibeheatpump.f1x45-44300.label = Accumulated Energy Heat Cpr and Add +channel-type.nibeheatpump.f1x45-44302.label = Accumulated Energy Cooling Cpr +channel-type.nibeheatpump.f1x45-44304.label = Accumulated Energy Pool Cpr +channel-type.nibeheatpump.f1x45-44306.label = Accumulated Energy HW Cpr +channel-type.nibeheatpump.f1x45-44308.label = Accumulated Energy Heat Cpr +channel-type.nibeheatpump.f1x45-44320.label = Used Cprs. Cool +channel-type.nibeheatpump.f1x45-44320.description = The number of compressors that's currently producing active cooling +channel-type.nibeheatpump.f1x45-44331.label = Software Release +channel-type.nibeheatpump.f1x45-44380.label = External Compressors +channel-type.nibeheatpump.f1x45-44380.description = Number of compressors with external control +channel-type.nibeheatpump.f1x45-44410.label = EB108 Own Hot Water +channel-type.nibeheatpump.f1x45-44411.label = EB108-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44412.label = EB108-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44413.label = EB108-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44416.label = EB107 Own Hot Water +channel-type.nibeheatpump.f1x45-44417.label = EB107-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44418.label = EB107-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44419.label = EB107-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44422.label = EB106 Own Hot Water +channel-type.nibeheatpump.f1x45-44423.label = EB106-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44424.label = EB106-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44425.label = EB106-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44428.label = EB105 Own Hot Water +channel-type.nibeheatpump.f1x45-44429.label = EB105-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44430.label = EB105-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44431.label = EB105-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44434.label = EB104 Own Hot Water +channel-type.nibeheatpump.f1x45-44435.label = EB104-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44436.label = EB104-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44437.label = EB104-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44440.label = EB103 Own Hot Water +channel-type.nibeheatpump.f1x45-44441.label = EB103-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44442.label = EB103-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44443.label = EB103-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44446.label = EB102 Own Hot Water +channel-type.nibeheatpump.f1x45-44447.label = EB102-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44448.label = EB102-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44449.label = EB102-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44452.label = EB101 Own Hot Water +channel-type.nibeheatpump.f1x45-44453.label = EB101-BT6 Hot Water Load Temp. +channel-type.nibeheatpump.f1x45-44454.label = EB101-BT7 Hot Water Top Temp. +channel-type.nibeheatpump.f1x45-44455.label = EB101-BT2 Supply Temp. +channel-type.nibeheatpump.f1x45-44487.label = Cool Compressors +channel-type.nibeheatpump.f1x45-44487.description = Number of compressors docked to cooling +channel-type.nibeheatpump.f1x45-44744.label = Extra Heating System Pump S4 +channel-type.nibeheatpump.f1x45-44745.label = Extra Heating System Pump S3 +channel-type.nibeheatpump.f1x45-44746.label = Extra Heating System Pump S2 +channel-type.nibeheatpump.f1x45-44748.label = Pool 2 Pump +channel-type.nibeheatpump.f1x45-44749.label = Pool 1 Pump +channel-type.nibeheatpump.f1x45-44753.label = Passiv Cool Shunt +channel-type.nibeheatpump.f1x45-44754.label = Passiv Cool Pool +channel-type.nibeheatpump.f1x45-44756.label = State Ground Water Pump +channel-type.nibeheatpump.f1x45-44874.label = State SG Ready +channel-type.nibeheatpump.f1x45-44878.label = SG Ready Input A +channel-type.nibeheatpump.f1x45-44879.label = SG Ready Input B +channel-type.nibeheatpump.f1x45-44910.label = Brine Pump DT Act. +channel-type.nibeheatpump.f1x45-44910.description = Current value between set and act value on brine pumps +channel-type.nibeheatpump.f1x45-44911.label = Brine Pump DT Act. +channel-type.nibeheatpump.f1x45-44911.description = set point delta T for the brine pumps +channel-type.nibeheatpump.f1x45-44912.label = Brine Pump Auto Controlled +channel-type.nibeheatpump.f1x45-44912.description = Brine pump auto controlled +channel-type.nibeheatpump.f1x45-45001.label = Alarm Number +channel-type.nibeheatpump.f1x45-45001.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.f1x45-47004.label = Heat Curve S4 +channel-type.nibeheatpump.f1x45-47004.description = Heat curve to use see manual for the different curves. +channel-type.nibeheatpump.f1x45-47005.label = Heat Curve S3 +channel-type.nibeheatpump.f1x45-47005.description = Heat curve to use see manual for the different curves. +channel-type.nibeheatpump.f1x45-47006.label = Heat Curve S2 +channel-type.nibeheatpump.f1x45-47006.description = Heat curve to use see manual for the different curves. +channel-type.nibeheatpump.f1x45-47007.label = Heat Curve S1 +channel-type.nibeheatpump.f1x45-47007.description = Heat curve to use see manual for the different curves. +channel-type.nibeheatpump.f1x45-47008.label = Offset S4 +channel-type.nibeheatpump.f1x45-47008.description = Offset of the heat curve +channel-type.nibeheatpump.f1x45-47009.label = Offset S3 +channel-type.nibeheatpump.f1x45-47009.description = Offset of the heat curve +channel-type.nibeheatpump.f1x45-47010.label = Offset S2 +channel-type.nibeheatpump.f1x45-47010.description = Offset of the heat curve +channel-type.nibeheatpump.f1x45-47011.label = Offset S1 +channel-type.nibeheatpump.f1x45-47011.description = Offset of the heat curve +channel-type.nibeheatpump.f1x45-47012.label = Min Supply System 4 +channel-type.nibeheatpump.f1x45-47013.label = Min Supply System 3 +channel-type.nibeheatpump.f1x45-47014.label = Min Supply System 2 +channel-type.nibeheatpump.f1x45-47015.label = Min Supply System 1 +channel-type.nibeheatpump.f1x45-47016.label = Max Supply System 4 +channel-type.nibeheatpump.f1x45-47017.label = Max Supply System 3 +channel-type.nibeheatpump.f1x45-47018.label = Max Supply System 2 +channel-type.nibeheatpump.f1x45-47019.label = Max Supply System 1 +channel-type.nibeheatpump.f1x45-47020.label = Own Curve P7 +channel-type.nibeheatpump.f1x45-47020.description = User defined curve point +channel-type.nibeheatpump.f1x45-47021.label = Own Curve P6 +channel-type.nibeheatpump.f1x45-47021.description = User defined curve point +channel-type.nibeheatpump.f1x45-47022.label = Own Curve P5 +channel-type.nibeheatpump.f1x45-47022.description = User defined curve point +channel-type.nibeheatpump.f1x45-47023.label = Own Curve P4 +channel-type.nibeheatpump.f1x45-47023.description = User defined curve point +channel-type.nibeheatpump.f1x45-47024.label = Own Curve P3 +channel-type.nibeheatpump.f1x45-47024.description = User defined curve point +channel-type.nibeheatpump.f1x45-47025.label = Own Curve P2 +channel-type.nibeheatpump.f1x45-47025.description = User defined curve point +channel-type.nibeheatpump.f1x45-47026.label = Own Curve P1 +channel-type.nibeheatpump.f1x45-47026.description = User defined curve point +channel-type.nibeheatpump.f1x45-47027.label = Point Offset Outdoor Temp. +channel-type.nibeheatpump.f1x45-47027.description = Outdoor temperature point where the heat curve is offset +channel-type.nibeheatpump.f1x45-47028.label = Point Offset +channel-type.nibeheatpump.f1x45-47028.description = Amount of offset at the point offset temperature +channel-type.nibeheatpump.f1x45-47029.label = External Adjustment S4 +channel-type.nibeheatpump.f1x45-47029.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47030.label = External Adjustment S3 +channel-type.nibeheatpump.f1x45-47030.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47031.label = External Adjustment S2 +channel-type.nibeheatpump.f1x45-47031.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47032.label = External Adjustment S1 +channel-type.nibeheatpump.f1x45-47032.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47033.label = External Adjustment with Room Sensor S4 +channel-type.nibeheatpump.f1x45-47033.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47034.label = External Adjustment with Room Sensor S3 +channel-type.nibeheatpump.f1x45-47034.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47035.label = External Adjustment with Room Sensor S2 +channel-type.nibeheatpump.f1x45-47035.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47036.label = External Adjustment with Room Sensor S1 +channel-type.nibeheatpump.f1x45-47036.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x45-47041.label = Hot Water Mode +channel-type.nibeheatpump.f1x45-47041.description = 0=Economy 1=Normal 2=Luxury +channel-type.nibeheatpump.f1x45-47041.state.option.0 = Economy +channel-type.nibeheatpump.f1x45-47041.state.option.1 = Normal +channel-type.nibeheatpump.f1x45-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f1x45-47043.label = Start Temperature HW Luxury +channel-type.nibeheatpump.f1x45-47043.description = Start temperature for heating water +channel-type.nibeheatpump.f1x45-47044.label = Start Temperature HW Normal +channel-type.nibeheatpump.f1x45-47044.description = Start temperature for heating water +channel-type.nibeheatpump.f1x45-47045.label = Start Temperature HW Economy +channel-type.nibeheatpump.f1x45-47045.description = Start temperature for heating water +channel-type.nibeheatpump.f1x45-47046.label = Stop Temperature Periodic HW +channel-type.nibeheatpump.f1x45-47046.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x45-47047.label = Stop Temperature HW Luxury +channel-type.nibeheatpump.f1x45-47047.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x45-47048.label = Stop Temperature HW Normal +channel-type.nibeheatpump.f1x45-47048.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x45-47049.label = Stop Temperature HW Economy +channel-type.nibeheatpump.f1x45-47049.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x45-47050.label = Periodic HW +channel-type.nibeheatpump.f1x45-47050.description = Activates the periodic hot water generation +channel-type.nibeheatpump.f1x45-47051.label = Periodic HW Interval +channel-type.nibeheatpump.f1x45-47051.description = Interval between Periodic hot water sessions +channel-type.nibeheatpump.f1x45-47054.label = Run Time HWC +channel-type.nibeheatpump.f1x45-47054.description = Run time for the hot water circulation system +channel-type.nibeheatpump.f1x45-47055.label = Still Time HWC +channel-type.nibeheatpump.f1x45-47055.description = Still time for the hot water circulation system +channel-type.nibeheatpump.f1x45-47131.label = Language +channel-type.nibeheatpump.f1x45-47131.description = Display language in the heat pump 0=English 1=Svenska 2=Deutsch 3=Francais 4=Espanol 5=Suomi 6=Lietuviu 7=Cesky 8=Polski 9=Nederlands 10=Norsk 11=Dansk 12=Eesti 13=Latviesu 16=Magyar +channel-type.nibeheatpump.f1x45-47131.state.option.0 = English +channel-type.nibeheatpump.f1x45-47131.state.option.1 = Svenska +channel-type.nibeheatpump.f1x45-47131.state.option.2 = Deutsch +channel-type.nibeheatpump.f1x45-47131.state.option.3 = Francais +channel-type.nibeheatpump.f1x45-47131.state.option.4 = Espanol +channel-type.nibeheatpump.f1x45-47131.state.option.5 = Suomi +channel-type.nibeheatpump.f1x45-47131.state.option.6 = Lietuviu +channel-type.nibeheatpump.f1x45-47131.state.option.7 = Cesky +channel-type.nibeheatpump.f1x45-47131.state.option.8 = Polski +channel-type.nibeheatpump.f1x45-47131.state.option.9 = Nederlands +channel-type.nibeheatpump.f1x45-47131.state.option.10 = Norsk +channel-type.nibeheatpump.f1x45-47131.state.option.11 = Dansk +channel-type.nibeheatpump.f1x45-47131.state.option.12 = Eesti +channel-type.nibeheatpump.f1x45-47131.state.option.13 = Latviesu +channel-type.nibeheatpump.f1x45-47131.state.option.16 = Magyar +channel-type.nibeheatpump.f1x45-47134.label = Period HW +channel-type.nibeheatpump.f1x45-47135.label = Period Heat +channel-type.nibeheatpump.f1x45-47136.label = Period Pool +channel-type.nibeheatpump.f1x45-47137.label = Operational Mode +channel-type.nibeheatpump.f1x45-47137.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.f1x45-47137.state.option.0 = Auto +channel-type.nibeheatpump.f1x45-47137.state.option.1 = Manual +channel-type.nibeheatpump.f1x45-47137.state.option.2 = Add. heat only +channel-type.nibeheatpump.f1x45-47138.label = Operational Mode Heat Medium Pump +channel-type.nibeheatpump.f1x45-47138.description = 10=Intermittent 20=Continous 30=Economy 40=Auto +channel-type.nibeheatpump.f1x45-47138.state.option.10 = Intermittent +channel-type.nibeheatpump.f1x45-47138.state.option.20 = Continous +channel-type.nibeheatpump.f1x45-47138.state.option.30 = Economy +channel-type.nibeheatpump.f1x45-47138.state.option.40 = Auto +channel-type.nibeheatpump.f1x45-47139.label = Operational Mode Brine Medium Pump +channel-type.nibeheatpump.f1x45-47139.description = 10=Intermittent 20=Continuous 30=Economy 40=Auto +channel-type.nibeheatpump.f1x45-47139.state.option.10 = Intermittent +channel-type.nibeheatpump.f1x45-47139.state.option.20 = Continuous +channel-type.nibeheatpump.f1x45-47139.state.option.30 = Economy +channel-type.nibeheatpump.f1x45-47139.state.option.40 = Auto +channel-type.nibeheatpump.f1x45-47206.label = DM Start Heating +channel-type.nibeheatpump.f1x45-47206.description = The value the degree minutes needed to be reached for the pump to start heating +channel-type.nibeheatpump.f1x45-47207.label = DM Start Cooling +channel-type.nibeheatpump.f1x45-47207.description = The value the degree minutes needed to be reached for the pump to start cooling +channel-type.nibeheatpump.f1x45-47208.label = DM Start Add. +channel-type.nibeheatpump.f1x45-47208.description = The value the degree minutes needed to be reached for the pump to start electric addition +channel-type.nibeheatpump.f1x45-47209.label = DM Between Add. Steps +channel-type.nibeheatpump.f1x45-47209.description = The number of degree minutes between start of each electric addition step +channel-type.nibeheatpump.f1x45-47210.label = DM Start Add. with Shunt +channel-type.nibeheatpump.f1x45-47212.label = Max Int Add. Power +channel-type.nibeheatpump.f1x45-47214.label = Fuse +channel-type.nibeheatpump.f1x45-47214.description = Size of the fuse that the HP is connected to +channel-type.nibeheatpump.f1x45-47261.label = Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x45-47262.label = Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x45-47263.label = Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x45-47264.label = Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x45-47265.label = Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x45-47271.label = Fan Return Time 4 +channel-type.nibeheatpump.f1x45-47271.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x45-47272.label = Fan Return Time 3 +channel-type.nibeheatpump.f1x45-47272.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x45-47273.label = Fan Return Time 2 +channel-type.nibeheatpump.f1x45-47273.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x45-47274.label = Fan Return Time 1 +channel-type.nibeheatpump.f1x45-47274.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x45-47275.label = Filter Reminder Period +channel-type.nibeheatpump.f1x45-47275.description = Time between the reminder of filter replacement/cleaning. +channel-type.nibeheatpump.f1x45-47276.label = Floor Drying +channel-type.nibeheatpump.f1x45-47276.description = 0=Off 1=On +channel-type.nibeheatpump.f1x45-47277.label = Floor Drying Period 7 +channel-type.nibeheatpump.f1x45-47277.description = Days each period is active +channel-type.nibeheatpump.f1x45-47278.label = Floor Drying Period 6 +channel-type.nibeheatpump.f1x45-47278.description = Days each period is active +channel-type.nibeheatpump.f1x45-47279.label = Floor Drying Period 5 +channel-type.nibeheatpump.f1x45-47279.description = Days each period is active +channel-type.nibeheatpump.f1x45-47280.label = Floor Drying Period 4 +channel-type.nibeheatpump.f1x45-47280.description = Days each period is active +channel-type.nibeheatpump.f1x45-47281.label = Floor Drying Period 3 +channel-type.nibeheatpump.f1x45-47281.description = Days each period is active +channel-type.nibeheatpump.f1x45-47282.label = Floor Drying Period 2 +channel-type.nibeheatpump.f1x45-47282.description = Days each period is active +channel-type.nibeheatpump.f1x45-47283.label = Floor Drying Period 1 +channel-type.nibeheatpump.f1x45-47283.description = Days each period is active +channel-type.nibeheatpump.f1x45-47284.label = Floor Drying Temp. 7 +channel-type.nibeheatpump.f1x45-47284.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47285.label = Floor Drying Temp. 6 +channel-type.nibeheatpump.f1x45-47285.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47286.label = Floor Drying Temp. 5 +channel-type.nibeheatpump.f1x45-47286.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47287.label = Floor Drying Temp. 4 +channel-type.nibeheatpump.f1x45-47287.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47288.label = Floor Drying Temp. 3 +channel-type.nibeheatpump.f1x45-47288.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47289.label = Floor Drying Temp. 2 +channel-type.nibeheatpump.f1x45-47289.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47290.label = Floor Drying Temp. 1 +channel-type.nibeheatpump.f1x45-47290.description = Supply temperature each period +channel-type.nibeheatpump.f1x45-47291.label = Floor Drying Timer +channel-type.nibeheatpump.f1x45-47302.label = Climate System 2 Accessory +channel-type.nibeheatpump.f1x45-47302.description = Activates the climate system 2 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47303.label = Climate System 3 Accessory +channel-type.nibeheatpump.f1x45-47303.description = Activates the climate system 3 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47304.label = Climate System 4 Accessory +channel-type.nibeheatpump.f1x45-47304.description = Activates the climate system 4 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47305.label = Climate System 4 Mixing Valve Amp. +channel-type.nibeheatpump.f1x45-47305.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x45-47306.label = Climate System 3 Mixing Valve Amp. +channel-type.nibeheatpump.f1x45-47306.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x45-47307.label = Climate System 2 Mixing Valve Amp. +channel-type.nibeheatpump.f1x45-47307.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x45-47308.label = Climate System 4 Shunt Wait +channel-type.nibeheatpump.f1x45-47308.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x45-47309.label = Climate System 3 Shunt Wait +channel-type.nibeheatpump.f1x45-47309.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x45-47310.label = Climate System 2 Shunt Wait +channel-type.nibeheatpump.f1x45-47310.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x45-47312.label = FLM Pump +channel-type.nibeheatpump.f1x45-47312.description = Operating mode for the FLM pump 0=Off 1=On +channel-type.nibeheatpump.f1x45-47313.label = FLM Defrost +channel-type.nibeheatpump.f1x45-47313.description = Minimum time between defrost in FLM +channel-type.nibeheatpump.f1x45-47317.label = Shunt Controlled Add. Accessory +channel-type.nibeheatpump.f1x45-47317.description = Activates the shunt controlled addition accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47318.label = Shunt Controlled Add. Min. Temp. +channel-type.nibeheatpump.f1x45-47319.label = Shunt Controlled Add. Min. Runtime +channel-type.nibeheatpump.f1x45-47320.label = Shunt Controlled Add. Mixing Valve Amp. +channel-type.nibeheatpump.f1x45-47320.description = Mixing valve amplification for shunt controlled add. +channel-type.nibeheatpump.f1x45-47321.label = Shunt Controlled Add. Mixing Valve Wait +channel-type.nibeheatpump.f1x45-47321.description = Wait time between changes of the shunt in shunt controlled add. +channel-type.nibeheatpump.f1x45-47322.label = Step Controlled Add. Accessory +channel-type.nibeheatpump.f1x45-47322.description = Activates the step controlled addition accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47323.label = Step Controlled Add. Start DM +channel-type.nibeheatpump.f1x45-47323.description = DM where the first step of step controlled add. starts +channel-type.nibeheatpump.f1x45-47324.label = Step Controlled Add. Diff. DM +channel-type.nibeheatpump.f1x45-47324.description = Difference in DM of each step in the step controlled add. +channel-type.nibeheatpump.f1x45-47325.label = Step Controlled Add. Max. Step +channel-type.nibeheatpump.f1x45-47325.description = Maximum number of steps allowed in step controlled add. +channel-type.nibeheatpump.f1x45-47326.label = Step Controlled Add. Mode +channel-type.nibeheatpump.f1x45-47326.description = Binary or linear stepping method. 0=Linear 1=Binary +channel-type.nibeheatpump.f1x45-47327.label = Ground Water Pump Accessory +channel-type.nibeheatpump.f1x45-47327.description = Ground water pump using AXC40 0=Off 1=On +channel-type.nibeheatpump.f1x45-47329.label = Cooling 2-pipe Accessory +channel-type.nibeheatpump.f1x45-47329.description = Activates the 2-pipe cooling accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47330.label = Cooling 4-pipe Accessory +channel-type.nibeheatpump.f1x45-47330.description = Activates the 4-pipe cooling accessory 0=Off 1=On +channel-type.nibeheatpump.f1x45-47335.label = Time Betw. Switch Heat/cool +channel-type.nibeheatpump.f1x45-47335.description = Time between switching from heating to cooling or vice versa. +channel-type.nibeheatpump.f1x45-47336.label = Heat At Room Under Temp. +channel-type.nibeheatpump.f1x45-47336.description = This value indicates how many degrees under set room temp heating will be allowed +channel-type.nibeheatpump.f1x45-47337.label = Cool At Room over Temp. +channel-type.nibeheatpump.f1x45-47337.description = This value indicates how many degrees over set room temp cooling will be allowed +channel-type.nibeheatpump.f1x45-47338.label = Cooling Mix. Valve Amp. +channel-type.nibeheatpump.f1x45-47338.description = Mixing valve amplification for the cooling valve +channel-type.nibeheatpump.f1x45-47339.label = Cooling Mix. Valve Step Delay +channel-type.nibeheatpump.f1x45-47340.label = Cooling with Room Sensor +channel-type.nibeheatpump.f1x45-47340.description = Enables use of room sensor together with cooling 0=Off 1=On +channel-type.nibeheatpump.f1x45-47341.label = HPAC Accessory +channel-type.nibeheatpump.f1x45-47341.description = Activates the HPAC accessory +channel-type.nibeheatpump.f1x45-47342.label = Start Passive Cooling DM +channel-type.nibeheatpump.f1x45-47342.description = Value the degree minutes have to reach to start passive cooling +channel-type.nibeheatpump.f1x45-47343.label = Start Active Cooling DM +channel-type.nibeheatpump.f1x45-47343.description = Value the degree minutes have to reach to start active cooling +channel-type.nibeheatpump.f1x45-47352.label = SMS40 Accessory +channel-type.nibeheatpump.f1x45-47352.description = Activates the SMS40 accessory +channel-type.nibeheatpump.f1x45-47365.label = RMU System 1 +channel-type.nibeheatpump.f1x45-47365.description = Activates the RMU accessory for system 1 +channel-type.nibeheatpump.f1x45-47366.label = RMU System 2 +channel-type.nibeheatpump.f1x45-47366.description = Activates the RMU accessory for system 2 +channel-type.nibeheatpump.f1x45-47367.label = RMU System 3 +channel-type.nibeheatpump.f1x45-47367.description = Activates the RMU accessory for system 3 +channel-type.nibeheatpump.f1x45-47368.label = RMU System 4 +channel-type.nibeheatpump.f1x45-47368.description = Activates the RMU accessory for system 4 +channel-type.nibeheatpump.f1x45-47370.label = Allow Additive Heating +channel-type.nibeheatpump.f1x45-47370.description = Whether to allow additive heating (only valid for operational mode Manual) +channel-type.nibeheatpump.f1x45-47371.label = Allow Heating +channel-type.nibeheatpump.f1x45-47371.description = Whether to allow heating (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f1x45-47372.label = Allow Cooling +channel-type.nibeheatpump.f1x45-47372.description = Whether to allow cooling (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f1x45-47374.label = Start Temperature Cooling +channel-type.nibeheatpump.f1x45-47374.description = Start temperature for cooling +channel-type.nibeheatpump.f1x45-47375.label = Stop Temperature Heating +channel-type.nibeheatpump.f1x45-47375.description = Stop temperature for heating +channel-type.nibeheatpump.f1x45-47376.label = Stop Temperature Additive +channel-type.nibeheatpump.f1x45-47376.description = Stop temperature for additive +channel-type.nibeheatpump.f1x45-47377.label = Outdoor Filter Time +channel-type.nibeheatpump.f1x45-47377.description = Filter time in hours +channel-type.nibeheatpump.f1x45-47378.label = Max Diff. Comp. +channel-type.nibeheatpump.f1x45-47379.label = Max Diff. Add. +channel-type.nibeheatpump.f1x45-47380.label = Low Brine out Autoreset +channel-type.nibeheatpump.f1x45-47380.description = 0=Off 1=On +channel-type.nibeheatpump.f1x45-47381.label = Low Brine out Temp. +channel-type.nibeheatpump.f1x45-47382.label = High Brine In +channel-type.nibeheatpump.f1x45-47382.description = Activates the High brine in temperature alarm. 0=Off 1=On +channel-type.nibeheatpump.f1x45-47383.label = High Brine in Temp. +channel-type.nibeheatpump.f1x45-47383.description = The brine in temperature that triggers the high brine in temperature alarm (if active). +channel-type.nibeheatpump.f1x45-47384.label = Date Format +channel-type.nibeheatpump.f1x45-47384.description = 1=DD-MM-YY 2=YY-MM-DD +channel-type.nibeheatpump.f1x45-47384.state.option.1 = DD-MM-YY +channel-type.nibeheatpump.f1x45-47384.state.option.2 = YY-MM-DD +channel-type.nibeheatpump.f1x45-47385.label = Time Format +channel-type.nibeheatpump.f1x45-47385.description = 12=12 hours 24=24 Hours +channel-type.nibeheatpump.f1x45-47385.state.option.12 = hours 24 +channel-type.nibeheatpump.f1x45-47385.state.option.24 = Hours +channel-type.nibeheatpump.f1x45-47387.label = HW Production +channel-type.nibeheatpump.f1x45-47387.description = Activates hot water production where applicable 0=Off 1=On +channel-type.nibeheatpump.f1x45-47388.label = Alarm Lower Room Temp. +channel-type.nibeheatpump.f1x45-47388.description = Lowers the room temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f1x45-47389.label = Alarm Lower HW Temp. +channel-type.nibeheatpump.f1x45-47389.description = Lowers the hot water temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f1x45-47391.label = Use Room Sensor S4 +channel-type.nibeheatpump.f1x45-47391.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x45-47392.label = Use Room Sensor S3 +channel-type.nibeheatpump.f1x45-47392.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x45-47393.label = Use Room Sensor S2 +channel-type.nibeheatpump.f1x45-47393.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x45-47394.label = Use Room Sensor S1 +channel-type.nibeheatpump.f1x45-47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x45-47395.label = Room Sensor Setpoint S4 +channel-type.nibeheatpump.f1x45-47395.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x45-47396.label = Room Sensor Setpoint S3 +channel-type.nibeheatpump.f1x45-47396.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x45-47397.label = Room Sensor Setpoint S2 +channel-type.nibeheatpump.f1x45-47397.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x45-47398.label = Room Sensor Setpoint S1 +channel-type.nibeheatpump.f1x45-47398.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x45-47399.label = Room Sensor Factor S4 +channel-type.nibeheatpump.f1x45-47399.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x45-47400.label = Room Sensor Factor S3 +channel-type.nibeheatpump.f1x45-47400.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x45-47401.label = Room Sensor Factor S2 +channel-type.nibeheatpump.f1x45-47401.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x45-47402.label = Room Sensor Factor S1 +channel-type.nibeheatpump.f1x45-47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x45-47413.label = Speed Circ.pump HW +channel-type.nibeheatpump.f1x45-47414.label = Speed Circ.pump Heat +channel-type.nibeheatpump.f1x45-47415.label = Speed Circ.pump Pool +channel-type.nibeheatpump.f1x45-47416.label = Speed Circ.pump Economy +channel-type.nibeheatpump.f1x45-47417.label = Speed Circ.pump Cooling +channel-type.nibeheatpump.f1x45-47418.label = Speed Brine Pump +channel-type.nibeheatpump.f1x45-47537.label = Night Cooling +channel-type.nibeheatpump.f1x45-47537.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. 0=Off 1=On +channel-type.nibeheatpump.f1x45-47538.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f1x45-47539.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f1x45-47539.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f1x45-47540.label = Heat DM Diff +channel-type.nibeheatpump.f1x45-47540.description = Difference in DM between compressor starts in heating mode +channel-type.nibeheatpump.f1x45-47543.label = Cooling DM Diff +channel-type.nibeheatpump.f1x45-47543.description = Difference in DM between compressor starts in cooling mode +channel-type.nibeheatpump.f1x45-47570.label = Operational Mode +channel-type.nibeheatpump.f1x45-47570.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.f1x45-47570.state.option.0 = Auto +channel-type.nibeheatpump.f1x45-47570.state.option.1 = Manual +channel-type.nibeheatpump.f1x45-47570.state.option.2 = Add. heat only +channel-type.nibeheatpump.f1x45-48043.label = Holiday - Activated +channel-type.nibeheatpump.f1x45-48043.description = 0=inactive, 10=active +channel-type.nibeheatpump.f1x45-48043.state.option.0 = inactive +channel-type.nibeheatpump.f1x45-48043.state.option.10 = active +channel-type.nibeheatpump.f1x45-48046.label = Heat Offset Holiday +channel-type.nibeheatpump.f1x45-48046.description = Offset of the heat curve, Holiday +channel-type.nibeheatpump.f1x45-48047.label = Hot water mode Holiday +channel-type.nibeheatpump.f1x45-48047.description = Hot water comfort mode Holiday, -1 = off, 0 = economy, 1 = normal, 2 = luxury +channel-type.nibeheatpump.f1x45-48047.state.option.-1 = off +channel-type.nibeheatpump.f1x45-48047.state.option.0 = economy +channel-type.nibeheatpump.f1x45-48047.state.option.1 = normal +channel-type.nibeheatpump.f1x45-48047.state.option.2 = luxury +channel-type.nibeheatpump.f1x45-48053.label = FLM 2 Speed 4 +channel-type.nibeheatpump.f1x45-48054.label = FLM 2 Speed 3 +channel-type.nibeheatpump.f1x45-48055.label = FLM 2 Speed 2 +channel-type.nibeheatpump.f1x45-48056.label = FLM 2 Speed 1 +channel-type.nibeheatpump.f1x45-48057.label = FLM 2 Speed Normal +channel-type.nibeheatpump.f1x45-48058.label = FLM 3 Speed 4 +channel-type.nibeheatpump.f1x45-48059.label = FLM 3 Speed 3 +channel-type.nibeheatpump.f1x45-48060.label = FLM 3 Speed 2 +channel-type.nibeheatpump.f1x45-48061.label = FLM 3 Speed 1 +channel-type.nibeheatpump.f1x45-48062.label = FLM 3 Speed Normal +channel-type.nibeheatpump.f1x45-48063.label = FLM 4 Speed 4 +channel-type.nibeheatpump.f1x45-48064.label = FLM 4 Speed 3 +channel-type.nibeheatpump.f1x45-48065.label = FLM 4 Speed 2 +channel-type.nibeheatpump.f1x45-48066.label = FLM 4 Speed 1 +channel-type.nibeheatpump.f1x45-48067.label = FLM 4 Speed Normal +channel-type.nibeheatpump.f1x45-48068.label = FLM 4 Accessory +channel-type.nibeheatpump.f1x45-48068.description = Activates the FLM 4 accessory +channel-type.nibeheatpump.f1x45-48069.label = FLM 3 Accessory +channel-type.nibeheatpump.f1x45-48069.description = Activates the FLM 3 accessory +channel-type.nibeheatpump.f1x45-48070.label = FLM 2 Accessory +channel-type.nibeheatpump.f1x45-48070.description = Activates the FLM 2 accessory +channel-type.nibeheatpump.f1x45-48071.label = FLM 1 Accessory +channel-type.nibeheatpump.f1x45-48071.description = Activates the FLM 1 accessory +channel-type.nibeheatpump.f1x45-48072.label = DM Diff Start Add. +channel-type.nibeheatpump.f1x45-48072.description = The value below the last compressor step the degree minutes needed to be reached for the pump to start electric addition +channel-type.nibeheatpump.f1x45-48073.label = FLM Cooling +channel-type.nibeheatpump.f1x45-48073.description = FLM cooling activated +channel-type.nibeheatpump.f1x45-48074.label = Set Point for BT74 +channel-type.nibeheatpump.f1x45-48074.description = Set point for change between cooling and heating when using BT74 +channel-type.nibeheatpump.f1x45-48087.label = Pool 2 Accessory +channel-type.nibeheatpump.f1x45-48087.description = Activate the pool 2 accessory +channel-type.nibeheatpump.f1x45-48088.label = Pool 1 Accessory +channel-type.nibeheatpump.f1x45-48088.description = Activates the pool 1 accessory +channel-type.nibeheatpump.f1x45-48089.label = Pool 2 Start Temp. +channel-type.nibeheatpump.f1x45-48089.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.f1x45-48090.label = Pool 1 Start Temp. +channel-type.nibeheatpump.f1x45-48090.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.f1x45-48091.label = Pool 2 Stop Temp. +channel-type.nibeheatpump.f1x45-48091.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.f1x45-48092.label = Pool 1 Stop Temp. +channel-type.nibeheatpump.f1x45-48092.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.f1x45-48093.label = Pool 2 Activated +channel-type.nibeheatpump.f1x45-48093.description = Activates pool heating +channel-type.nibeheatpump.f1x45-48094.label = Pool 1 Activated +channel-type.nibeheatpump.f1x45-48094.description = Activates pool heating +channel-type.nibeheatpump.f1x45-48133.label = Period Pool 2 +channel-type.nibeheatpump.f1x45-48174.label = Min Cooling Supply Temp S4 +channel-type.nibeheatpump.f1x45-48174.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x45-48175.label = Min Cooling Supply Temp S3 +channel-type.nibeheatpump.f1x45-48175.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x45-48176.label = Min Cooling Supply Temp S2 +channel-type.nibeheatpump.f1x45-48176.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x45-48177.label = Min Cooling Supply Temp S1 +channel-type.nibeheatpump.f1x45-48177.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x45-48178.label = Cooling Supply Temp. At 20°C +channel-type.nibeheatpump.f1x45-48178.description = Supply Temperature at 20°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48179.label = Cooling Supply Temp. At 20°C +channel-type.nibeheatpump.f1x45-48179.description = Supply Temperature at 20°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48180.label = Cooling Supply Temp. At 20°C +channel-type.nibeheatpump.f1x45-48180.description = Supply Temperature at 20°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48181.label = Cooling Supply Temp. At 20°C +channel-type.nibeheatpump.f1x45-48181.description = Supply Temperature at 20°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48182.label = Cooling Supply Temp. At 40°C +channel-type.nibeheatpump.f1x45-48182.description = Supply Temperature at 40°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48183.label = Cooling Supply Temp. At 40°C +channel-type.nibeheatpump.f1x45-48183.description = Supply Temperature at 40°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48184.label = Cooling Supply Temp. At 40°C +channel-type.nibeheatpump.f1x45-48184.description = Supply Temperature at 40°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48185.label = Cooling Supply Temp. At 40°C +channel-type.nibeheatpump.f1x45-48185.description = Supply Temperature at 40°C. Used to create cooling curve +channel-type.nibeheatpump.f1x45-48186.label = Cooling Use Mix. Valves +channel-type.nibeheatpump.f1x45-48186.description = Close use valves during cooling mode +channel-type.nibeheatpump.f1x45-48187.label = Cooling Use Mix. Valves +channel-type.nibeheatpump.f1x45-48187.description = Close use valves during cooling mode +channel-type.nibeheatpump.f1x45-48188.label = Cooling Use Mix. Valves +channel-type.nibeheatpump.f1x45-48188.description = Close use valves during cooling mode +channel-type.nibeheatpump.f1x45-48189.label = Cooling Use Mix. Valves +channel-type.nibeheatpump.f1x45-48189.description = Close use valves during cooling mode +channel-type.nibeheatpump.f1x45-48190.label = Heatdump Mix. Valve Delay +channel-type.nibeheatpump.f1x45-48190.description = Mixing valve step delay for the heatdump valve +channel-type.nibeheatpump.f1x45-48191.label = Heatdump Mix. Valve Amp. +channel-type.nibeheatpump.f1x45-48191.description = Mixing valve amplification for the heatdump valve +channel-type.nibeheatpump.f1x45-48192.label = Cooldump Mix. Valve Delay +channel-type.nibeheatpump.f1x45-48192.description = Mixing valve step delay for the cooldump valve for the ACS-system +channel-type.nibeheatpump.f1x45-48193.label = Cooldump Mix. Valve Amp. +channel-type.nibeheatpump.f1x45-48193.description = Mixing valve amplification for the cooldump valve for the ACS-system +channel-type.nibeheatpump.f1x45-48194.label = ACS Accessory +channel-type.nibeheatpump.f1x45-48194.description = Activate the ACS accessory +channel-type.nibeheatpump.f1x45-48195.label = ACS Heat Dump 24h-function +channel-type.nibeheatpump.f1x45-48196.label = ACS Run Brinepump in Wait Mode +channel-type.nibeheatpump.f1x45-48197.label = ACS Closingtime for Cool Dump +channel-type.nibeheatpump.f1x45-48226.label = Max Charge Pump Reg Speed +channel-type.nibeheatpump.f1x45-48226.description = Max charge pump reg speed +channel-type.nibeheatpump.f1x45-48282.label = SG Ready Heating +channel-type.nibeheatpump.f1x45-48282.description = Sets whether or not SG Ready should affect heating +channel-type.nibeheatpump.f1x45-48283.label = SG Ready Cooling +channel-type.nibeheatpump.f1x45-48283.description = Sets whether or not SG Ready should affect cooling +channel-type.nibeheatpump.f1x45-48284.label = SG Ready Hot Water +channel-type.nibeheatpump.f1x45-48284.description = Sets whether or not SG Ready should affect hot water +channel-type.nibeheatpump.f1x45-48285.label = SG Ready Pool +channel-type.nibeheatpump.f1x45-48285.description = Sets whether or not SG Ready should affect pool +channel-type.nibeheatpump.f1x45-48452.label = Auto Heat Medium Pump Speed, Hw +channel-type.nibeheatpump.f1x45-48452.description = Auto heat medium pump speed hw +channel-type.nibeheatpump.f1x45-48453.label = Auto Heat Medium Pump Speed, Heat +channel-type.nibeheatpump.f1x45-48453.description = Auto heat medium pump speed heat +channel-type.nibeheatpump.f1x45-48454.label = Auto Heat Medium Pump Speed, Pool +channel-type.nibeheatpump.f1x45-48454.description = Auto heat medium pump speed pool +channel-type.nibeheatpump.f1x45-48455.label = Auto Heat Medium Pump Speed, Cool +channel-type.nibeheatpump.f1x45-48455.description = Auto heat medium pump speed cool +channel-type.nibeheatpump.f1x45-48456.label = Operational Mode Heat Medium Pump, Cooling +channel-type.nibeheatpump.f1x45-48458.label = Max Speed Circ.pump Heat +channel-type.nibeheatpump.f1x45-48459.label = Speed Brine Pump Cooling +channel-type.nibeheatpump.f1x45-48487.label = Speed Circ.pump Cooling +channel-type.nibeheatpump.f1x45-49008.label = Smart Energy Source, DM Diff Source Prio 2 +channel-type.nibeheatpump.f1x45-49008.description = Smart energy source, DM diff source with prio 2 +channel-type.nibeheatpump.f1x45-49009.label = Smart Energy Source, DM Start Source Prio 1 +channel-type.nibeheatpump.f1x45-49009.description = Smart energy source, DM start source with prio 1 +channel-type.nibeheatpump.f1x55-32260.label = NIBE Inverter 216-state +channel-type.nibeheatpump.f1x55-40004.label = BT1 Outdoor Temperature +channel-type.nibeheatpump.f1x55-40004.description = Current outdoor temperature +channel-type.nibeheatpump.f1x55-40005.label = EP23-BT2 Supply Temp S4 +channel-type.nibeheatpump.f1x55-40005.description = Supply temperature for system 4 +channel-type.nibeheatpump.f1x55-40006.label = EP22-BT2 Supply Temp S3 +channel-type.nibeheatpump.f1x55-40006.description = Supply temperature for system 3 +channel-type.nibeheatpump.f1x55-40007.label = EP21-BT2 Supply Temp S2 +channel-type.nibeheatpump.f1x55-40007.description = Supply temperature for system 2 +channel-type.nibeheatpump.f1x55-40008.label = BT2 Supply Temp S1 +channel-type.nibeheatpump.f1x55-40008.description = Supply temperature for system 1 +channel-type.nibeheatpump.f1x55-40012.label = EB100-EP14-BT3 Return Temp +channel-type.nibeheatpump.f1x55-40012.description = Return temperature +channel-type.nibeheatpump.f1x55-40013.label = BT7 HW Top +channel-type.nibeheatpump.f1x55-40013.description = Hot water top temperature, BT7 +channel-type.nibeheatpump.f1x55-40014.label = BT6 HW Load +channel-type.nibeheatpump.f1x55-40014.description = Hot water load temperature, BT6 +channel-type.nibeheatpump.f1x55-40015.label = EB100-EP14-BT10 Brine in Temp +channel-type.nibeheatpump.f1x55-40015.description = Brine in temperature, BT10 +channel-type.nibeheatpump.f1x55-40016.label = EB100-EP14-BT11 Brine out Temp +channel-type.nibeheatpump.f1x55-40016.description = Brine out temperature, BT11 +channel-type.nibeheatpump.f1x55-40017.label = EB100-EP14-BT12 Condensor Out +channel-type.nibeheatpump.f1x55-40017.description = Condensor out temperature, BT12 +channel-type.nibeheatpump.f1x55-40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f1x55-40018.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.f1x55-40019.label = EB100-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f1x55-40019.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.f1x55-40022.label = EB100-EP14-BT17 Suction +channel-type.nibeheatpump.f1x55-40022.description = Suction temperature, BT17 +channel-type.nibeheatpump.f1x55-40025.label = BT20 Exhaust Air Temp. 1 +channel-type.nibeheatpump.f1x55-40026.label = BT21 Vented Air Temp. 1 +channel-type.nibeheatpump.f1x55-40028.label = AZ1-BT26 Temp Collector in FLM 1 +channel-type.nibeheatpump.f1x55-40028.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40029.label = AZ1-BT27 Temp Collector out FLM 1 +channel-type.nibeheatpump.f1x55-40029.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40030.label = EP23-BT50 Room Temp S4 +channel-type.nibeheatpump.f1x55-40031.label = EP22-BT50 Room Temp S3 +channel-type.nibeheatpump.f1x55-40032.label = EP21-BT50 Room Temp S2 +channel-type.nibeheatpump.f1x55-40033.label = BT50 Room Temp S1 +channel-type.nibeheatpump.f1x55-40042.label = CL11-BT51 Pool 1 Temp +channel-type.nibeheatpump.f1x55-40042.description = Pool temperature for Pool 1, BT51 +channel-type.nibeheatpump.f1x55-40043.label = BT53 Solar Panel Temp +channel-type.nibeheatpump.f1x55-40043.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f1x55-40044.label = BT54 Solar Load Temp +channel-type.nibeheatpump.f1x55-40044.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f1x55-40045.label = EQ1-BT64 Cool Supply Temp +channel-type.nibeheatpump.f1x55-40045.description = Cool supply temperature, BT64 +channel-type.nibeheatpump.f1x55-40046.label = EQ1-BT65 Cool Return Temp +channel-type.nibeheatpump.f1x55-40046.description = Cool return temperature, BT65 +channel-type.nibeheatpump.f1x55-40054.label = EB100-FD1 Temperature Limiter +channel-type.nibeheatpump.f1x55-40067.label = BT1 Average +channel-type.nibeheatpump.f1x55-40067.description = EB100-BT1 Outdoor temperature average +channel-type.nibeheatpump.f1x55-40070.label = EM1-BT52 Boiler Temperature +channel-type.nibeheatpump.f1x55-40070.description = Boiler temperature, BT52 +channel-type.nibeheatpump.f1x55-40071.label = BT25 Ext. Supply +channel-type.nibeheatpump.f1x55-40071.description = External supply temperature, BT25 +channel-type.nibeheatpump.f1x55-40072.label = BF1 EP14 Flow +channel-type.nibeheatpump.f1x55-40072.description = Current flow EP14|Current flow EP15 +channel-type.nibeheatpump.f1x55-40074.label = EB100-FR1 Anode Status +channel-type.nibeheatpump.f1x55-40075.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f1x55-40079.label = EB100-BE3 Current +channel-type.nibeheatpump.f1x55-40081.label = EB100-BE2 Current +channel-type.nibeheatpump.f1x55-40083.label = EB100-BE1 Current +channel-type.nibeheatpump.f1x55-40106.label = CL12-BT51 Pool 2 Temp +channel-type.nibeheatpump.f1x55-40106.description = Pool temperature for Pool 2, BT51 +channel-type.nibeheatpump.f1x55-40107.label = BT20 Exhaust Air Temp. 4 +channel-type.nibeheatpump.f1x55-40108.label = BT20 Exhaust Air Temp. 3 +channel-type.nibeheatpump.f1x55-40109.label = BT20 Exhaust Air Temp. 2 +channel-type.nibeheatpump.f1x55-40110.label = BT21 Vented Air Temp. 4 +channel-type.nibeheatpump.f1x55-40111.label = BT21 Vented Air Temp. 3 +channel-type.nibeheatpump.f1x55-40112.label = BT21 Vented Air Temp. 2 +channel-type.nibeheatpump.f1x55-40113.label = AZ4-BT26 Temp Collector in FLM 4 +channel-type.nibeheatpump.f1x55-40113.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40114.label = AZ3-BT26 Temp Collector in FLM 3 +channel-type.nibeheatpump.f1x55-40114.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40115.label = AZ2-BT26 Temp Collector in FLM 2 +channel-type.nibeheatpump.f1x55-40115.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40116.label = AZ4-BT27 Temp Collector out FLM 4 +channel-type.nibeheatpump.f1x55-40116.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40117.label = AZ3-BT27 Temp Collector out FLM 3 +channel-type.nibeheatpump.f1x55-40117.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40118.label = AZ2-BT27 Temp Collector out FLM 2 +channel-type.nibeheatpump.f1x55-40118.description = Connected to the FLM module +channel-type.nibeheatpump.f1x55-40127.label = EP23-BT3 Return Temp S4 +channel-type.nibeheatpump.f1x55-40127.description = Return temperature for system 4 +channel-type.nibeheatpump.f1x55-40128.label = EP22-BT3 Return Temp S3 +channel-type.nibeheatpump.f1x55-40128.description = Return temperature for system 3 +channel-type.nibeheatpump.f1x55-40129.label = EP21-BT3 Return Temp S2 +channel-type.nibeheatpump.f1x55-40129.description = Return temperature for system 2 +channel-type.nibeheatpump.f1x55-40146.label = EB100-EP14-BT29 Cpr Oil Temp +channel-type.nibeheatpump.f1x55-40146.description = Compressor oil temperature, BT29 +channel-type.nibeheatpump.f1x55-40147.label = BT70 HW Comfort Supply Temp. +channel-type.nibeheatpump.f1x55-40147.description = Hot water comfort supply temperature, BT70 +channel-type.nibeheatpump.f1x55-40155.label = EQ1-BT57 Collector Temp. +channel-type.nibeheatpump.f1x55-40155.description = External collector temperature, BT57, for ACS +channel-type.nibeheatpump.f1x55-40156.label = EQ1-BT75 Heatdump Temp. +channel-type.nibeheatpump.f1x55-40156.description = Heating medium dump temperature, BT75, for ACS +channel-type.nibeheatpump.f1x55-40159.label = EP47-BT2 Supply Temp S8 +channel-type.nibeheatpump.f1x55-40159.description = Supply temperature for system 8 +channel-type.nibeheatpump.f1x55-40160.label = EP46-BT2 Supply Temp S7 +channel-type.nibeheatpump.f1x55-40160.description = Supply temperature for system 7 +channel-type.nibeheatpump.f1x55-40161.label = EP45-BT2 Supply Temp S6 +channel-type.nibeheatpump.f1x55-40161.description = Supply temperature for system 6 +channel-type.nibeheatpump.f1x55-40162.label = EP44-BT2 Supply Temp S5 +channel-type.nibeheatpump.f1x55-40162.description = Supply temperature for system 5 +channel-type.nibeheatpump.f1x55-40163.label = EP47-BT3 Return Temp S8 +channel-type.nibeheatpump.f1x55-40163.description = Return temperature for system 8 +channel-type.nibeheatpump.f1x55-40164.label = EP46-BT3 Return Temp S7 +channel-type.nibeheatpump.f1x55-40164.description = Return temperature for system 7 +channel-type.nibeheatpump.f1x55-40165.label = EP45-BT3 Return Temp S6 +channel-type.nibeheatpump.f1x55-40165.description = Return temperature for system 6 +channel-type.nibeheatpump.f1x55-40166.label = EP44-BT3 Return Temp S5 +channel-type.nibeheatpump.f1x55-40166.description = Return temperature for system 5 +channel-type.nibeheatpump.f1x55-40167.label = EP47-BT50 Room Temp S8 +channel-type.nibeheatpump.f1x55-40168.label = EP46-BT50 Room Temp S7 +channel-type.nibeheatpump.f1x55-40169.label = EP45-BT50 Room Temp S6 +channel-type.nibeheatpump.f1x55-40170.label = EP44-BT50 Room Temp S5 +channel-type.nibeheatpump.f1x55-40183.label = AZ30-BT23 Outdoor Temp. ERS 1 +channel-type.nibeheatpump.f1x55-40185.label = BT1 Average, 1h +channel-type.nibeheatpump.f1x55-40185.description = EB100-BT1 Outdoor temperature average, 1h +channel-type.nibeheatpump.f1x55-40188.label = EP47-BT50 Room Temp S8 Average +channel-type.nibeheatpump.f1x55-40189.label = EP46-BT50 Room Temp S7 Average +channel-type.nibeheatpump.f1x55-40190.label = EP45-BT50 Room Temp S6 Average +channel-type.nibeheatpump.f1x55-40191.label = EP44-BT50 Room Temp S5 Average +channel-type.nibeheatpump.f1x55-40192.label = EP23-BT50 Room Temp S4 Average +channel-type.nibeheatpump.f1x55-40193.label = EP22-BT50 Room Temp S3 Average +channel-type.nibeheatpump.f1x55-40194.label = EP21-BT50 Room Temp S2 Average +channel-type.nibeheatpump.f1x55-40195.label = BT50 Room Temp S1 Average +channel-type.nibeheatpump.f1x55-40212.label = BT74 Average +channel-type.nibeheatpump.f1x55-40212.description = BT74 heating cooling sensor average +channel-type.nibeheatpump.f1x55-40216.label = BT25 Ext. Supply Temp, Cooling +channel-type.nibeheatpump.f1x55-40217.label = Calc. Supply S8 +channel-type.nibeheatpump.f1x55-40217.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-40218.label = Calc. Supply S7 +channel-type.nibeheatpump.f1x55-40218.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-40219.label = Calc. Supply S6 +channel-type.nibeheatpump.f1x55-40219.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-40220.label = Calculated Supply S5 +channel-type.nibeheatpump.f1x55-40220.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-40221.label = Calc. Cooling Supply S8 +channel-type.nibeheatpump.f1x55-40221.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-40222.label = Calc. Cooling Supply S7 +channel-type.nibeheatpump.f1x55-40222.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-40223.label = Calc. Cooling Supply S6 +channel-type.nibeheatpump.f1x55-40223.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-40224.label = Calc. Cooling Supply S5 +channel-type.nibeheatpump.f1x55-40224.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-40305.label = Mixing Valve State S8 +channel-type.nibeheatpump.f1x55-40305.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-40306.label = Mixing Valve State S7 +channel-type.nibeheatpump.f1x55-40306.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-40307.label = Mixing Valve State S6 +channel-type.nibeheatpump.f1x55-40307.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-40308.label = Mixing Valve State S5 +channel-type.nibeheatpump.f1x55-40308.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-40310.label = External ERS 1 Accessory Relays +channel-type.nibeheatpump.f1x55-40310.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.f1x55-40311.label = External ERS 1 Accessory GQ2 Speed +channel-type.nibeheatpump.f1x55-40311.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-40312.label = External ERS 1 Accessory GQ3 Speed +channel-type.nibeheatpump.f1x55-40312.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-40316.label = Inverter Limit Status +channel-type.nibeheatpump.f1x55-40317.label = Inverter Drive Status +channel-type.nibeheatpump.f1x55-40321.label = Compressor Frequency, Request +channel-type.nibeheatpump.f1x55-40321.description = The compressor frequency that has been requested by the system +channel-type.nibeheatpump.f1x55-40322.label = Max Compressor Frequency, Heating +channel-type.nibeheatpump.f1x55-40322.description = The maximum frequency of the compressor in heating mode +channel-type.nibeheatpump.f1x55-40323.label = Inverter Alarm Code +channel-type.nibeheatpump.f1x55-40324.label = Inverter Fault Code +channel-type.nibeheatpump.f1x55-40326.label = Inverter Drive Command +channel-type.nibeheatpump.f1x55-40327.label = NIBE Inverter Pic Version +channel-type.nibeheatpump.f1x55-40328.label = NIBE Inverter 8051 Version +channel-type.nibeheatpump.f1x55-40329.label = NIBE Inverter Def. Wizard +channel-type.nibeheatpump.f1x55-40330.label = NIBE Inverter Mce Version +channel-type.nibeheatpump.f1x55-40331.label = NIBE Inverter Hw Version +channel-type.nibeheatpump.f1x55-40332.label = NIBE Inverter Hw Type +channel-type.nibeheatpump.f1x55-40339.label = External Adjustment Activated Via Input S8 +channel-type.nibeheatpump.f1x55-40340.label = External Adjustment Activated Via Input S7 +channel-type.nibeheatpump.f1x55-40341.label = External Adjustment Activated Via Input S6 +channel-type.nibeheatpump.f1x55-40342.label = External Adjustment Activated Via Input S5 +channel-type.nibeheatpump.f1x55-40365.label = Extra Heating System Pump S8 +channel-type.nibeheatpump.f1x55-40366.label = Extra Heating System Pump S7 +channel-type.nibeheatpump.f1x55-40367.label = Extra Heating System Pump S6 +channel-type.nibeheatpump.f1x55-40368.label = Extra Heating System Pump S5 +channel-type.nibeheatpump.f1x55-40369.label = Extra Cooling HPAC, ACS +channel-type.nibeheatpump.f1x55-40625.label = BT82 HW Comfort Return Temp +channel-type.nibeheatpump.f1x55-40626.label = BT83 HW Comfort Cylinder Temp +channel-type.nibeheatpump.f1x55-40755.label = Tot. Ext. HW Add Op.time +channel-type.nibeheatpump.f1x55-40755.description = Total external hw-electric additive operation time +channel-type.nibeheatpump.f1x55-40771.label = Heat Meter - Pool2 Cpr EP14 +channel-type.nibeheatpump.f1x55-40771.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-40792.label = OPT State +channel-type.nibeheatpump.f1x55-40792.description = Indicates the state of the boiler connected through the OPT accessory. +channel-type.nibeheatpump.f1x55-40793.label = OPT Version +channel-type.nibeheatpump.f1x55-40793.description = Version of the OPT PCBA software +channel-type.nibeheatpump.f1x55-40801.label = OPT Rel. Modulation Level +channel-type.nibeheatpump.f1x55-40801.description = OPT relative modulation level +channel-type.nibeheatpump.f1x55-40802.label = OPT Boiler Temperature +channel-type.nibeheatpump.f1x55-40802.description = OPT boiler temperature +channel-type.nibeheatpump.f1x55-40806.label = OPT Boiler Op. Time +channel-type.nibeheatpump.f1x55-40806.description = OPT boiler operation time +channel-type.nibeheatpump.f1x55-40813.label = Compressor Slow Down Reason +channel-type.nibeheatpump.f1x55-40813.description = Bitmap telling the reason to why the compressor slows down. b0:inverter b1:brine b2:current b3:high cond b4:hot gas b5:evaporator +channel-type.nibeheatpump.f1x55-40834.label = BM1 Humidity +channel-type.nibeheatpump.f1x55-40856.label = BM1 BT50 Room Temp. +channel-type.nibeheatpump.f1x55-40857.label = BM1 Pressure +channel-type.nibeheatpump.f1x55-40858.label = BM1 Dewpoint +channel-type.nibeheatpump.f1x55-40868.label = +Adjust AUX Port +channel-type.nibeheatpump.f1x55-40870.label = +Adjust OP Mode +channel-type.nibeheatpump.f1x55-40870.description = Tells if plusadjust system calls for heat or cool +channel-type.nibeheatpump.f1x55-40871.label = +Adjust Comfort Mode +channel-type.nibeheatpump.f1x55-40871.description = Which comfort mode +channel-type.nibeheatpump.f1x55-40872.label = +Adjust Parallell Adjustment +channel-type.nibeheatpump.f1x55-40872.description = requested adjustment +channel-type.nibeheatpump.f1x55-40873.label = +Adjust Humidity +channel-type.nibeheatpump.f1x55-40873.description = Humidity +channel-type.nibeheatpump.f1x55-40874.label = +Adjust Temp Indoor +channel-type.nibeheatpump.f1x55-40874.description = Average of all room sensors +channel-type.nibeheatpump.f1x55-40875.label = +Adjust Temp Outdoor +channel-type.nibeheatpump.f1x55-40875.description = Outdoor temp +channel-type.nibeheatpump.f1x55-40876.label = +Adjust Version +channel-type.nibeheatpump.f1x55-40876.description = PCA input version +channel-type.nibeheatpump.f1x55-40877.label = +Adjust Activated +channel-type.nibeheatpump.f1x55-40877.description = If plusadjust accessory is activated +channel-type.nibeheatpump.f1x55-40878.label = +Adjust Need +channel-type.nibeheatpump.f1x55-40878.description = If plusadjust system calls for heat +channel-type.nibeheatpump.f1x55-40879.label = +Adjust Parallell Factor +channel-type.nibeheatpump.f1x55-40880.label = +Adjust Max Change +channel-type.nibeheatpump.f1x55-40880.description = Largest allowed change +channel-type.nibeheatpump.f1x55-40881.label = +Adjust Affect System8 +channel-type.nibeheatpump.f1x55-40881.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40882.label = +Adjust Affect System7 +channel-type.nibeheatpump.f1x55-40882.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40883.label = +Adjust Affect System6 +channel-type.nibeheatpump.f1x55-40883.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40884.label = +Adjust Affect System5 +channel-type.nibeheatpump.f1x55-40884.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40885.label = +Adjust Affect System4 +channel-type.nibeheatpump.f1x55-40885.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40886.label = +Adjust Affect System3 +channel-type.nibeheatpump.f1x55-40886.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40887.label = +Adjust Affect System2 +channel-type.nibeheatpump.f1x55-40887.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40888.label = +Adjust Affect System1 +channel-type.nibeheatpump.f1x55-40888.description = System affected by paralell change +channel-type.nibeheatpump.f1x55-40889.label = BT64 Average +channel-type.nibeheatpump.f1x55-40889.description = BT64 Cooling supply average +channel-type.nibeheatpump.f1x55-40912.label = EQ1 State ACS Thermostat +channel-type.nibeheatpump.f1x55-40912.description = 10=off,40=active wait,50=active +channel-type.nibeheatpump.f1x55-40912.state.option.10 = off +channel-type.nibeheatpump.f1x55-40912.state.option.40 = active wait +channel-type.nibeheatpump.f1x55-40912.state.option.50 = active +channel-type.nibeheatpump.f1x55-40913.label = EQ1 State ACS Thermostat Heat Dump +channel-type.nibeheatpump.f1x55-40913.description = 10=shunt off,20=shunt open,30=shunt closed +channel-type.nibeheatpump.f1x55-40913.state.option.10 = shunt off +channel-type.nibeheatpump.f1x55-40913.state.option.20 = shunt open +channel-type.nibeheatpump.f1x55-40913.state.option.30 = shunt closed +channel-type.nibeheatpump.f1x55-40940.label = Degree Minutes (32 Bit) +channel-type.nibeheatpump.f1x55-40940.description = Degree minutes, 32bit value. Full resolution. +channel-type.nibeheatpump.f1x55-40942.label = External ERS 1 Accessory Block Status +channel-type.nibeheatpump.f1x55-40942.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.f1x55-40943.label = External ERS 1 Accessory EB17 +channel-type.nibeheatpump.f1x55-40943.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.f1x55-40943.state.option.0 = open. +channel-type.nibeheatpump.f1x55-40993.label = Inverter Min Speed +channel-type.nibeheatpump.f1x55-40994.label = Inverter Max Speed +channel-type.nibeheatpump.f1x55-40995.label = External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.f1x55-40997.label = External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.f1x55-41027.label = Humidity Average +channel-type.nibeheatpump.f1x55-41027.description = Humidity average +channel-type.nibeheatpump.f1x55-41186.label = Set Point OPT Boiler +channel-type.nibeheatpump.f1x55-41186.description = Set point OPT boiler +channel-type.nibeheatpump.f1x55-41189.label = AA20-BE5 EME10 Current +channel-type.nibeheatpump.f1x55-41190.label = AA20-BE5 EME10 Average Current +channel-type.nibeheatpump.f1x55-41191.label = PV Panel State +channel-type.nibeheatpump.f1x55-41210.label = AZ4-BT50 Room Temp +channel-type.nibeheatpump.f1x55-41210.description = AZ4-BT50 Room temp +channel-type.nibeheatpump.f1x55-41211.label = AZ3-BT50 Room Temp +channel-type.nibeheatpump.f1x55-41211.description = AZ3-BT50 Room temp +channel-type.nibeheatpump.f1x55-41212.label = AZ2-BT50 Room Temp +channel-type.nibeheatpump.f1x55-41212.description = AZ2-BT50 Room temp +channel-type.nibeheatpump.f1x55-41213.label = AZ1-BT50 Room Temp +channel-type.nibeheatpump.f1x55-41213.description = AZ1-BT50 Room temp +channel-type.nibeheatpump.f1x55-41256.label = Fan Speed Current +channel-type.nibeheatpump.f1x55-41256.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f1x55-41257.label = Fan Speed Current +channel-type.nibeheatpump.f1x55-41257.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f1x55-41258.label = Fan Speed Current +channel-type.nibeheatpump.f1x55-41258.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f1x55-41265.label = Smart Home Mode +channel-type.nibeheatpump.f1x55-41265.description = Current smart home mode, 0=Default,1=Away from home,2=Vacation +channel-type.nibeheatpump.f1x55-41265.state.option.0 = Default +channel-type.nibeheatpump.f1x55-41265.state.option.1 = Away from home +channel-type.nibeheatpump.f1x55-41265.state.option.2 = Vacation +channel-type.nibeheatpump.f1x55-41266.label = Offset to Smart Home System +channel-type.nibeheatpump.f1x55-41266.description = Offset to smart home system +channel-type.nibeheatpump.f1x55-41267.label = Smart Home Ctrl Syst 8 +channel-type.nibeheatpump.f1x55-41267.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41268.label = Smart Home Ctrl Syst 7 +channel-type.nibeheatpump.f1x55-41268.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41269.label = Smart Home Ctrl Syst 6 +channel-type.nibeheatpump.f1x55-41269.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41270.label = Smart Home Ctrl Syst 5 +channel-type.nibeheatpump.f1x55-41270.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41271.label = Smart Home Ctrl Syst 4 +channel-type.nibeheatpump.f1x55-41271.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41272.label = Smart Home Ctrl Syst 3 +channel-type.nibeheatpump.f1x55-41272.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41273.label = Smart Home Ctrl Syst 2 +channel-type.nibeheatpump.f1x55-41273.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41274.label = Smart Home Ctrl Syst 1 +channel-type.nibeheatpump.f1x55-41274.description = Smart Home is controlling the system +channel-type.nibeheatpump.f1x55-41287.label = OPT Boiler Has Priority Hot Water +channel-type.nibeheatpump.f1x55-41287.description = OPT boiler has priority hot water +channel-type.nibeheatpump.f1x55-41393.label = Smart Energy Source, Energy Source Prio 7, Start DM +channel-type.nibeheatpump.f1x55-41393.description = Energy source prio 7, start DM +channel-type.nibeheatpump.f1x55-41395.label = Smart Energy Source, Energy Source Prio 6, Start DM +channel-type.nibeheatpump.f1x55-41395.description = Energy source prio 6, start DM +channel-type.nibeheatpump.f1x55-41397.label = Smart Energy Source, Energy Source Prio 5, Start DM +channel-type.nibeheatpump.f1x55-41397.description = Energy source prio 5, start DM +channel-type.nibeheatpump.f1x55-41399.label = Smart Energy Source, Energy Source Prio 4, Start DM +channel-type.nibeheatpump.f1x55-41399.description = Energy source prio 4, start DM +channel-type.nibeheatpump.f1x55-41401.label = Smart Energy Source, Energy Source Prio 3, Start DM +channel-type.nibeheatpump.f1x55-41401.description = Energy source prio 3, start DM +channel-type.nibeheatpump.f1x55-41403.label = Smart Energy Source, Energy Source Prio 2, Start DM +channel-type.nibeheatpump.f1x55-41403.description = Energy source prio 2, start DM +channel-type.nibeheatpump.f1x55-41405.label = Smart Energy Source, Energy Source Prio 1, Start DM +channel-type.nibeheatpump.f1x55-41405.description = Energy source prio 1, start DM +channel-type.nibeheatpump.f1x55-41421.label = Smart Energy Source, Degree Minute Min Value +channel-type.nibeheatpump.f1x55-41421.description = Smart energy source, degree minute min value in Smart energy source system +channel-type.nibeheatpump.f1x55-41424.label = Smart Energy Source, Actual OPT10 Addition Price +channel-type.nibeheatpump.f1x55-41424.description = Smart energy source, actual OPT10 addition price. +channel-type.nibeheatpump.f1x55-41425.label = Smart Energy Source, Actual Shunt Add Price +channel-type.nibeheatpump.f1x55-41425.description = Smart energy source, actual external step addition price. +channel-type.nibeheatpump.f1x55-41426.label = Smart Energy Source, Actual Ext. Step Add Price +channel-type.nibeheatpump.f1x55-41426.description = Smart energy source, actual external step add price. +channel-type.nibeheatpump.f1x55-41427.label = Smart Energy Source, Actual Electricity Price +channel-type.nibeheatpump.f1x55-41427.description = Smart energy source, actual electricity price. +channel-type.nibeheatpump.f1x55-41429.label = EP12-BT57 Collector In +channel-type.nibeheatpump.f1x55-41430.label = EP12-BT58 Collector Out +channel-type.nibeheatpump.f1x55-41928.label = Smart Price Adaption Price +channel-type.nibeheatpump.f1x55-41928.description = The current electric price +channel-type.nibeheatpump.f1x55-41929.label = Smart Price Adaption Price Level +channel-type.nibeheatpump.f1x55-41929.description = Whether the current price is unknown (0), low (1), medium (2), high (3) +channel-type.nibeheatpump.f1x55-41930.label = AA23-BE5 Power 10 +channel-type.nibeheatpump.f1x55-41931.label = AA23-BE5 Power 9 +channel-type.nibeheatpump.f1x55-41932.label = AA23-BE5 Power 8 +channel-type.nibeheatpump.f1x55-41933.label = AA23-BE5 Power 7 +channel-type.nibeheatpump.f1x55-41934.label = AA23-BE5 Power 6 +channel-type.nibeheatpump.f1x55-41935.label = AA23-BE5 Power 5 +channel-type.nibeheatpump.f1x55-41936.label = AA23-BE5 Power 4 +channel-type.nibeheatpump.f1x55-41937.label = AA23-BE5 Power 3 +channel-type.nibeheatpump.f1x55-41938.label = AA23-BE5 Power 2 +channel-type.nibeheatpump.f1x55-41939.label = AA23-BE5 Power 1 +channel-type.nibeheatpump.f1x55-41940.label = AA23-BE5 Error High 10 +channel-type.nibeheatpump.f1x55-41941.label = AA23-BE5 Error High 9 +channel-type.nibeheatpump.f1x55-41942.label = AA23-BE5 Error High 8 +channel-type.nibeheatpump.f1x55-41943.label = AA23-BE5 Error High 7 +channel-type.nibeheatpump.f1x55-41944.label = AA23-BE5 Error High 6 +channel-type.nibeheatpump.f1x55-41945.label = AA23-BE5 Error High 5 +channel-type.nibeheatpump.f1x55-41946.label = AA23-BE5 Error High 4 +channel-type.nibeheatpump.f1x55-41947.label = AA23-BE5 Error High 3 +channel-type.nibeheatpump.f1x55-41948.label = AA23-BE5 Error High 2 +channel-type.nibeheatpump.f1x55-41949.label = AA23-BE5 Error High 1 +channel-type.nibeheatpump.f1x55-41950.label = AA23-BE5 Error Low 10 +channel-type.nibeheatpump.f1x55-41951.label = AA23-BE5 Error Low 9 +channel-type.nibeheatpump.f1x55-41952.label = AA23-BE5 Error Low 8 +channel-type.nibeheatpump.f1x55-41953.label = AA23-BE5 Error Low 7 +channel-type.nibeheatpump.f1x55-41954.label = AA23-BE5 Error Low 6 +channel-type.nibeheatpump.f1x55-41955.label = AA23-BE5 Error Low 5 +channel-type.nibeheatpump.f1x55-41956.label = AA23-BE5 Error Low 4 +channel-type.nibeheatpump.f1x55-41957.label = AA23-BE5 Error Low 3 +channel-type.nibeheatpump.f1x55-41958.label = AA23-BE5 Error Low 2 +channel-type.nibeheatpump.f1x55-41959.label = AA23-BE5 Error Low 1 +channel-type.nibeheatpump.f1x55-41960.label = AA23-BE5 Com Percentage 10 +channel-type.nibeheatpump.f1x55-41961.label = AA23-BE5 Com Percentage 9 +channel-type.nibeheatpump.f1x55-41962.label = AA23-BE5 Com Percentage 8 +channel-type.nibeheatpump.f1x55-41963.label = AA23-BE5 Com Percentage 7 +channel-type.nibeheatpump.f1x55-41964.label = AA23-BE5 Com Percentage 6 +channel-type.nibeheatpump.f1x55-41965.label = AA23-BE5 Com Percentage 5 +channel-type.nibeheatpump.f1x55-41966.label = AA23-BE5 Com Percentage 4 +channel-type.nibeheatpump.f1x55-41967.label = AA23-BE5 Com Percentage 3 +channel-type.nibeheatpump.f1x55-41968.label = AA23-BE5 Com Percentage 2 +channel-type.nibeheatpump.f1x55-41969.label = AA23-BE5 Com Percentage 1 +channel-type.nibeheatpump.f1x55-41980.label = AA23-BE5 Voltage1 10 +channel-type.nibeheatpump.f1x55-41981.label = AA23-BE5 Voltage1 9 +channel-type.nibeheatpump.f1x55-41982.label = AA23-BE5 Voltage1 8 +channel-type.nibeheatpump.f1x55-41983.label = AA23-BE5 Voltage1 7 +channel-type.nibeheatpump.f1x55-41984.label = AA23-BE5 Voltage1 6 +channel-type.nibeheatpump.f1x55-41985.label = AA23-BE5 Voltage1 5 +channel-type.nibeheatpump.f1x55-41986.label = AA23-BE5 Voltage1 4 +channel-type.nibeheatpump.f1x55-41987.label = AA23-BE5 Voltage1 3 +channel-type.nibeheatpump.f1x55-41988.label = AA23-BE5 Voltage1 2 +channel-type.nibeheatpump.f1x55-41989.label = AA23-BE5 Voltage1 1 +channel-type.nibeheatpump.f1x55-41990.label = AA23-BE5 Voltage2 10 +channel-type.nibeheatpump.f1x55-41991.label = AA23-BE5 Voltage2 9 +channel-type.nibeheatpump.f1x55-41992.label = AA23-BE5 Voltage2 8 +channel-type.nibeheatpump.f1x55-41993.label = AA23-BE5 Voltage2 7 +channel-type.nibeheatpump.f1x55-41994.label = AA23-BE5 Voltage2 6 +channel-type.nibeheatpump.f1x55-41995.label = AA23-BE5 Voltage2 5 +channel-type.nibeheatpump.f1x55-41996.label = AA23-BE5 Voltage2 4 +channel-type.nibeheatpump.f1x55-41997.label = AA23-BE5 Voltage2 3 +channel-type.nibeheatpump.f1x55-41998.label = AA23-BE5 Voltage2 2 +channel-type.nibeheatpump.f1x55-41999.label = AA23-BE5 Voltage2 1 +channel-type.nibeheatpump.f1x55-42000.label = AA23-BE5 Temperature 10 +channel-type.nibeheatpump.f1x55-42001.label = AA23-BE5 Temperature 9 +channel-type.nibeheatpump.f1x55-42002.label = AA23-BE5 Temperature 8 +channel-type.nibeheatpump.f1x55-42003.label = AA23-BE5 Temperature 7 +channel-type.nibeheatpump.f1x55-42004.label = AA23-BE5 Temperature 6 +channel-type.nibeheatpump.f1x55-42005.label = AA23-BE5 Temperature 5 +channel-type.nibeheatpump.f1x55-42006.label = AA23-BE5 Temperature 4 +channel-type.nibeheatpump.f1x55-42007.label = AA23-BE5 Temperature 3 +channel-type.nibeheatpump.f1x55-42008.label = AA23-BE5 Temperature 2 +channel-type.nibeheatpump.f1x55-42009.label = AA23-BE5 Temperature 1 +channel-type.nibeheatpump.f1x55-42010.label = AA23-BE5 Energy 10 +channel-type.nibeheatpump.f1x55-42012.label = AA23-BE5 Energy 9 +channel-type.nibeheatpump.f1x55-42014.label = AA23-BE5 Energy 8 +channel-type.nibeheatpump.f1x55-42016.label = AA23-BE5 Energy 7 +channel-type.nibeheatpump.f1x55-42018.label = AA23-BE5 Energy 6 +channel-type.nibeheatpump.f1x55-42020.label = AA23-BE5 Energy 5 +channel-type.nibeheatpump.f1x55-42022.label = AA23-BE5 Energy 4 +channel-type.nibeheatpump.f1x55-42024.label = AA23-BE5 Energy 3 +channel-type.nibeheatpump.f1x55-42026.label = AA23-BE5 Energy 2 +channel-type.nibeheatpump.f1x55-42028.label = AA23-BE5 Energy 1 +channel-type.nibeheatpump.f1x55-42030.label = AA23-BE5 EME20 Version +channel-type.nibeheatpump.f1x55-42033.label = PV Panel Heat Offset +channel-type.nibeheatpump.f1x55-42034.label = PV Panel Pool Offset +channel-type.nibeheatpump.f1x55-42035.label = AA23-BE5 EME20 Total Power +channel-type.nibeheatpump.f1x55-42037.label = AA23-BE5 EME20 Total Average Power +channel-type.nibeheatpump.f1x55-42075.label = AA23-BE5 EME20 Total Energy +channel-type.nibeheatpump.f1x55-42080.label = AA23-BE5 Alarm 504 +channel-type.nibeheatpump.f1x55-42081.label = AA23-BE5 Alarm 505 +channel-type.nibeheatpump.f1x55-42082.label = AA23-BE5 Alarm 506 +channel-type.nibeheatpump.f1x55-42083.label = AA23-BE5 Alarm 507 +channel-type.nibeheatpump.f1x55-42084.label = AA23-BE5 Alarm 508 +channel-type.nibeheatpump.f1x55-42085.label = AA23-BE5 Alarm 509 +channel-type.nibeheatpump.f1x55-42086.label = AA23-BE5 Alarm 510 +channel-type.nibeheatpump.f1x55-42087.label = AA23-BE5 Alarm 511 +channel-type.nibeheatpump.f1x55-42097.label = Ground Water Pump Auto Speed +channel-type.nibeheatpump.f1x55-42097.description = Ground water pump auto speed +channel-type.nibeheatpump.f1x55-42100.label = BT1 Average, 24h +channel-type.nibeheatpump.f1x55-42100.description = EB100-BT1 Outdoor temperature average, 24h +channel-type.nibeheatpump.f1x55-42101.label = Used Heating Power Average, 24h +channel-type.nibeheatpump.f1x55-42101.description = Used heating power average, 24h +channel-type.nibeheatpump.f1x55-42136.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f1x55-42137.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f1x55-42138.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f1x55-42139.label = AZ30-BT23 Outdoor Temp. ERS 4 +channel-type.nibeheatpump.f1x55-42140.label = AZ30-BT23 Outdoor Temp. ERS 3 +channel-type.nibeheatpump.f1x55-42141.label = AZ30-BT23 Outdoor Temp. ERS 2 +channel-type.nibeheatpump.f1x55-42150.label = External ERS 4 Accessory Relays +channel-type.nibeheatpump.f1x55-42150.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.f1x55-42151.label = External ERS 3 Accessory Relays +channel-type.nibeheatpump.f1x55-42151.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.f1x55-42152.label = External ERS 2 Accessory Relays +channel-type.nibeheatpump.f1x55-42152.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.f1x55-42153.label = External ERS 4 Accessory GQ2 Speed +channel-type.nibeheatpump.f1x55-42153.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42154.label = External ERS 3 Accessory GQ2 Speed +channel-type.nibeheatpump.f1x55-42154.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42155.label = External ERS 2 Accessory GQ2 Speed +channel-type.nibeheatpump.f1x55-42155.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42156.label = External ERS 4 Accessory GQ3 Speed +channel-type.nibeheatpump.f1x55-42156.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42157.label = External ERS 3 Accessory GQ3 Speed +channel-type.nibeheatpump.f1x55-42157.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42158.label = External ERS 2 Accessory GQ3 Speed +channel-type.nibeheatpump.f1x55-42158.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.f1x55-42159.label = External ERS 4 Accessory Block Status +channel-type.nibeheatpump.f1x55-42159.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.f1x55-42160.label = External ERS 3 Accessory Block Status +channel-type.nibeheatpump.f1x55-42160.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.f1x55-42161.label = External ERS 2 Accessory Block Status +channel-type.nibeheatpump.f1x55-42161.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.f1x55-42162.label = External ERS 4 Accessory EB17 +channel-type.nibeheatpump.f1x55-42162.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.f1x55-42162.state.option.0 = open. +channel-type.nibeheatpump.f1x55-42163.label = External ERS 3 Accessory EB17 +channel-type.nibeheatpump.f1x55-42163.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.f1x55-42163.state.option.0 = open. +channel-type.nibeheatpump.f1x55-42164.label = External ERS 2 Accessory EB17 +channel-type.nibeheatpump.f1x55-42164.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.f1x55-42164.state.option.0 = open. +channel-type.nibeheatpump.f1x55-42437.label = Heat Meter - HW Cpr and Add - Total System +channel-type.nibeheatpump.f1x55-42437.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42439.label = Heat Meter - Heat Cpr and Add - Total System +channel-type.nibeheatpump.f1x55-42439.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42441.label = Heat Meter - Cooling Cpr - Total System +channel-type.nibeheatpump.f1x55-42441.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42443.label = Heat Meter - Pool Cpr - Total System +channel-type.nibeheatpump.f1x55-42443.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42445.label = Heat Meter - HW Cpr - Total System +channel-type.nibeheatpump.f1x55-42445.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42447.label = Heat Meter - Heat Cpr - Total System +channel-type.nibeheatpump.f1x55-42447.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f1x55-42464.label = External ERS 4 Fire Place Guard +channel-type.nibeheatpump.f1x55-42465.label = External ERS 3 Fire Place Guard +channel-type.nibeheatpump.f1x55-42466.label = External ERS 2 Fire Place Guard +channel-type.nibeheatpump.f1x55-42467.label = External ERS 1 Fire Place Guard +channel-type.nibeheatpump.f1x55-42504.label = External Energy Meter Accumulated System +channel-type.nibeheatpump.f1x55-43001.label = Software Version +channel-type.nibeheatpump.f1x55-43005.label = Degree Minutes (16 Bit) +channel-type.nibeheatpump.f1x55-43005.description = Degree minutes, 16bit value (-32768 < x < 32767). Values outside valid values are rounded to the closest valid value. +channel-type.nibeheatpump.f1x55-43006.label = Calc. Supply S4 +channel-type.nibeheatpump.f1x55-43006.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-43007.label = Calc. Supply S3 +channel-type.nibeheatpump.f1x55-43007.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-43008.label = Calc. Supply S2 +channel-type.nibeheatpump.f1x55-43008.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-43009.label = Calc. Supply S1 +channel-type.nibeheatpump.f1x55-43009.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f1x55-43013.label = Freeze Protection Status +channel-type.nibeheatpump.f1x55-43013.description = 1 = Freeze protection active +channel-type.nibeheatpump.f1x55-43013.state.option.1 = Freeze protection active +channel-type.nibeheatpump.f1x55-43024.label = Status Cooling +channel-type.nibeheatpump.f1x55-43024.description = 0=Off 1=On +channel-type.nibeheatpump.f1x55-43024.state.option.0 = Off +channel-type.nibeheatpump.f1x55-43024.state.option.1 = On +channel-type.nibeheatpump.f1x55-43064.label = Heat Medium Flow DT Set Point +channel-type.nibeheatpump.f1x55-43064.description = Set point delta T for the heat medium flow +channel-type.nibeheatpump.f1x55-43065.label = Heat Medium Flow DT Actual +channel-type.nibeheatpump.f1x55-43065.description = Current value of the delta T for the heat medium flow +channel-type.nibeheatpump.f1x55-43081.label = Tot. Op.time Add. +channel-type.nibeheatpump.f1x55-43081.description = Total electric additive operation time +channel-type.nibeheatpump.f1x55-43084.label = Int. El.add. Power +channel-type.nibeheatpump.f1x55-43084.description = Current power from the internal electrical addition +channel-type.nibeheatpump.f1x55-43086.label = Prio +channel-type.nibeheatpump.f1x55-43086.description = Indicates what heating action (HW/heat/pool) currently prioritised 10=Off 20=Hot Water 30=Heat 40=Pool 41=Pool 2 50=Transfer 60=Cooling +channel-type.nibeheatpump.f1x55-43086.state.option.10 = Off +channel-type.nibeheatpump.f1x55-43086.state.option.20 = Hot Water +channel-type.nibeheatpump.f1x55-43086.state.option.30 = Heat +channel-type.nibeheatpump.f1x55-43086.state.option.40 = Pool +channel-type.nibeheatpump.f1x55-43086.state.option.41 = Pool 2 +channel-type.nibeheatpump.f1x55-43086.state.option.50 = Transfer +channel-type.nibeheatpump.f1x55-43086.state.option.60 = Cooling +channel-type.nibeheatpump.f1x55-43091.label = Int. El.add. State +channel-type.nibeheatpump.f1x55-43091.description = Number of steps active for internal step-controlled addition +channel-type.nibeheatpump.f1x55-43093.label = Mixing Valve State S4 +channel-type.nibeheatpump.f1x55-43093.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-43094.label = Mixing Valve State S3 +channel-type.nibeheatpump.f1x55-43094.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-43095.label = Mixing Valve State S2 +channel-type.nibeheatpump.f1x55-43095.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-43096.label = Mixing Valve State S1 +channel-type.nibeheatpump.f1x55-43096.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f1x55-43097.label = Status of the Shunt Controlled Additional Heat Accessory +channel-type.nibeheatpump.f1x55-43097.description = 10 = Off, 20 = Running, 30 = Passive +channel-type.nibeheatpump.f1x55-43097.state.option.10 = Off +channel-type.nibeheatpump.f1x55-43097.state.option.20 = Running +channel-type.nibeheatpump.f1x55-43097.state.option.30 = Passive +channel-type.nibeheatpump.f1x55-43103.label = HPAC State +channel-type.nibeheatpump.f1x55-43103.description = State of the HPAC cooling accessory. +channel-type.nibeheatpump.f1x55-43108.label = Fan Speed Current +channel-type.nibeheatpump.f1x55-43108.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f1x55-43122.label = Compr. Current Min.freq. +channel-type.nibeheatpump.f1x55-43122.description = The current minimum frequency of the compressor +channel-type.nibeheatpump.f1x55-43123.label = Compr. Current Max.freq. +channel-type.nibeheatpump.f1x55-43123.description = The current maximum frequency of the compressor +channel-type.nibeheatpump.f1x55-43132.label = Inverter Com. Timer +channel-type.nibeheatpump.f1x55-43132.description = This value shows the time since last communication with the inverter +channel-type.nibeheatpump.f1x55-43136.label = Compressor Frequency, Actual +channel-type.nibeheatpump.f1x55-43136.description = The compressor frequency the compressor is currently running at +channel-type.nibeheatpump.f1x55-43140.label = Inverter Temperature +channel-type.nibeheatpump.f1x55-43140.description = Current inverter temparture +channel-type.nibeheatpump.f1x55-43141.label = Compr. in Power +channel-type.nibeheatpump.f1x55-43141.description = The power delivered from the inverter to the compressor +channel-type.nibeheatpump.f1x55-43147.label = Compr. in Current +channel-type.nibeheatpump.f1x55-43147.description = The current delivered from the inverter to the compressor +channel-type.nibeheatpump.f1x55-43152.label = Internal Cooling Blocked +channel-type.nibeheatpump.f1x55-43158.label = External Adjustment Activated Via Input S4 +channel-type.nibeheatpump.f1x55-43159.label = External Adjustment Activated Via Input S3 +channel-type.nibeheatpump.f1x55-43160.label = External Adjustment Activated Via Input S2 +channel-type.nibeheatpump.f1x55-43161.label = External Adjustment Activated Via Input S1 +channel-type.nibeheatpump.f1x55-43163.label = Blocking Status of the Shunt Controlled Add Heat Acc +channel-type.nibeheatpump.f1x55-43163.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.f1x55-43163.state.option.0 = Unblocked +channel-type.nibeheatpump.f1x55-43163.state.option.1 = Blocked +channel-type.nibeheatpump.f1x55-43164.label = Cooling Blocked +channel-type.nibeheatpump.f1x55-43164.description = Whether cooling is blocked +channel-type.nibeheatpump.f1x55-43171.label = Blocking Status of the Step Controlled Add Heat Acc +channel-type.nibeheatpump.f1x55-43171.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.f1x55-43171.state.option.0 = Unblocked +channel-type.nibeheatpump.f1x55-43171.state.option.1 = Blocked +channel-type.nibeheatpump.f1x55-43180.label = HWC Pump Status GP11 +channel-type.nibeheatpump.f1x55-43180.description = Hot water circulation pump status. 1=on, 0=off +channel-type.nibeheatpump.f1x55-43180.state.option.1 = on +channel-type.nibeheatpump.f1x55-43180.state.option.0 = off +channel-type.nibeheatpump.f1x55-43182.label = Compressor Frequency, Target +channel-type.nibeheatpump.f1x55-43182.description = The targeted compressor frequency, before excluding any blocked frequencies +channel-type.nibeheatpump.f1x55-43239.label = Tot. HW Op.time Add. +channel-type.nibeheatpump.f1x55-43239.description = Total electric additive operation time in hot water mode +channel-type.nibeheatpump.f1x55-43375.label = Compr. in Power Mean +channel-type.nibeheatpump.f1x55-43375.description = Mean power delivered from the inverter to the compressor. Mean is calculated every 10 seconds. +channel-type.nibeheatpump.f1x55-43395.label = HPAC Relays +channel-type.nibeheatpump.f1x55-43395.description = Indicates the active relays on the HPAC accessory. The information is binary encoded +channel-type.nibeheatpump.f1x55-43416.label = Compressor Starts EB100-EP14 +channel-type.nibeheatpump.f1x55-43416.description = Number of compressorer starts +channel-type.nibeheatpump.f1x55-43420.label = Tot. Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f1x55-43420.description = Total compressorer operation time +channel-type.nibeheatpump.f1x55-43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f1x55-43424.description = Total compressorer operation time in hot water mode +channel-type.nibeheatpump.f1x55-43427.label = Compressor State EP14 +channel-type.nibeheatpump.f1x55-43427.description = 20 = Stopped, 40 = Starting, 60 = Running, 100 = Stopping +channel-type.nibeheatpump.f1x55-43427.state.option.20 = Stopped +channel-type.nibeheatpump.f1x55-43427.state.option.40 = Starting +channel-type.nibeheatpump.f1x55-43427.state.option.60 = Running +channel-type.nibeheatpump.f1x55-43427.state.option.100 = Stopping +channel-type.nibeheatpump.f1x55-43431.label = Supply Pump State EP14 +channel-type.nibeheatpump.f1x55-43431.description = 10=off,15=starting,20=on,40=10-day mode,80=calibration +channel-type.nibeheatpump.f1x55-43431.state.option.10 = off +channel-type.nibeheatpump.f1x55-43431.state.option.15 = starting +channel-type.nibeheatpump.f1x55-43431.state.option.20 = on +channel-type.nibeheatpump.f1x55-43431.state.option.40 = 10-day mode +channel-type.nibeheatpump.f1x55-43431.state.option.80 = calibration +channel-type.nibeheatpump.f1x55-43433.label = Brine Pump State EP14 +channel-type.nibeheatpump.f1x55-43433.description = 10=off,15=starting,20=on,40=10-day mode,80=calibration +channel-type.nibeheatpump.f1x55-43433.state.option.10 = off +channel-type.nibeheatpump.f1x55-43433.state.option.15 = starting +channel-type.nibeheatpump.f1x55-43433.state.option.20 = on +channel-type.nibeheatpump.f1x55-43433.state.option.40 = 10-day mode +channel-type.nibeheatpump.f1x55-43433.state.option.80 = calibration +channel-type.nibeheatpump.f1x55-43435.label = Cpr Status EP14 +channel-type.nibeheatpump.f1x55-43435.description = Status of the compressor. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.f1x55-43435.state.option.1 = on +channel-type.nibeheatpump.f1x55-43435.state.option.0 = off +channel-type.nibeheatpump.f1x55-43435.state.option.0 = Off +channel-type.nibeheatpump.f1x55-43435.state.option.1 = On +channel-type.nibeheatpump.f1x55-43437.label = Supply Pump Speed EP14 +channel-type.nibeheatpump.f1x55-43437.description = Supply pump speed in % +channel-type.nibeheatpump.f1x55-43439.label = EP14-GP2 Brine Pump Status EP14 +channel-type.nibeheatpump.f1x55-43439.description = Brine pump speed in % +channel-type.nibeheatpump.f1x55-43484.label = FLM 4 Cooling Status +channel-type.nibeheatpump.f1x55-43484.description = Whether FLM cooling is active, 1=yes, 0=no +channel-type.nibeheatpump.f1x55-43484.state.option.1 = yes +channel-type.nibeheatpump.f1x55-43484.state.option.0 = no +channel-type.nibeheatpump.f1x55-43485.label = FLM 3 Cooling Status +channel-type.nibeheatpump.f1x55-43485.description = Whether FLM cooling is active, 1=yes, 0=no +channel-type.nibeheatpump.f1x55-43485.state.option.1 = yes +channel-type.nibeheatpump.f1x55-43485.state.option.0 = no +channel-type.nibeheatpump.f1x55-43486.label = FLM 2 Cooling Status +channel-type.nibeheatpump.f1x55-43486.description = Whether FLM cooling is active, 1=yes, 0=no +channel-type.nibeheatpump.f1x55-43486.state.option.1 = yes +channel-type.nibeheatpump.f1x55-43486.state.option.0 = no +channel-type.nibeheatpump.f1x55-43487.label = FLM 1 Cooling Status +channel-type.nibeheatpump.f1x55-43487.description = Whether FLM cooling is active, 1=yes, 0=no +channel-type.nibeheatpump.f1x55-43487.state.option.1 = yes +channel-type.nibeheatpump.f1x55-43487.state.option.0 = no +channel-type.nibeheatpump.f1x55-43514.label = EB100-EP14 PCA Base Relays +channel-type.nibeheatpump.f1x55-43514.description = Indicates active relays on the PCA Base card. Please refer to the wiring diagram for relay description. Binary encoded. 1=on, 0=off. Bit0=K4,Bit1=K3,Bit2=K2,Bit3=K1 +channel-type.nibeheatpump.f1x55-43514.state.option.1 = on +channel-type.nibeheatpump.f1x55-43514.state.option.0 = off. Bit0 K4 Bit1 K3 Bit2 K2 Bit3 K1 +channel-type.nibeheatpump.f1x55-43516.label = PCA-Power Relays EP14 +channel-type.nibeheatpump.f1x55-43516.description = Indicates the active relays on the PCA-Power card. The information is binary encoded +channel-type.nibeheatpump.f1x55-43542.label = Calculated Supply Air Temp. +channel-type.nibeheatpump.f1x55-43555.label = HW Comfort Shunt State +channel-type.nibeheatpump.f1x55-43555.description = 10=shunt off,20=shunt open,30=shunt closed +channel-type.nibeheatpump.f1x55-43555.state.option.10 = shunt off +channel-type.nibeheatpump.f1x55-43555.state.option.20 = shunt open +channel-type.nibeheatpump.f1x55-43555.state.option.30 = shunt closed +channel-type.nibeheatpump.f1x55-43556.label = HW Comfort Add Status +channel-type.nibeheatpump.f1x55-43556.description = 1=on,0=off +channel-type.nibeheatpump.f1x55-43556.state.option.1 = on +channel-type.nibeheatpump.f1x55-43556.state.option.0 = off +channel-type.nibeheatpump.f1x55-43560.label = Pool 2 Blocked +channel-type.nibeheatpump.f1x55-43561.label = Pool 1 Blocked +channel-type.nibeheatpump.f1x55-43563.label = GP9 Pool 2 Valve +channel-type.nibeheatpump.f1x55-43564.label = GP9 Pool 1 Valve +channel-type.nibeheatpump.f1x55-44266.label = Cool Degree Minutes +channel-type.nibeheatpump.f1x55-44267.label = Calc. Cooling Supply S4 +channel-type.nibeheatpump.f1x55-44267.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-44268.label = Calc. Cooling Supply S3 +channel-type.nibeheatpump.f1x55-44268.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-44269.label = Calc. Cooling Supply S2 +channel-type.nibeheatpump.f1x55-44269.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-44270.label = Calc. Cooling Supply S1 +channel-type.nibeheatpump.f1x55-44270.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.f1x55-44276.label = State ACS +channel-type.nibeheatpump.f1x55-44276.description = The state of the ACS accessory +channel-type.nibeheatpump.f1x55-44277.label = EQ1-QN25 State ACS Heat Dump +channel-type.nibeheatpump.f1x55-44277.description = 10=shunt off,20=shunt open,30=shunt closed +channel-type.nibeheatpump.f1x55-44277.state.option.10 = shunt off +channel-type.nibeheatpump.f1x55-44277.state.option.20 = shunt open +channel-type.nibeheatpump.f1x55-44277.state.option.30 = shunt closed +channel-type.nibeheatpump.f1x55-44278.label = EQ1-QN18 State ACS Cool Dump +channel-type.nibeheatpump.f1x55-44278.description = 10=shunt off,20=shunt open,30=shunt closed +channel-type.nibeheatpump.f1x55-44278.state.option.10 = shunt off +channel-type.nibeheatpump.f1x55-44278.state.option.20 = shunt open +channel-type.nibeheatpump.f1x55-44278.state.option.30 = shunt closed +channel-type.nibeheatpump.f1x55-44298.label = Heat Meter - HW Cpr and Add EP14 +channel-type.nibeheatpump.f1x55-44298.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44300.label = Heat Meter - Heat Cpr and Add EP14 +channel-type.nibeheatpump.f1x55-44300.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44302.label = Heat Meter - Cooling Cpr EP14 +channel-type.nibeheatpump.f1x55-44302.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44304.label = Heat Meter - Pool Cpr EP14 +channel-type.nibeheatpump.f1x55-44304.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44306.label = Heat Meter - HW Cpr EP14 +channel-type.nibeheatpump.f1x55-44306.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44308.label = Heat Meter - Heat Cpr EP14 +channel-type.nibeheatpump.f1x55-44308.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f1x55-44331.label = Software Release +channel-type.nibeheatpump.f1x55-44744.label = Extra Heating System Pump S4 +channel-type.nibeheatpump.f1x55-44745.label = Extra Heating System Pump S3 +channel-type.nibeheatpump.f1x55-44746.label = Extra Heating System Pump S2 +channel-type.nibeheatpump.f1x55-44748.label = Pool 2 Pump Status +channel-type.nibeheatpump.f1x55-44748.description = 1=on,0=off +channel-type.nibeheatpump.f1x55-44748.state.option.1 = on +channel-type.nibeheatpump.f1x55-44748.state.option.0 = off +channel-type.nibeheatpump.f1x55-44749.label = Pool 1 Pump Status +channel-type.nibeheatpump.f1x55-44749.description = 1=on,0=off +channel-type.nibeheatpump.f1x55-44749.state.option.1 = on +channel-type.nibeheatpump.f1x55-44749.state.option.0 = off +channel-type.nibeheatpump.f1x55-44751.label = EQ1-QN12 ACS Valve +channel-type.nibeheatpump.f1x55-44751.description = ACS valve is 1=open,0=closed +channel-type.nibeheatpump.f1x55-44751.state.option.1 = open +channel-type.nibeheatpump.f1x55-44751.state.option.0 = closed +channel-type.nibeheatpump.f1x55-44752.label = EQ1-GP20 ACS Dump Signal +channel-type.nibeheatpump.f1x55-44752.description = GP20 is 1=running,0=off +channel-type.nibeheatpump.f1x55-44752.state.option.1 = running +channel-type.nibeheatpump.f1x55-44752.state.option.0 = off +channel-type.nibeheatpump.f1x55-44753.label = Passive Cool Shunt +channel-type.nibeheatpump.f1x55-44754.label = GP13 Passive Cool Pool +channel-type.nibeheatpump.f1x55-44756.label = State Ground Water Pump +channel-type.nibeheatpump.f1x55-44874.label = State SG Ready +channel-type.nibeheatpump.f1x55-44878.label = SG Ready Input A +channel-type.nibeheatpump.f1x55-44879.label = SG Ready Input B +channel-type.nibeheatpump.f1x55-44896.label = Smart Price Adaption Heating Offset +channel-type.nibeheatpump.f1x55-44897.label = Smart Price Adaption HW Comfort Mode +channel-type.nibeheatpump.f1x55-44897.description = 0=Eco,1=Normal,2=Luxury,10=Normal+,20=Mini +channel-type.nibeheatpump.f1x55-44897.state.option.0 = Eco +channel-type.nibeheatpump.f1x55-44897.state.option.1 = Normal +channel-type.nibeheatpump.f1x55-44897.state.option.2 = Luxury +channel-type.nibeheatpump.f1x55-44897.state.option.10 = Normal+ +channel-type.nibeheatpump.f1x55-44897.state.option.20 = Mini +channel-type.nibeheatpump.f1x55-44898.label = Smart Price Adaption Pool Offset +channel-type.nibeheatpump.f1x55-44899.label = Smart Price Adaption Cool Offset +channel-type.nibeheatpump.f1x55-44908.label = State Smart Price Adaption +channel-type.nibeheatpump.f1x55-44910.label = Brine Pump DT Actual +channel-type.nibeheatpump.f1x55-44910.description = Current value between set and act value on brine pumps +channel-type.nibeheatpump.f1x55-44911.label = Brine Pump DT Set Point +channel-type.nibeheatpump.f1x55-44911.description = Set point delta T for the brine pumps +channel-type.nibeheatpump.f1x55-45001.label = Alarm +channel-type.nibeheatpump.f1x55-45001.description = Indicates the alarm number of the most severe current alarm +channel-type.nibeheatpump.f1x55-45171.label = Alarm Reset +channel-type.nibeheatpump.f1x55-45171.description = Reset alarm by setting value 1 +channel-type.nibeheatpump.f1x55-47004.label = Heat Curve S4 +channel-type.nibeheatpump.f1x55-47004.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47005.label = Heat Curve S3 +channel-type.nibeheatpump.f1x55-47005.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47006.label = Heat Curve S2 +channel-type.nibeheatpump.f1x55-47006.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47007.label = Heat Curve S1 +channel-type.nibeheatpump.f1x55-47007.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47008.label = Heat Offset S4 +channel-type.nibeheatpump.f1x55-47008.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47009.label = Heat Offset S3 +channel-type.nibeheatpump.f1x55-47009.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47010.label = Heat Offset S2 +channel-type.nibeheatpump.f1x55-47010.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47011.label = Heat Offset S1 +channel-type.nibeheatpump.f1x55-47011.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47012.label = Min Supply System 4 +channel-type.nibeheatpump.f1x55-47013.label = Min Supply System 3 +channel-type.nibeheatpump.f1x55-47014.label = Min Supply System 2 +channel-type.nibeheatpump.f1x55-47015.label = Min Supply System 1 +channel-type.nibeheatpump.f1x55-47016.label = Max Supply System 4 +channel-type.nibeheatpump.f1x55-47017.label = Max Supply System 3 +channel-type.nibeheatpump.f1x55-47018.label = Max Supply System 2 +channel-type.nibeheatpump.f1x55-47019.label = Max Supply System 1 +channel-type.nibeheatpump.f1x55-47020.label = Own Heating Curve P7 +channel-type.nibeheatpump.f1x55-47020.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47021.label = Own Heating Curve P6 +channel-type.nibeheatpump.f1x55-47021.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47022.label = Own Heating Curve P5 +channel-type.nibeheatpump.f1x55-47022.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47023.label = Own Heating Curve P4 +channel-type.nibeheatpump.f1x55-47023.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47024.label = Own Heating Curve P3 +channel-type.nibeheatpump.f1x55-47024.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47025.label = Own Heating Curve P2 +channel-type.nibeheatpump.f1x55-47025.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47026.label = Own Heating Curve P1 +channel-type.nibeheatpump.f1x55-47026.description = User defined heating curve point +channel-type.nibeheatpump.f1x55-47027.label = Point Offset Outdoor Temp. +channel-type.nibeheatpump.f1x55-47027.description = Outdoor temperature point where the heat curve is offset +channel-type.nibeheatpump.f1x55-47028.label = Point Offset +channel-type.nibeheatpump.f1x55-47028.description = Amount of offset at the point offset temperature +channel-type.nibeheatpump.f1x55-47029.label = External Adjustment S4 +channel-type.nibeheatpump.f1x55-47029.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47030.label = External Adjustment S3 +channel-type.nibeheatpump.f1x55-47030.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47031.label = External Adjustment S2 +channel-type.nibeheatpump.f1x55-47031.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47032.label = External Adjustment S1 +channel-type.nibeheatpump.f1x55-47032.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47033.label = External Adjustment with Room Sensor S4 +channel-type.nibeheatpump.f1x55-47033.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47034.label = External Adjustment with Room Sensor S3 +channel-type.nibeheatpump.f1x55-47034.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47035.label = External Adjustment with Room Sensor S2 +channel-type.nibeheatpump.f1x55-47035.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47036.label = External Adjustment with Room Sensor S1 +channel-type.nibeheatpump.f1x55-47036.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-47041.label = Hot Water Comfort Mode +channel-type.nibeheatpump.f1x55-47041.description = Setting in menu 2.2. 0=Economy,1=Normal,2=Luxury,4=Smart Control 0=Economy 1=Normal 2=Luxury +channel-type.nibeheatpump.f1x55-47041.state.option.0 = Economy +channel-type.nibeheatpump.f1x55-47041.state.option.1 = Normal +channel-type.nibeheatpump.f1x55-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f1x55-47041.state.option.4 = Smart Control +channel-type.nibeheatpump.f1x55-47043.label = Start Temperature HW Luxury +channel-type.nibeheatpump.f1x55-47043.description = Start temperature for heating water +channel-type.nibeheatpump.f1x55-47044.label = Start Temperature HW Normal +channel-type.nibeheatpump.f1x55-47044.description = Start temperature for heating water +channel-type.nibeheatpump.f1x55-47045.label = Start Temperature HW Economy +channel-type.nibeheatpump.f1x55-47045.description = Start temperature for heating water +channel-type.nibeheatpump.f1x55-47046.label = Stop Temperature Periodic HW +channel-type.nibeheatpump.f1x55-47046.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x55-47047.label = Stop Temperature HW Luxury +channel-type.nibeheatpump.f1x55-47047.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x55-47048.label = Stop Temperature HW Normal +channel-type.nibeheatpump.f1x55-47048.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x55-47049.label = Stop Temperature HW Economy +channel-type.nibeheatpump.f1x55-47049.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f1x55-47050.label = Periodic HW +channel-type.nibeheatpump.f1x55-47050.description = Activates the periodic hot water generation +channel-type.nibeheatpump.f1x55-47051.label = Periodic HW Interval +channel-type.nibeheatpump.f1x55-47051.description = Interval between Periodic hot water sessions +channel-type.nibeheatpump.f1x55-47054.label = Run Time HWC +channel-type.nibeheatpump.f1x55-47054.description = Run time for the hot water circulation system +channel-type.nibeheatpump.f1x55-47055.label = Still Time HWC +channel-type.nibeheatpump.f1x55-47055.description = Still time for the hot water circulation system +channel-type.nibeheatpump.f1x55-47099.label = GMz +channel-type.nibeheatpump.f1x55-47099.description = Compressor frequency regulator GMz +channel-type.nibeheatpump.f1x55-47100.label = Max Diff VBF-BerVBF +channel-type.nibeheatpump.f1x55-47100.description = Largest allowed difference between Supply and calc supply +channel-type.nibeheatpump.f1x55-47101.label = Comp Freq Reg P +channel-type.nibeheatpump.f1x55-47101.description = Compressor frequency regulator P +channel-type.nibeheatpump.f1x55-47102.label = Comp Freq Max Delta F +channel-type.nibeheatpump.f1x55-47102.description = Maximum change of copmpressor frequency in compressor frequency regulator +channel-type.nibeheatpump.f1x55-47103.label = Min Comp Freq +channel-type.nibeheatpump.f1x55-47103.description = Minimum allowed compressor frequency +channel-type.nibeheatpump.f1x55-47104.label = Max Comp Freq +channel-type.nibeheatpump.f1x55-47104.description = Maximum allowed compressor frequency +channel-type.nibeheatpump.f1x55-47131.label = Language +channel-type.nibeheatpump.f1x55-47131.description = Display language in the heat pump 0=English 1=Svenska 2=Deutsch 3=Francais 4=Espanol 5=Suomi 6=Lietuviu 7=Cesky 8=Polski 9=Nederlands 10=Norsk 11=Dansk 12=Eesti 13=Latviesu 16=Magyar +channel-type.nibeheatpump.f1x55-47131.state.option.0 = English +channel-type.nibeheatpump.f1x55-47131.state.option.1 = Svenska +channel-type.nibeheatpump.f1x55-47131.state.option.2 = Deutsch +channel-type.nibeheatpump.f1x55-47131.state.option.3 = Francais +channel-type.nibeheatpump.f1x55-47131.state.option.4 = Espanol +channel-type.nibeheatpump.f1x55-47131.state.option.5 = Suomi +channel-type.nibeheatpump.f1x55-47131.state.option.6 = Lietuviu +channel-type.nibeheatpump.f1x55-47131.state.option.7 = Cesky +channel-type.nibeheatpump.f1x55-47131.state.option.8 = Polski +channel-type.nibeheatpump.f1x55-47131.state.option.9 = Nederlands +channel-type.nibeheatpump.f1x55-47131.state.option.10 = Norsk +channel-type.nibeheatpump.f1x55-47131.state.option.11 = Dansk +channel-type.nibeheatpump.f1x55-47131.state.option.12 = Eesti +channel-type.nibeheatpump.f1x55-47131.state.option.13 = Latviesu +channel-type.nibeheatpump.f1x55-47131.state.option.16 = Magyar +channel-type.nibeheatpump.f1x55-47134.label = Period HW +channel-type.nibeheatpump.f1x55-47135.label = Period Heat +channel-type.nibeheatpump.f1x55-47136.label = Period Pool +channel-type.nibeheatpump.f1x55-47137.label = Operational Mode +channel-type.nibeheatpump.f1x55-47137.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.f1x55-47137.state.option.0 = Auto +channel-type.nibeheatpump.f1x55-47137.state.option.1 = Manual +channel-type.nibeheatpump.f1x55-47137.state.option.2 = Add. heat only +channel-type.nibeheatpump.f1x55-47138.label = Operational Mode Heat Medium Pump +channel-type.nibeheatpump.f1x55-47138.description = 10=Intermittent 20=Continous 30=Economy 40=Auto +channel-type.nibeheatpump.f1x55-47138.state.option.10 = Intermittent +channel-type.nibeheatpump.f1x55-47138.state.option.20 = Continous +channel-type.nibeheatpump.f1x55-47138.state.option.30 = Economy +channel-type.nibeheatpump.f1x55-47138.state.option.40 = Auto +channel-type.nibeheatpump.f1x55-47139.label = Operational Mode Brine Medium Pump +channel-type.nibeheatpump.f1x55-47139.description = 10=Intermittent 20=Continuous 30=Economy 40=Auto +channel-type.nibeheatpump.f1x55-47139.state.option.10 = Intermittent +channel-type.nibeheatpump.f1x55-47139.state.option.20 = Continuous +channel-type.nibeheatpump.f1x55-47139.state.option.30 = Economy +channel-type.nibeheatpump.f1x55-47139.state.option.40 = Auto +channel-type.nibeheatpump.f1x55-47206.label = DM Start Heating +channel-type.nibeheatpump.f1x55-47206.description = The value the degree minutes needed to be reached for the pump to start heating +channel-type.nibeheatpump.f1x55-47209.label = DM Between Add. Steps +channel-type.nibeheatpump.f1x55-47209.description = The number of degree minutes between start of each electric addition step +channel-type.nibeheatpump.f1x55-47210.label = DM Start Add. with Shunt +channel-type.nibeheatpump.f1x55-47212.label = Max Int Add. Power +channel-type.nibeheatpump.f1x55-47214.label = Fuse +channel-type.nibeheatpump.f1x55-47214.description = Size of the fuse that the HP is connected to +channel-type.nibeheatpump.f1x55-47261.label = Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x55-47262.label = Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x55-47263.label = Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x55-47264.label = Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x55-47265.label = Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x55-47271.label = Fan Return Time 4 +channel-type.nibeheatpump.f1x55-47271.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x55-47272.label = Fan Return Time 3 +channel-type.nibeheatpump.f1x55-47272.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x55-47273.label = Fan Return Time 2 +channel-type.nibeheatpump.f1x55-47273.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x55-47274.label = Fan Return Time 1 +channel-type.nibeheatpump.f1x55-47274.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f1x55-47275.label = Filter Reminder Period +channel-type.nibeheatpump.f1x55-47275.description = Time between the reminder of filter replacement/cleaning. +channel-type.nibeheatpump.f1x55-47276.label = Floor Drying +channel-type.nibeheatpump.f1x55-47276.description = 0=Off 1=On +channel-type.nibeheatpump.f1x55-47277.label = Floor Drying Period 7 +channel-type.nibeheatpump.f1x55-47277.description = Days each period is active +channel-type.nibeheatpump.f1x55-47278.label = Floor Drying Period 6 +channel-type.nibeheatpump.f1x55-47278.description = Days each period is active +channel-type.nibeheatpump.f1x55-47279.label = Floor Drying Period 5 +channel-type.nibeheatpump.f1x55-47279.description = Days each period is active +channel-type.nibeheatpump.f1x55-47280.label = Floor Drying Period 4 +channel-type.nibeheatpump.f1x55-47280.description = Days each period is active +channel-type.nibeheatpump.f1x55-47281.label = Floor Drying Period 3 +channel-type.nibeheatpump.f1x55-47281.description = Days each period is active +channel-type.nibeheatpump.f1x55-47282.label = Floor Drying Period 2 +channel-type.nibeheatpump.f1x55-47282.description = Days each period is active +channel-type.nibeheatpump.f1x55-47283.label = Floor Drying Period 1 +channel-type.nibeheatpump.f1x55-47283.description = Days each period is active +channel-type.nibeheatpump.f1x55-47284.label = Floor Drying Temp. 7 +channel-type.nibeheatpump.f1x55-47284.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47285.label = Floor Drying Temp. 6 +channel-type.nibeheatpump.f1x55-47285.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47286.label = Floor Drying Temp. 5 +channel-type.nibeheatpump.f1x55-47286.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47287.label = Floor Drying Temp. 4 +channel-type.nibeheatpump.f1x55-47287.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47288.label = Floor Drying Temp. 3 +channel-type.nibeheatpump.f1x55-47288.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47289.label = Floor Drying Temp. 2 +channel-type.nibeheatpump.f1x55-47289.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47290.label = Floor Drying Temp. 1 +channel-type.nibeheatpump.f1x55-47290.description = Supply temperature each period +channel-type.nibeheatpump.f1x55-47291.label = Floor Drying Timer +channel-type.nibeheatpump.f1x55-47300.label = DOT +channel-type.nibeheatpump.f1x55-47300.description = Dimensioning outdoor temperature +channel-type.nibeheatpump.f1x55-47301.label = Delta T At DOT +channel-type.nibeheatpump.f1x55-47301.description = Delta T (BT12-BT3)at dimensioning outdoor temperature +channel-type.nibeheatpump.f1x55-47302.label = Climate System 2 Accessory +channel-type.nibeheatpump.f1x55-47302.description = Activates the climate system 2 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47303.label = Climate System 3 Accessory +channel-type.nibeheatpump.f1x55-47303.description = Activates the climate system 3 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47304.label = Climate System 4 Accessory +channel-type.nibeheatpump.f1x55-47304.description = Activates the climate system 4 accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47305.label = Climate System 4 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-47305.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-47306.label = Climate System 3 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-47306.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-47307.label = Climate System 2 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-47307.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-47308.label = Climate System 4 Shunt Wait +channel-type.nibeheatpump.f1x55-47308.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-47309.label = Climate System 3 Shunt Wait +channel-type.nibeheatpump.f1x55-47309.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-47310.label = Climate System 2 Shunt Wait +channel-type.nibeheatpump.f1x55-47310.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-47312.label = FLM Pump 1 +channel-type.nibeheatpump.f1x55-47312.description = Operating mode for the FLM pump 1|Operating mode for the FLM pump 2|Operating mode for the FLM pump 3|Operating mode for the FLM pump 4 0=Off 1=On +channel-type.nibeheatpump.f1x55-47313.label = FLM 1 Defrost +channel-type.nibeheatpump.f1x55-47313.description = Minimum time between defrost in FLM 1|Minimum time between defrost in FLM 2|Minimum time between defrost in FLM 3|Minimum time between defrost in FLM 4 +channel-type.nibeheatpump.f1x55-47317.label = Shunt Controlled Add. Accessory +channel-type.nibeheatpump.f1x55-47317.description = Activates the shunt controlled addition accessory. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.f1x55-47318.label = Shunt Controlled Add. Min. Temp. +channel-type.nibeheatpump.f1x55-47319.label = Shunt Controlled Add. Min. Runtime +channel-type.nibeheatpump.f1x55-47320.label = Shunt Controlled Add. Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-47320.description = Mixing valve amplification for shunt controlled add. +channel-type.nibeheatpump.f1x55-47321.label = Shunt Controlled Add. Mixing Valve Wait +channel-type.nibeheatpump.f1x55-47321.description = Wait time between changes of the shunt in shunt controlled add. +channel-type.nibeheatpump.f1x55-47322.label = Step Controlled Add. Accessory +channel-type.nibeheatpump.f1x55-47322.description = Activates the step controlled addition accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47324.label = Step Controlled Add. Diff. DM +channel-type.nibeheatpump.f1x55-47324.description = Difference in DM of each step in the step controlled add. +channel-type.nibeheatpump.f1x55-47325.label = Step Controlled Add. Max. Step +channel-type.nibeheatpump.f1x55-47325.description = Maximum number of steps allowed in step controlled add. +channel-type.nibeheatpump.f1x55-47326.label = Step Controlled Add. Mode +channel-type.nibeheatpump.f1x55-47326.description = Binary or linear stepping method. 0=Linear 1=Binary +channel-type.nibeheatpump.f1x55-47327.label = Ground Water Pump Accessory +channel-type.nibeheatpump.f1x55-47327.description = Ground water pump using AXC40 0=Off 1=On +channel-type.nibeheatpump.f1x55-47329.label = Cooling 2-pipe Accessory +channel-type.nibeheatpump.f1x55-47329.description = Activates the 2-pipe cooling accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47330.label = Cooling 4-pipe Accessory +channel-type.nibeheatpump.f1x55-47330.description = Activates the 4-pipe cooling accessory 0=Off 1=On +channel-type.nibeheatpump.f1x55-47335.label = Time Betw. Switch Heat/cool +channel-type.nibeheatpump.f1x55-47335.description = Time between switching from heating to cooling or vice versa. +channel-type.nibeheatpump.f1x55-47336.label = Heat At Room Under Temp. +channel-type.nibeheatpump.f1x55-47336.description = This value indicates how many degrees under set room temp heating will be allowed +channel-type.nibeheatpump.f1x55-47337.label = Cool At Room over Temp. +channel-type.nibeheatpump.f1x55-47337.description = This value indicates how many degrees over set room temp cooling will be allowed +channel-type.nibeheatpump.f1x55-47338.label = Cooling Mix. Valve Amp. +channel-type.nibeheatpump.f1x55-47338.description = Mixing valve amplification for the cooling valve +channel-type.nibeheatpump.f1x55-47339.label = Cooling Mix. Valve Step Delay +channel-type.nibeheatpump.f1x55-47340.label = Cooling with Room Sensor +channel-type.nibeheatpump.f1x55-47340.description = Enables use of room sensor together with cooling 0=Off 1=On +channel-type.nibeheatpump.f1x55-47340.state.option.0 = Off +channel-type.nibeheatpump.f1x55-47340.state.option.1 = On +channel-type.nibeheatpump.f1x55-47341.label = HPAC Accessory +channel-type.nibeheatpump.f1x55-47341.description = Activates the HPAC accessory +channel-type.nibeheatpump.f1x55-47342.label = Start Passive Cooling DM +channel-type.nibeheatpump.f1x55-47342.description = Value the degree minutes have to reach to start passive cooling +channel-type.nibeheatpump.f1x55-47343.label = Start Active Cooling DM +channel-type.nibeheatpump.f1x55-47343.description = Value the degree minutes have to reach to start active cooling +channel-type.nibeheatpump.f1x55-47352.label = SMS40 Accessory +channel-type.nibeheatpump.f1x55-47352.description = Activates the SMS40 accessory +channel-type.nibeheatpump.f1x55-47365.label = RMU System 1 +channel-type.nibeheatpump.f1x55-47365.description = Activates the RMU accessory for system 1 +channel-type.nibeheatpump.f1x55-47366.label = RMU System 2 +channel-type.nibeheatpump.f1x55-47366.description = Activates the RMU accessory for system 2 +channel-type.nibeheatpump.f1x55-47367.label = RMU System 3 +channel-type.nibeheatpump.f1x55-47367.description = Activates the RMU accessory for system 3 +channel-type.nibeheatpump.f1x55-47368.label = RMU System 4 +channel-type.nibeheatpump.f1x55-47368.description = Activates the RMU accessory for system 4 +channel-type.nibeheatpump.f1x55-47370.label = Allow Additive Heating +channel-type.nibeheatpump.f1x55-47370.description = Whether to allow additive heating (only valid for operational mode Manual) +channel-type.nibeheatpump.f1x55-47371.label = Allow Heating +channel-type.nibeheatpump.f1x55-47371.description = Whether to allow heating (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f1x55-47372.label = Allow Cooling +channel-type.nibeheatpump.f1x55-47372.description = Whether to allow cooling (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f1x55-47374.label = Start Temperature Cooling +channel-type.nibeheatpump.f1x55-47374.description = Start temperature for cooling, as set in menu 4.9.2 0=Off 1=On +channel-type.nibeheatpump.f1x55-47374.state.option.0 = Off +channel-type.nibeheatpump.f1x55-47374.state.option.1 = On +channel-type.nibeheatpump.f1x55-47375.label = Stop Temperature Heating +channel-type.nibeheatpump.f1x55-47375.description = Stop temperature for heating, as set in menu 4.9.2 +channel-type.nibeheatpump.f1x55-47376.label = Stop Temperature Additive +channel-type.nibeheatpump.f1x55-47376.description = Stop temperature for additive, as set in menu 4.9.2 +channel-type.nibeheatpump.f1x55-47377.label = Outdoor Filter Time +channel-type.nibeheatpump.f1x55-47377.description = 12=12 Hours 24=24 Hours +channel-type.nibeheatpump.f1x55-47377.state.option.12 = Hours 24 +channel-type.nibeheatpump.f1x55-47377.state.option.24 = Hours +channel-type.nibeheatpump.f1x55-47378.label = Max Diff. Comp. +channel-type.nibeheatpump.f1x55-47379.label = Max Diff. Add. +channel-type.nibeheatpump.f1x55-47380.label = Low Brine out Autoreset +channel-type.nibeheatpump.f1x55-47380.description = 0=Off 1=On +channel-type.nibeheatpump.f1x55-47381.label = Low Brine out Temp.EP14 +channel-type.nibeheatpump.f1x55-47382.label = High Brine In +channel-type.nibeheatpump.f1x55-47382.description = Activates the High brine in temperature alarm. 0=Off 1=On +channel-type.nibeheatpump.f1x55-47382.state.option.0 = Off +channel-type.nibeheatpump.f1x55-47382.state.option.1 = On +channel-type.nibeheatpump.f1x55-47383.label = High Brine in Temp. +channel-type.nibeheatpump.f1x55-47383.description = The brine in temperature that triggers the high brine in temperature alarm (if active). +channel-type.nibeheatpump.f1x55-47384.label = Date Format +channel-type.nibeheatpump.f1x55-47384.description = 1=DD-MM-YY 2=YY-MM-DD +channel-type.nibeheatpump.f1x55-47384.state.option.1 = DD-MM-YY +channel-type.nibeheatpump.f1x55-47384.state.option.2 = YY-MM-DD +channel-type.nibeheatpump.f1x55-47385.label = Time Format +channel-type.nibeheatpump.f1x55-47385.description = 12=12 hours 24=24 Hours +channel-type.nibeheatpump.f1x55-47385.state.option.12 = hours 24 +channel-type.nibeheatpump.f1x55-47385.state.option.24 = Hours +channel-type.nibeheatpump.f1x55-47387.label = HW Production +channel-type.nibeheatpump.f1x55-47387.description = Activates hot water production where applicable 0=Off 1=On +channel-type.nibeheatpump.f1x55-47388.label = Alarm Lower Room Temp. +channel-type.nibeheatpump.f1x55-47388.description = Lowers the room temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f1x55-47389.label = Alarm Lower HW Temp. +channel-type.nibeheatpump.f1x55-47389.description = Lowers the hot water temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f1x55-47391.label = Use Room Sensor S4 +channel-type.nibeheatpump.f1x55-47391.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x55-47392.label = Use Room Sensor S3 +channel-type.nibeheatpump.f1x55-47392.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x55-47393.label = Use Room Sensor S2 +channel-type.nibeheatpump.f1x55-47393.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x55-47394.label = Use Room Sensor S1 +channel-type.nibeheatpump.f1x55-47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f1x55-47395.label = Room Sensor Setpoint S4 +channel-type.nibeheatpump.f1x55-47395.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-47396.label = Room Sensor Setpoint S3 +channel-type.nibeheatpump.f1x55-47396.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-47397.label = Room Sensor Setpoint S2 +channel-type.nibeheatpump.f1x55-47397.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-47398.label = Room Sensor Setpoint S1 +channel-type.nibeheatpump.f1x55-47398.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-47399.label = Room Sensor Factor S4 +channel-type.nibeheatpump.f1x55-47399.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-47400.label = Room Sensor Factor S3 +channel-type.nibeheatpump.f1x55-47400.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-47401.label = Room Sensor Factor S2 +channel-type.nibeheatpump.f1x55-47401.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-47402.label = Room Sensor Factor S1 +channel-type.nibeheatpump.f1x55-47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-47413.label = Speed Circ.pump HW +channel-type.nibeheatpump.f1x55-47414.label = Speed Circ.pump Heat +channel-type.nibeheatpump.f1x55-47415.label = Speed Circ.pump Pool +channel-type.nibeheatpump.f1x55-47416.label = Speed Circ.pump Economy +channel-type.nibeheatpump.f1x55-47417.label = Speed Circulation Pump Passive Cooling EP14 +channel-type.nibeheatpump.f1x55-47418.label = Speed Brine Pump +channel-type.nibeheatpump.f1x55-47442.label = Preset Flow Clim. Sys. +channel-type.nibeheatpump.f1x55-47442.description = Preset flow setting for climate system. 0 = manual setting, 1 = radiator, 2 = floor heating, 3 = radiator + floor heating. +channel-type.nibeheatpump.f1x55-47442.state.option.0 = manual setting +channel-type.nibeheatpump.f1x55-47442.state.option.1 = radiator +channel-type.nibeheatpump.f1x55-47442.state.option.2 = floor heating +channel-type.nibeheatpump.f1x55-47442.state.option.3 = radiator + floor heating. +channel-type.nibeheatpump.f1x55-47525.label = Heat Curve S8 +channel-type.nibeheatpump.f1x55-47525.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-47537.label = Night Cooling +channel-type.nibeheatpump.f1x55-47537.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. 0=Off 1=On +channel-type.nibeheatpump.f1x55-47538.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f1x55-47539.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f1x55-47539.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f1x55-47567.label = Heat Curve S7 +channel-type.nibeheatpump.f1x55-47567.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48043.label = Holiday - Activated +channel-type.nibeheatpump.f1x55-48043.description = 0=inactive, 10=active +channel-type.nibeheatpump.f1x55-48043.state.option.0 = inactive +channel-type.nibeheatpump.f1x55-48043.state.option.10 = active +channel-type.nibeheatpump.f1x55-48053.label = FLM 2 Speed 4 +channel-type.nibeheatpump.f1x55-48054.label = FLM 2 Speed 3 +channel-type.nibeheatpump.f1x55-48055.label = FLM 2 Speed 2 +channel-type.nibeheatpump.f1x55-48056.label = FLM 2 Speed 1 +channel-type.nibeheatpump.f1x55-48057.label = FLM 2 Speed Normal +channel-type.nibeheatpump.f1x55-48058.label = FLM 3 Speed 4 +channel-type.nibeheatpump.f1x55-48059.label = FLM 3 Speed 3 +channel-type.nibeheatpump.f1x55-48060.label = FLM 3 Speed 2 +channel-type.nibeheatpump.f1x55-48061.label = FLM 3 Speed 1 +channel-type.nibeheatpump.f1x55-48062.label = FLM 3 Speed Normal +channel-type.nibeheatpump.f1x55-48063.label = FLM 4 Speed 4 +channel-type.nibeheatpump.f1x55-48064.label = FLM 4 Speed 3 +channel-type.nibeheatpump.f1x55-48065.label = FLM 4 Speed 2 +channel-type.nibeheatpump.f1x55-48066.label = FLM 4 Speed 1 +channel-type.nibeheatpump.f1x55-48067.label = FLM 4 Speed Normal +channel-type.nibeheatpump.f1x55-48068.label = FLM 4 Accessory +channel-type.nibeheatpump.f1x55-48068.description = Activates the FLM 4 accessory +channel-type.nibeheatpump.f1x55-48069.label = FLM 3 Accessory +channel-type.nibeheatpump.f1x55-48069.description = Activates the FLM 3 accessory +channel-type.nibeheatpump.f1x55-48070.label = FLM 2 Accessory +channel-type.nibeheatpump.f1x55-48070.description = Activates the FLM 2 accessory +channel-type.nibeheatpump.f1x55-48071.label = FLM 1 Accessory +channel-type.nibeheatpump.f1x55-48071.description = Activates the FLM 1 accessory +channel-type.nibeheatpump.f1x55-48072.label = DM Diff Start Add. +channel-type.nibeheatpump.f1x55-48072.description = The value below the last compressor step the degree minutes needed to be reached for the pump to start electric addition +channel-type.nibeheatpump.f1x55-48073.label = FLM 1 Cooling +channel-type.nibeheatpump.f1x55-48073.description = FLM 1 cooling activated|FLM 2 cooling activated|FLM 3 cooling activated|FLM 4 cooling activated +channel-type.nibeheatpump.f1x55-48074.label = Cool/Heat Sensor Set Point +channel-type.nibeheatpump.f1x55-48074.description = Set point for change between cooling and heating when using the cool/heat sensor +channel-type.nibeheatpump.f1x55-48087.label = Pool 2 Accessory +channel-type.nibeheatpump.f1x55-48087.description = Activate the pool 2 accessory +channel-type.nibeheatpump.f1x55-48088.label = Pool 1 Accessory +channel-type.nibeheatpump.f1x55-48088.description = Activates the pool 1 accessory +channel-type.nibeheatpump.f1x55-48089.label = Pool 2 Start Temp. +channel-type.nibeheatpump.f1x55-48089.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.f1x55-48090.label = Pool 1 Start Temp. +channel-type.nibeheatpump.f1x55-48090.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.f1x55-48091.label = Pool 2 Stop Temp. +channel-type.nibeheatpump.f1x55-48091.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.f1x55-48092.label = Pool 1 Stop Temp. +channel-type.nibeheatpump.f1x55-48092.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.f1x55-48093.label = Pool 2 Activated +channel-type.nibeheatpump.f1x55-48093.description = Activates pool heating +channel-type.nibeheatpump.f1x55-48094.label = Pool 1 Activated +channel-type.nibeheatpump.f1x55-48094.description = Activates pool heating +channel-type.nibeheatpump.f1x55-48120.label = HW Comfort +channel-type.nibeheatpump.f1x55-48120.description = Activates the HW Comfort Accessory. +channel-type.nibeheatpump.f1x55-48132.label = Temporary Lux +channel-type.nibeheatpump.f1x55-48132.description = 0=Off, 1=3h, 2=6h, 3=12h, 4=One time increase +channel-type.nibeheatpump.f1x55-48132.state.option.0 = Off +channel-type.nibeheatpump.f1x55-48132.state.option.1 = 3h +channel-type.nibeheatpump.f1x55-48132.state.option.2 = 6h +channel-type.nibeheatpump.f1x55-48132.state.option.3 = 12h +channel-type.nibeheatpump.f1x55-48132.state.option.4 = One time increase +channel-type.nibeheatpump.f1x55-48133.label = Period Pool 2 +channel-type.nibeheatpump.f1x55-48139.label = DM Startdiff Add. with Shunt +channel-type.nibeheatpump.f1x55-48142.label = Step Controlled Add. Start Diff DM +channel-type.nibeheatpump.f1x55-48142.description = DM diff from last compressor step where the first step of step controlled add. starts +channel-type.nibeheatpump.f1x55-48144.label = HW Comfort Add During Heat +channel-type.nibeheatpump.f1x55-48144.description = Allows the HW Comfort addition to run during heating. +channel-type.nibeheatpump.f1x55-48145.label = HW Comfort Mixing Valve +channel-type.nibeheatpump.f1x55-48145.description = Activates the HW Comfort Shunt. +channel-type.nibeheatpump.f1x55-48146.label = HW Comfort Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-48146.description = Mixing valve amplification for the HW Comfort Accessory +channel-type.nibeheatpump.f1x55-48147.label = HW Comfort Mixing Valve Wait +channel-type.nibeheatpump.f1x55-48147.description = Wait time between changes of the mixing valve for the HW Comfort Accessory +channel-type.nibeheatpump.f1x55-48148.label = HW Comfort Hotwater Temperature +channel-type.nibeheatpump.f1x55-48148.description = The desired hotwater temperature +channel-type.nibeheatpump.f1x55-48157.label = HW Comfort Add. +channel-type.nibeheatpump.f1x55-48157.description = Activates the HW Comfort Addition. +channel-type.nibeheatpump.f1x55-48174.label = Min Cooling Supply Temp S4 +channel-type.nibeheatpump.f1x55-48174.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48175.label = Min Cooling Supply Temp S3 +channel-type.nibeheatpump.f1x55-48175.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48176.label = Min Cooling Supply Temp S2 +channel-type.nibeheatpump.f1x55-48176.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48177.label = Min Cooling Supply Temp S1 +channel-type.nibeheatpump.f1x55-48177.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48181.label = Own Cooling Curve P3 +channel-type.nibeheatpump.f1x55-48181.description = User defined cooling curve point +channel-type.nibeheatpump.f1x55-48185.label = Own Cooling Curve P5 +channel-type.nibeheatpump.f1x55-48185.description = User defined cooling curve point +channel-type.nibeheatpump.f1x55-48186.label = Cooling Use Mix. Valve S4 +channel-type.nibeheatpump.f1x55-48186.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48187.label = Cooling Use Mix. Valve S3 +channel-type.nibeheatpump.f1x55-48187.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48188.label = Cooling Use Mix. Valve S2 +channel-type.nibeheatpump.f1x55-48188.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48189.label = Cooling Use Mix. Valve S1 +channel-type.nibeheatpump.f1x55-48189.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48190.label = Heatdump Mix. Valve Delay +channel-type.nibeheatpump.f1x55-48190.description = Mixing valve step delay for the heatdump valve +channel-type.nibeheatpump.f1x55-48191.label = Heatdump Mix. Valve Amp. +channel-type.nibeheatpump.f1x55-48191.description = Mixing valve amplification for the heatdump valve +channel-type.nibeheatpump.f1x55-48192.label = Cooldump Mix. Valve Delay +channel-type.nibeheatpump.f1x55-48192.description = Mixing valve step delay for the cooldump valve for the ACS-system +channel-type.nibeheatpump.f1x55-48193.label = Cooldump Mix. Valve Amp. +channel-type.nibeheatpump.f1x55-48193.description = Mixing valve amplification for the cooldump valve for the ACS-system +channel-type.nibeheatpump.f1x55-48194.label = ACS Accessory +channel-type.nibeheatpump.f1x55-48194.description = Activate the ACS accessory +channel-type.nibeheatpump.f1x55-48195.label = ACS Heat Dump 24h-function +channel-type.nibeheatpump.f1x55-48197.label = ACS Closingtime for Cool Dump +channel-type.nibeheatpump.f1x55-48264.label = Brine Shunt Accessory +channel-type.nibeheatpump.f1x55-48264.description = Activates the Brine shunt accessory +channel-type.nibeheatpump.f1x55-48265.label = Brine Shunt Amplication +channel-type.nibeheatpump.f1x55-48265.description = The Brine shunt accessory, shunt amplication +channel-type.nibeheatpump.f1x55-48266.label = Brine Shunt Wait Time +channel-type.nibeheatpump.f1x55-48266.description = The Brine shunt accessory, wait time +channel-type.nibeheatpump.f1x55-48267.label = Brine Shunt, Max Brine Temp +channel-type.nibeheatpump.f1x55-48267.description = The Brine shunt accessory, max brine temperature +channel-type.nibeheatpump.f1x55-48275.label = Max Charge Pump Reg Speed +channel-type.nibeheatpump.f1x55-48275.description = Max heat medium pump reg speed +channel-type.nibeheatpump.f1x55-48281.label = Charge Method HW +channel-type.nibeheatpump.f1x55-48281.description = Heating medium pump control when hot water is charged +channel-type.nibeheatpump.f1x55-48282.label = SG Ready Heating +channel-type.nibeheatpump.f1x55-48282.description = Sets whether or not SG Ready should affect heating +channel-type.nibeheatpump.f1x55-48283.label = SG Ready Cooling +channel-type.nibeheatpump.f1x55-48283.description = Sets whether or not SG Ready should affect cooling +channel-type.nibeheatpump.f1x55-48284.label = SG Ready Hot Water +channel-type.nibeheatpump.f1x55-48284.description = Sets whether or not SG Ready should affect hot water +channel-type.nibeheatpump.f1x55-48285.label = SG Ready Pool +channel-type.nibeheatpump.f1x55-48285.description = Sets whether or not SG Ready should affect pool +channel-type.nibeheatpump.f1x55-48286.label = Pool 2 Cpr Percentage +channel-type.nibeheatpump.f1x55-48287.label = Pool 1 Cpr Percentage +channel-type.nibeheatpump.f1x55-48288.label = Cool Cpr Percentage +channel-type.nibeheatpump.f1x55-48452.label = Auto Heat Medium Pump Speed, Hw +channel-type.nibeheatpump.f1x55-48452.description = Auto heat medium pump speed hw +channel-type.nibeheatpump.f1x55-48453.label = Auto Heat Medium Pump Speed, Heat +channel-type.nibeheatpump.f1x55-48453.description = Auto heat medium pump speed heat +channel-type.nibeheatpump.f1x55-48454.label = Auto Heat Medium Pump Speed, Pool +channel-type.nibeheatpump.f1x55-48454.description = Auto heat medium pump speed pool +channel-type.nibeheatpump.f1x55-48455.label = Auto Heat Medium Pump Speed, Cool +channel-type.nibeheatpump.f1x55-48455.description = Auto heat medium pump speed cool +channel-type.nibeheatpump.f1x55-48456.label = Operational Mode Heat Medium Pump, Cooling +channel-type.nibeheatpump.f1x55-48458.label = Max Speed Circ.pump Heat +channel-type.nibeheatpump.f1x55-48459.label = Speed Brine Pump Passive Cooling +channel-type.nibeheatpump.f1x55-48487.label = Speed Circulation Pump Active Cooling EP14 +channel-type.nibeheatpump.f1x55-48488.label = Heat Curve S6 +channel-type.nibeheatpump.f1x55-48488.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48489.label = Heat Curve S5 +channel-type.nibeheatpump.f1x55-48489.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48491.label = Heat Offset S8 +channel-type.nibeheatpump.f1x55-48491.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48492.label = Heat Offset S7 +channel-type.nibeheatpump.f1x55-48492.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48493.label = Heat Offset S6 +channel-type.nibeheatpump.f1x55-48493.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48494.label = Heat Offset S5 +channel-type.nibeheatpump.f1x55-48494.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f1x55-48495.label = Min Supply System 8 +channel-type.nibeheatpump.f1x55-48496.label = Min Supply System 7 +channel-type.nibeheatpump.f1x55-48497.label = Min Supply System 6 +channel-type.nibeheatpump.f1x55-48498.label = Min Supply System 5 +channel-type.nibeheatpump.f1x55-48499.label = Max Supply System 8 +channel-type.nibeheatpump.f1x55-48500.label = Max Supply System 7 +channel-type.nibeheatpump.f1x55-48501.label = Max Supply System 6 +channel-type.nibeheatpump.f1x55-48502.label = Max Supply System 5 +channel-type.nibeheatpump.f1x55-48503.label = External Adjustment S8 +channel-type.nibeheatpump.f1x55-48503.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48504.label = External Adjustment S7 +channel-type.nibeheatpump.f1x55-48504.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48505.label = External Adjustment S6 +channel-type.nibeheatpump.f1x55-48505.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48506.label = External Adjustment S5 +channel-type.nibeheatpump.f1x55-48506.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48507.label = External Adjustment with Room Sensor S8 +channel-type.nibeheatpump.f1x55-48507.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48508.label = External Adjustment with Room Sensor S7 +channel-type.nibeheatpump.f1x55-48508.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48509.label = External Adjustment with Room Sensor S6 +channel-type.nibeheatpump.f1x55-48509.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48510.label = External Adjustment with Room Sensor S5 +channel-type.nibeheatpump.f1x55-48510.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f1x55-48569.label = Climate System 5 Accessory +channel-type.nibeheatpump.f1x55-48569.description = Activates the climate system 5 accessory +channel-type.nibeheatpump.f1x55-48570.label = Climate System 6 Accessory +channel-type.nibeheatpump.f1x55-48570.description = Activates the climate system 6 accessory +channel-type.nibeheatpump.f1x55-48571.label = Climate System 7 Accessory +channel-type.nibeheatpump.f1x55-48571.description = Activates the climate system 7 accessory +channel-type.nibeheatpump.f1x55-48572.label = Climate System 8 Accessory +channel-type.nibeheatpump.f1x55-48572.description = Activates the climate system 8 accessory +channel-type.nibeheatpump.f1x55-48573.label = Climate System 8 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-48573.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-48574.label = Climate System 7 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-48574.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-48575.label = Climate System 6 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-48575.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-48576.label = Climate System 5 Mixing Valve Amp. +channel-type.nibeheatpump.f1x55-48576.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f1x55-48577.label = Climate System 8 Shunt Wait +channel-type.nibeheatpump.f1x55-48577.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-48578.label = Climate System 7 Shunt Wait +channel-type.nibeheatpump.f1x55-48578.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-48579.label = Climate System 6 Shunt Wait +channel-type.nibeheatpump.f1x55-48579.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-48580.label = Climate System 5 Shunt Wait +channel-type.nibeheatpump.f1x55-48580.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f1x55-48581.label = Min Cooling Supply Temp S8 +channel-type.nibeheatpump.f1x55-48581.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48582.label = Min Cooling Supply Temp S7 +channel-type.nibeheatpump.f1x55-48582.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48583.label = Min Cooling Supply Temp S6 +channel-type.nibeheatpump.f1x55-48583.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48584.label = Min Cooling Supply Temp S5 +channel-type.nibeheatpump.f1x55-48584.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.f1x55-48593.label = Cooling Use Mix. Valve S8 +channel-type.nibeheatpump.f1x55-48593.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48594.label = Cooling Use Mix. Valve S7 +channel-type.nibeheatpump.f1x55-48594.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48595.label = Cooling Use Mix. Valve S6 +channel-type.nibeheatpump.f1x55-48595.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48596.label = Cooling Use Mix. Valve S5 +channel-type.nibeheatpump.f1x55-48596.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.f1x55-48597.label = Heating Use Mix. Valve S8 +channel-type.nibeheatpump.f1x55-48597.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48598.label = Heating Use Mix. Valve S7 +channel-type.nibeheatpump.f1x55-48598.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48599.label = Heating Use Mix. Valve S6 +channel-type.nibeheatpump.f1x55-48599.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48600.label = Heating Use Mix. Valve S5 +channel-type.nibeheatpump.f1x55-48600.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48601.label = Heating Use Mix. Valve S4 +channel-type.nibeheatpump.f1x55-48601.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48602.label = Heating Use Mix. Valve S3 +channel-type.nibeheatpump.f1x55-48602.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48603.label = Heating Use Mix. Valve S2 +channel-type.nibeheatpump.f1x55-48603.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48604.label = Heating Use Mix. Valve S1 +channel-type.nibeheatpump.f1x55-48604.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.f1x55-48607.label = ERS 1 Accessory +channel-type.nibeheatpump.f1x55-48607.description = Activates the ERS accessory +channel-type.nibeheatpump.f1x55-48659.label = Cut Off Frequency Activated 2 +channel-type.nibeheatpump.f1x55-48659.description = Cut off frequency activated +channel-type.nibeheatpump.f1x55-48660.label = Cut Off Frequency Activated 1 +channel-type.nibeheatpump.f1x55-48660.description = Cut off frequency activated +channel-type.nibeheatpump.f1x55-48661.label = Cut Off Frequency Start 2 +channel-type.nibeheatpump.f1x55-48661.description = Cut off frequency start +channel-type.nibeheatpump.f1x55-48662.label = Cut Off Frequency Start 1 +channel-type.nibeheatpump.f1x55-48662.description = Cut off frequency start +channel-type.nibeheatpump.f1x55-48663.label = Cut Off Frequency Stop 2 +channel-type.nibeheatpump.f1x55-48663.description = Cut off frequency stop +channel-type.nibeheatpump.f1x55-48664.label = Cut Off Frequency Stop 1 +channel-type.nibeheatpump.f1x55-48664.description = Cut off frequency stop +channel-type.nibeheatpump.f1x55-48675.label = Use Room Sensor S8 +channel-type.nibeheatpump.f1x55-48675.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f1x55-48676.label = Use Room Sensor S7 +channel-type.nibeheatpump.f1x55-48676.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f1x55-48677.label = Use Room Sensor S6 +channel-type.nibeheatpump.f1x55-48677.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f1x55-48678.label = Use Room Sensor S5 +channel-type.nibeheatpump.f1x55-48678.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f1x55-48680.label = Room Sensor Setpoint S8 +channel-type.nibeheatpump.f1x55-48680.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-48681.label = Room Sensor Setpoint S7 +channel-type.nibeheatpump.f1x55-48681.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-48682.label = Room Sensor Setpoint S6 +channel-type.nibeheatpump.f1x55-48682.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-48683.label = Room Sensor Setpoint S5 +channel-type.nibeheatpump.f1x55-48683.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f1x55-48685.label = Room Sensor Factor S8 +channel-type.nibeheatpump.f1x55-48685.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-48686.label = Room Sensor Factor S7 +channel-type.nibeheatpump.f1x55-48686.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-48687.label = Room Sensor Factor S6 +channel-type.nibeheatpump.f1x55-48687.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-48688.label = Room Sensor Factor S5 +channel-type.nibeheatpump.f1x55-48688.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f1x55-48724.label = Cool Curve S8 +channel-type.nibeheatpump.f1x55-48724.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48725.label = Cool Curve S7 +channel-type.nibeheatpump.f1x55-48725.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48726.label = Cool Curve S6 +channel-type.nibeheatpump.f1x55-48726.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48727.label = Cool Curve S5 +channel-type.nibeheatpump.f1x55-48727.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48728.label = Cool Curve S4 +channel-type.nibeheatpump.f1x55-48728.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48729.label = Cool Curve S3 +channel-type.nibeheatpump.f1x55-48729.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48730.label = Cool Curve S2 +channel-type.nibeheatpump.f1x55-48730.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48731.label = Cool Curve S1 +channel-type.nibeheatpump.f1x55-48731.description = Cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48732.label = Cool Offset S8 +channel-type.nibeheatpump.f1x55-48732.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48733.label = Cool Offset S7 +channel-type.nibeheatpump.f1x55-48733.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48734.label = Cool Offset S6 +channel-type.nibeheatpump.f1x55-48734.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48735.label = Cool Offset S5 +channel-type.nibeheatpump.f1x55-48735.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48736.label = Cool Offset S4 +channel-type.nibeheatpump.f1x55-48736.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48737.label = Cool Offset S3 +channel-type.nibeheatpump.f1x55-48737.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48738.label = Cool Offset S2 +channel-type.nibeheatpump.f1x55-48738.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48739.label = Cool Offset S1 +channel-type.nibeheatpump.f1x55-48739.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f1x55-48740.label = Own Cooling Curve P4 +channel-type.nibeheatpump.f1x55-48740.description = User defined cooling curve point +channel-type.nibeheatpump.f1x55-48741.label = Own Cooling Curve P2 +channel-type.nibeheatpump.f1x55-48741.description = User defined cooling curve point +channel-type.nibeheatpump.f1x55-48742.label = Own Cooling Curve P1 +channel-type.nibeheatpump.f1x55-48742.description = User defined cooling curve point +channel-type.nibeheatpump.f1x55-48743.label = Hot Water High Power Mode +channel-type.nibeheatpump.f1x55-48755.label = Transformer Ratio +channel-type.nibeheatpump.f1x55-48755.description = Ratio of the current measurement transformers +channel-type.nibeheatpump.f1x55-48778.label = Room Sensor Cool Setpoint S8 +channel-type.nibeheatpump.f1x55-48778.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48779.label = Room Sensor Cool Setpoint S7 +channel-type.nibeheatpump.f1x55-48779.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48780.label = Room Sensor Cool Setpoint S6 +channel-type.nibeheatpump.f1x55-48780.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48781.label = Room Sensor Cool Setpoint S5 +channel-type.nibeheatpump.f1x55-48781.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48782.label = Room Sensor Cool Setpoint S4 +channel-type.nibeheatpump.f1x55-48782.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48783.label = Room Sensor Cool Setpoint S3 +channel-type.nibeheatpump.f1x55-48783.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48784.label = Room Sensor Cool Setpoint S2 +channel-type.nibeheatpump.f1x55-48784.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48785.label = Room Sensor Cool Setpoint S1 +channel-type.nibeheatpump.f1x55-48785.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.f1x55-48786.label = Room Sensor Cool Factor S8 +channel-type.nibeheatpump.f1x55-48786.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48787.label = Room Sensor Cool Factor S7 +channel-type.nibeheatpump.f1x55-48787.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48788.label = Room Sensor Cool Factor S6 +channel-type.nibeheatpump.f1x55-48788.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48789.label = Room Sensor Cool Factor S5 +channel-type.nibeheatpump.f1x55-48789.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48790.label = Room Sensor Cool Factor S4 +channel-type.nibeheatpump.f1x55-48790.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48791.label = Room Sensor Cool Factor S3 +channel-type.nibeheatpump.f1x55-48791.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48792.label = Room Sensor Cool Factor S2 +channel-type.nibeheatpump.f1x55-48792.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48793.label = Room Sensor Cool Factor S1 +channel-type.nibeheatpump.f1x55-48793.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48794.label = RH Set Value +channel-type.nibeheatpump.f1x55-48794.description = RH set value +channel-type.nibeheatpump.f1x55-48808.label = HTS Accessory +channel-type.nibeheatpump.f1x55-48808.description = HTS accessory +channel-type.nibeheatpump.f1x55-48810.label = Prevent Humidity S8 +channel-type.nibeheatpump.f1x55-48811.label = Prevent Humidity S7 +channel-type.nibeheatpump.f1x55-48812.label = Prevent Humidity S6 +channel-type.nibeheatpump.f1x55-48813.label = Prevent Humidity S5 +channel-type.nibeheatpump.f1x55-48814.label = Prevent Humidity S4 +channel-type.nibeheatpump.f1x55-48815.label = Prevent Humidity S3 +channel-type.nibeheatpump.f1x55-48816.label = Prevent Humidity S2 +channel-type.nibeheatpump.f1x55-48817.label = Prevent Humidity S1 +channel-type.nibeheatpump.f1x55-48819.label = Limit Humidity in Room, Heating S8 +channel-type.nibeheatpump.f1x55-48819.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48820.label = Limit Humidity in Room, Heating S7 +channel-type.nibeheatpump.f1x55-48820.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48821.label = Limit Humidity in Room, Heating S6 +channel-type.nibeheatpump.f1x55-48821.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48822.label = Limit Humidity in Room, Heating S5 +channel-type.nibeheatpump.f1x55-48822.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48823.label = Limit Humidity in Room, Heating S4 +channel-type.nibeheatpump.f1x55-48823.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48824.label = Limit Humidity in Room, Heating S3 +channel-type.nibeheatpump.f1x55-48824.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48825.label = Limit Humidity in Room, Heating S2 +channel-type.nibeheatpump.f1x55-48825.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48826.label = Limit Humidity in Room, Heating S1 +channel-type.nibeheatpump.f1x55-48826.description = Limit humidity in room, heating +channel-type.nibeheatpump.f1x55-48828.label = OPT +channel-type.nibeheatpump.f1x55-48828.description = Activates the OPT Accessory. +channel-type.nibeheatpump.f1x55-48829.label = OPT DM Startdiff +channel-type.nibeheatpump.f1x55-48829.description = The number of degree minutes below the last compressor the OPT is allowed to start +channel-type.nibeheatpump.f1x55-48849.label = Speed Brine Pump Active Cooling +channel-type.nibeheatpump.f1x55-48850.label = Delta Brine Pump Active Cooling +channel-type.nibeheatpump.f1x55-48851.label = Waiting Speed Brine Pump Cooling +channel-type.nibeheatpump.f1x55-48852.label = Modbus40 Word Swap +channel-type.nibeheatpump.f1x55-48852.description = If set; swapping the words in 32-bit variables when value requested via "read holding register" command. +channel-type.nibeheatpump.f1x55-48853.label = ERS 1 Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x55-48854.label = ERS 1 Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x55-48855.label = ERS 1 Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x55-48856.label = ERS 1 Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x55-48857.label = ERS 1 Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x55-48889.label = MODBUS40 Disable LOG.SET +channel-type.nibeheatpump.f1x55-48889.description = If set, the system will ignore the existing LOG.SET on the USB stick.1=ignore LOG.SET,0=use LOG.SET +channel-type.nibeheatpump.f1x55-48896.label = ERS 1 Supply Fan Speed 4 +channel-type.nibeheatpump.f1x55-48897.label = ERS 1 Supply Fan Speed 3 +channel-type.nibeheatpump.f1x55-48898.label = ERS 1 Supply Fan Speed 2 +channel-type.nibeheatpump.f1x55-48899.label = ERS 1 Supply Fan Speed 1 +channel-type.nibeheatpump.f1x55-48900.label = ERS 1 Supply Fan Speed Normal +channel-type.nibeheatpump.f1x55-48901.label = External ERS 1 Accessory Min Exhaust Temp. +channel-type.nibeheatpump.f1x55-48902.label = External ERS 1 Accessory Bypass Temp. +channel-type.nibeheatpump.f1x55-48908.label = Energy Meter Factor X23 +channel-type.nibeheatpump.f1x55-48908.description = Energy meter factor X23, energy per pulse +channel-type.nibeheatpump.f1x55-48909.label = Energy Meter Factor X22 +channel-type.nibeheatpump.f1x55-48909.description = Energy meter factor X22, energy per pulse +channel-type.nibeheatpump.f1x55-48910.label = Energy Meter X23 +channel-type.nibeheatpump.f1x55-48910.description = Activates the external energy meter +channel-type.nibeheatpump.f1x55-48911.label = Energy Meter X22 +channel-type.nibeheatpump.f1x55-48911.description = Activates the external energy meter +channel-type.nibeheatpump.f1x55-48918.label = Limit Humidity in Room, Cooling S8 +channel-type.nibeheatpump.f1x55-48918.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48919.label = Limit Humidity in Room, Cooling S7 +channel-type.nibeheatpump.f1x55-48919.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48920.label = Limit Humidity in Room, Cooling S6 +channel-type.nibeheatpump.f1x55-48920.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48921.label = Limit Humidity in Room, Cooling S5 +channel-type.nibeheatpump.f1x55-48921.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48922.label = Limit Humidity in Room, Cooling S4 +channel-type.nibeheatpump.f1x55-48922.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48923.label = Limit Humidity in Room, Cooling S3 +channel-type.nibeheatpump.f1x55-48923.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48924.label = Limit Humidity in Room, Cooling S2 +channel-type.nibeheatpump.f1x55-48924.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48925.label = Limit Humidity in Room, Cooling S1 +channel-type.nibeheatpump.f1x55-48925.description = Limit humidity in room, cooling +channel-type.nibeheatpump.f1x55-48926.label = Humidity Factor +channel-type.nibeheatpump.f1x55-48926.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature. +channel-type.nibeheatpump.f1x55-48927.label = Humidity Cool Factor +channel-type.nibeheatpump.f1x55-48927.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f1x55-48928.label = OPT Hystereses +channel-type.nibeheatpump.f1x55-48928.description = The hystereses in OPT system +channel-type.nibeheatpump.f1x55-48930.label = EME10 Activated +channel-type.nibeheatpump.f1x55-48930.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f1x55-48931.label = EME PV Panel Affect Heating +channel-type.nibeheatpump.f1x55-48931.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f1x55-48932.label = EME PV Panel Affect Hot Water +channel-type.nibeheatpump.f1x55-48932.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f1x55-48948.label = FLM Pump 4 +channel-type.nibeheatpump.f1x55-48948.description = Operating mode for the FLM pump 4 +channel-type.nibeheatpump.f1x55-48949.label = FLM Pump 3 +channel-type.nibeheatpump.f1x55-48949.description = Operating mode for the FLM pump 3 +channel-type.nibeheatpump.f1x55-48950.label = FLM Pump 2 +channel-type.nibeheatpump.f1x55-48950.description = Operating mode for the FLM pump 2 +channel-type.nibeheatpump.f1x55-48951.label = FLM 4 Defrost +channel-type.nibeheatpump.f1x55-48951.description = Minimum time between defrost in FLM 4 +channel-type.nibeheatpump.f1x55-48952.label = FLM 3 Defrost +channel-type.nibeheatpump.f1x55-48952.description = Minimum time between defrost in FLM 3 +channel-type.nibeheatpump.f1x55-48953.label = FLM 2 Defrost +channel-type.nibeheatpump.f1x55-48953.description = Minimum time between defrost in FLM 2 +channel-type.nibeheatpump.f1x55-48954.label = FLM 4 Cooling +channel-type.nibeheatpump.f1x55-48954.description = FLM 4 cooling activated +channel-type.nibeheatpump.f1x55-48955.label = FLM 3 Cooling +channel-type.nibeheatpump.f1x55-48955.description = FLM 3 cooling activated +channel-type.nibeheatpump.f1x55-48956.label = FLM 2 Cooling +channel-type.nibeheatpump.f1x55-48956.description = FLM 2 cooling activated +channel-type.nibeheatpump.f1x55-48957.label = FLM 4 Pump Speed +channel-type.nibeheatpump.f1x55-48957.description = FLM 4 pump speed +channel-type.nibeheatpump.f1x55-48958.label = FLM 3 Pump Speed +channel-type.nibeheatpump.f1x55-48958.description = FLM 3 pump speed +channel-type.nibeheatpump.f1x55-48959.label = FLM 2 Pump Speed +channel-type.nibeheatpump.f1x55-48959.description = FLM 2 pump speed +channel-type.nibeheatpump.f1x55-48960.label = FLM 1 Pump Speed +channel-type.nibeheatpump.f1x55-48960.description = FLM 1 pump speed +channel-type.nibeheatpump.f1x55-48961.label = FLM 4 over Temp +channel-type.nibeheatpump.f1x55-48961.description = Over temp for cooling active, when using FLM cooling +channel-type.nibeheatpump.f1x55-48962.label = FLM 3 over Temp +channel-type.nibeheatpump.f1x55-48962.description = Over temp for cooling active, when using FLM cooling +channel-type.nibeheatpump.f1x55-48963.label = FLM 2 over Temp +channel-type.nibeheatpump.f1x55-48963.description = Over temp for cooling active, when using FLM cooling +channel-type.nibeheatpump.f1x55-48964.label = FLM 1 over Temp +channel-type.nibeheatpump.f1x55-48964.description = Over temp for cooling active, when using FLM cooling +channel-type.nibeheatpump.f1x55-48965.label = FLM 4 Set Point, Cooling +channel-type.nibeheatpump.f1x55-48965.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f1x55-48966.label = FLM 3 Set Point, Cooling +channel-type.nibeheatpump.f1x55-48966.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f1x55-48967.label = FLM 2 Set Point, Cooling +channel-type.nibeheatpump.f1x55-48967.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f1x55-48968.label = FLM 1 Set Point, Cooling +channel-type.nibeheatpump.f1x55-48968.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f1x55-48969.label = AUX Block OPT +channel-type.nibeheatpump.f1x55-48969.description = AUX block OPT +channel-type.nibeheatpump.f1x55-48970.label = Outdoor Air Mixing Function +channel-type.nibeheatpump.f1x55-48970.description = Activates the Outdoor Air Mixing function. +channel-type.nibeheatpump.f1x55-48976.label = Smart Home Room Control +channel-type.nibeheatpump.f1x55-48977.label = Speed Brine Pump Wait Mode +channel-type.nibeheatpump.f1x55-48979.label = Smart Energy Source +channel-type.nibeheatpump.f1x55-48979.description = Smart energy source activated. +channel-type.nibeheatpump.f1x55-48980.label = Smart Energy Source, Ctrl Method +channel-type.nibeheatpump.f1x55-48980.description = Smart energy source, ctrl method. 0 = price. 1 = primary factor. +channel-type.nibeheatpump.f1x55-48981.label = Smart Energy Source, Electricity Price Source +channel-type.nibeheatpump.f1x55-48981.description = Smart energy source, electricity price source. 0 = fixed price. 1 = tariff. 2= spot price. +channel-type.nibeheatpump.f1x55-48981.state.option.0 = fixed price. +channel-type.nibeheatpump.f1x55-48981.state.option.1 = tariff. +channel-type.nibeheatpump.f1x55-48981.state.option.2 = spot price. +channel-type.nibeheatpump.f1x55-48982.label = Smart Energy Source, Electricity Price +channel-type.nibeheatpump.f1x55-48982.description = Smart energy source, electricity fixed price. +channel-type.nibeheatpump.f1x55-48983.label = Smart Energy Source, Fixed Elec. Price From +channel-type.nibeheatpump.f1x55-48983.description = Smart energy source, fixed electricity price part source, if spot electricity price are used. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.f1x55-48984.label = Smart Energy Source, Fixed Part Electricity Price +channel-type.nibeheatpump.f1x55-48984.description = Smart energy source, fixed part (if spot price are used) electricity price +channel-type.nibeheatpump.f1x55-48985.label = Smart Energy Source, Shunt Add Price Source +channel-type.nibeheatpump.f1x55-48985.description = Smart energy source, shunted addition price part source. From tariff or fixed price. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.f1x55-48986.label = Smart Energy Source, Shunt Add Price +channel-type.nibeheatpump.f1x55-48986.description = Smart energy source, shunted add price +channel-type.nibeheatpump.f1x55-48987.label = Smart Energy Source, Ext Step Add Price From +channel-type.nibeheatpump.f1x55-48987.description = Smart energy source, external step add source. From tariff or fixed price. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.f1x55-48988.label = Smart Energy Source, Ext Step Add Price +channel-type.nibeheatpump.f1x55-48988.description = Smart energy source, ext step add price +channel-type.nibeheatpump.f1x55-48989.label = Smart Energy Source, OPT10 Price Source +channel-type.nibeheatpump.f1x55-48989.description = Smart energy source, OPT10 addition price source. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.f1x55-48990.label = Smart Energy Source, OPT10 Price +channel-type.nibeheatpump.f1x55-48990.description = Smart energy source, OPT10 addition price. +channel-type.nibeheatpump.f1x55-48991.label = Smart Energy Source, Primary Factor Elec. +channel-type.nibeheatpump.f1x55-48991.description = Smart energy source, primary factor electricity +channel-type.nibeheatpump.f1x55-48992.label = Smart Energy Source, Primary Factor Shunted Add. +channel-type.nibeheatpump.f1x55-48992.description = Smart energy source, primary factor shunted addition +channel-type.nibeheatpump.f1x55-48993.label = Smart Energy Source, Primary Factor Ext Step Add +channel-type.nibeheatpump.f1x55-48993.description = Smart energy source, primary factor external step addition +channel-type.nibeheatpump.f1x55-48994.label = Smart Energy Source, Primary Factor OPT10 Add. +channel-type.nibeheatpump.f1x55-48994.description = Smart energy source, primary factor OPT10 addition +channel-type.nibeheatpump.f1x55-48995.label = Smart Energy Source, OPT10 High Tariff Price +channel-type.nibeheatpump.f1x55-48995.description = Smart energy source, OPT10 addition high tariff price +channel-type.nibeheatpump.f1x55-48996.label = Smart Energy Source, OPT10 Low Tariff Price +channel-type.nibeheatpump.f1x55-48996.description = Smart energy source, OPT10 addition low tariff price +channel-type.nibeheatpump.f1x55-48997.label = Smart Energy Source, Ext Step Add High Tariff Price +channel-type.nibeheatpump.f1x55-48997.description = Smart energy source, external step addition high tariff price +channel-type.nibeheatpump.f1x55-48998.label = Smart Energy Source, Ext Step Add Low Tariff Price +channel-type.nibeheatpump.f1x55-48998.description = Smart energy source, external step addition low tariff price +channel-type.nibeheatpump.f1x55-48999.label = Smart Energy Source, Shunt Add High Tariff Price +channel-type.nibeheatpump.f1x55-48999.description = Smart energy source, shunt addition high tariff price +channel-type.nibeheatpump.f1x55-49000.label = Smart Energy Source, Shunt Add Low Tariff Price +channel-type.nibeheatpump.f1x55-49000.description = Smart energy source, shunt addition low tariff price +channel-type.nibeheatpump.f1x55-49001.label = Smart Energy Source, Fixed Elec. High Tariff Price +channel-type.nibeheatpump.f1x55-49001.description = Smart energy source, fixed electricity part high tariff price +channel-type.nibeheatpump.f1x55-49002.label = Smart Energy Source, Fixed Elec. Low Tariff Price +channel-type.nibeheatpump.f1x55-49002.description = Smart energy source, fixed electricity part low tariff price +channel-type.nibeheatpump.f1x55-49003.label = Smart Energy Source, Electricity High Tariff Price +channel-type.nibeheatpump.f1x55-49003.description = Smart energy source, electricity high tariff price +channel-type.nibeheatpump.f1x55-49004.label = Smart Energy Source, Electricity High Low Price +channel-type.nibeheatpump.f1x55-49004.description = Smart energy source, electricity low tariff price +channel-type.nibeheatpump.f1x55-49005.label = Smart Energy Source, DM Diff Source Prio 5 +channel-type.nibeheatpump.f1x55-49005.description = Smart energy source, DM diff source with prio 5 +channel-type.nibeheatpump.f1x55-49006.label = Smart Energy Source, DM Diff Source Prio 4 +channel-type.nibeheatpump.f1x55-49006.description = Smart energy source, DM diff source with prio 4 +channel-type.nibeheatpump.f1x55-49007.label = Smart Energy Source, DM Diff Source Prio 3 +channel-type.nibeheatpump.f1x55-49007.description = Smart energy source, DM diff source with prio 3 +channel-type.nibeheatpump.f1x55-49008.label = Smart Energy Source, DM Diff Source Prio 2 +channel-type.nibeheatpump.f1x55-49008.description = Smart energy source, DM diff source with prio 2 +channel-type.nibeheatpump.f1x55-49009.label = Smart Energy Source, DM Start Source Prio 1 +channel-type.nibeheatpump.f1x55-49009.description = Smart energy source, DM start source with prio 1 +channel-type.nibeheatpump.f1x55-49190.label = Ground Water Pump Temp Alarm +channel-type.nibeheatpump.f1x55-49190.description = Ground water pump temperature alarm +channel-type.nibeheatpump.f1x55-49191.label = Ground Water Pump Temp Alarm Level +channel-type.nibeheatpump.f1x55-49191.description = Ground water pump temperature alarm level +channel-type.nibeheatpump.f1x55-49192.label = Fixed Delta T, Brine Pump +channel-type.nibeheatpump.f1x55-49193.label = Brine Pump Auto Controlled +channel-type.nibeheatpump.f1x55-49193.description = Brine pump auto controlled, 0= manual, 1 = auto controlled, 2 = fixed delta controlled +channel-type.nibeheatpump.f1x55-49193.state.option.0 = manual +channel-type.nibeheatpump.f1x55-49193.state.option.1 = auto controlled +channel-type.nibeheatpump.f1x55-49193.state.option.2 = fixed delta controlled +channel-type.nibeheatpump.f1x55-49221.label = Delta Brine Pump Passive Cooling +channel-type.nibeheatpump.f1x55-49239.label = EB101 Installed +channel-type.nibeheatpump.f1x55-49241.label = External ERS 1 Accessory Bypass Set Temp. +channel-type.nibeheatpump.f1x55-49242.label = External ERS 1 Accessory Bypass At Heat +channel-type.nibeheatpump.f1x55-49277.label = FLM 4 Fan +channel-type.nibeheatpump.f1x55-49277.description = FLM 4 fan +channel-type.nibeheatpump.f1x55-49278.label = FLM 3 Fan +channel-type.nibeheatpump.f1x55-49278.description = FLM 3 fan +channel-type.nibeheatpump.f1x55-49279.label = FLM 2 Fan +channel-type.nibeheatpump.f1x55-49279.description = FLM 2 fan +channel-type.nibeheatpump.f1x55-49280.label = FLM 1 Fan +channel-type.nibeheatpump.f1x55-49280.description = FLM 1 fan +channel-type.nibeheatpump.f1x55-49285.label = Energy Meter Pulses Per KWh X23 +channel-type.nibeheatpump.f1x55-49285.description = Energy meter factor X23, pulses per kWh +channel-type.nibeheatpump.f1x55-49286.label = Energy Meter Pulses Per KWh X22 +channel-type.nibeheatpump.f1x55-49286.description = Energy meter factor X22, pulses per kWh +channel-type.nibeheatpump.f1x55-49287.label = Energy Meter Mode X23 +channel-type.nibeheatpump.f1x55-49287.description = Energy meter X23 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.f1x55-49288.label = Energy Meter Mode X22 +channel-type.nibeheatpump.f1x55-49288.description = Energy meter X22 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.f1x55-49289.label = Ground Water Pump Speed Control +channel-type.nibeheatpump.f1x55-49290.label = Ground Water Pump Auto Speed Control +channel-type.nibeheatpump.f1x55-49290.description = Ground water pump auto speed control +channel-type.nibeheatpump.f1x55-49291.label = Ground Water Pump Manual Speed +channel-type.nibeheatpump.f1x55-49291.description = Ground water pump temperature alarm level +channel-type.nibeheatpump.f1x55-49292.label = Ground Water Pump Control Signal +channel-type.nibeheatpump.f1x55-49292.description = Ground water pump control signal (0 = 0V-10V; 1 = 10V-0V) +channel-type.nibeheatpump.f1x55-49293.label = Ground Water Pump Min Speed +channel-type.nibeheatpump.f1x55-49293.description = Ground water pump voltage at min speed +channel-type.nibeheatpump.f1x55-49297.label = EME20 Activated +channel-type.nibeheatpump.f1x55-49297.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f1x55-49298.label = EME PV Panel Affect Pool +channel-type.nibeheatpump.f1x55-49298.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f1x55-49298.state.option.0 = not affecting +channel-type.nibeheatpump.f1x55-49298.state.option.1 = affecting +channel-type.nibeheatpump.f1x55-49328.label = ERS 4 Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x55-49329.label = ERS 3 Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x55-49330.label = ERS 2 Exhaust Fan Speed 4 +channel-type.nibeheatpump.f1x55-49331.label = ERS 4 Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x55-49332.label = ERS 3 Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x55-49333.label = ERS 2 Exhaust Fan Speed 3 +channel-type.nibeheatpump.f1x55-49334.label = ERS 4 Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x55-49335.label = ERS 3 Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x55-49336.label = ERS 2 Exhaust Fan Speed 2 +channel-type.nibeheatpump.f1x55-49337.label = ERS 4 Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x55-49338.label = ERS 3 Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x55-49339.label = ERS 2 Exhaust Fan Speed 1 +channel-type.nibeheatpump.f1x55-49340.label = ERS 4 Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x55-49341.label = ERS 3 Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x55-49342.label = ERS 2 Exhaust Fan Speed Normal +channel-type.nibeheatpump.f1x55-49343.label = ERS 4 Supply Fan Speed 4 +channel-type.nibeheatpump.f1x55-49344.label = ERS 3 Supply Fan Speed 4 +channel-type.nibeheatpump.f1x55-49345.label = ERS 2 Supply Fan Speed 4 +channel-type.nibeheatpump.f1x55-49346.label = ERS 4 Supply Fan Speed 3 +channel-type.nibeheatpump.f1x55-49347.label = ERS 3 Supply Fan Speed 3 +channel-type.nibeheatpump.f1x55-49348.label = ERS 2 Supply Fan Speed 3 +channel-type.nibeheatpump.f1x55-49349.label = ERS 4 Supply Fan Speed 2 +channel-type.nibeheatpump.f1x55-49350.label = ERS 3 Supply Fan Speed 2 +channel-type.nibeheatpump.f1x55-49351.label = ERS 2 Supply Fan Speed 2 +channel-type.nibeheatpump.f1x55-49352.label = ERS 4 Supply Fan Speed 1 +channel-type.nibeheatpump.f1x55-49353.label = ERS 3 Supply Fan Speed 1 +channel-type.nibeheatpump.f1x55-49354.label = ERS 2 Supply Fan Speed 1 +channel-type.nibeheatpump.f1x55-49355.label = ERS 4 Supply Fan Speed Normal +channel-type.nibeheatpump.f1x55-49356.label = ERS 3 Supply Fan Speed Normal +channel-type.nibeheatpump.f1x55-49357.label = ERS 2 Supply Fan Speed Normal +channel-type.nibeheatpump.f1x55-49358.label = Night Cooling +channel-type.nibeheatpump.f1x55-49358.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f1x55-49359.label = Night Cooling +channel-type.nibeheatpump.f1x55-49359.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f1x55-49360.label = Night Cooling +channel-type.nibeheatpump.f1x55-49360.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f1x55-49361.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f1x55-49362.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f1x55-49363.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f1x55-49364.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f1x55-49364.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f1x55-49365.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f1x55-49365.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f1x55-49366.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f1x55-49366.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f1x55-49367.label = ERS 4 Accessory +channel-type.nibeheatpump.f1x55-49367.description = Activates the ERS accessory +channel-type.nibeheatpump.f1x55-49368.label = ERS 3 Accessory +channel-type.nibeheatpump.f1x55-49368.description = Activates the ERS accessory +channel-type.nibeheatpump.f1x55-49369.label = ERS 2 Accessory +channel-type.nibeheatpump.f1x55-49369.description = Activates the ERS accessory +channel-type.nibeheatpump.f1x55-49370.label = External ERS 4 Accessory Min Exhaust Temp. +channel-type.nibeheatpump.f1x55-49371.label = External ERS 3 Accessory Min Exhaust Temp. +channel-type.nibeheatpump.f1x55-49372.label = External ERS 2 Accessory Min Exhaust Temp. +channel-type.nibeheatpump.f1x55-49373.label = External ERS 4 Accessory Bypass Temp. +channel-type.nibeheatpump.f1x55-49374.label = External ERS 3 Accessory Bypass Temp. +channel-type.nibeheatpump.f1x55-49375.label = External ERS 2 Accessory Bypass Temp. +channel-type.nibeheatpump.f1x55-49376.label = External ERS 4 Accessory Bypass Set Temp. +channel-type.nibeheatpump.f1x55-49377.label = External ERS 3 Accessory Bypass Set Temp. +channel-type.nibeheatpump.f1x55-49378.label = External ERS 2 Accessory Bypass Set Temp. +channel-type.nibeheatpump.f1x55-49379.label = External ERS 4 Accessory Bypass At Heat +channel-type.nibeheatpump.f1x55-49380.label = External ERS 3 Accessory Bypass At Heat +channel-type.nibeheatpump.f1x55-49381.label = External ERS 2 Accessory Bypass At Heat +channel-type.nibeheatpump.f1x55-49430.label = AUX ERS Fire Place Guard +channel-type.nibeheatpump.f1x55-49430.description = Activates ERS Fire Place Guard +channel-type.nibeheatpump.f470-40004.label = BT1 Outdoor Temperature +channel-type.nibeheatpump.f470-40004.description = Current outdoor temperature +channel-type.nibeheatpump.f470-40005.label = EP23-BT2 Supply Temp S4 +channel-type.nibeheatpump.f470-40005.description = Supply temperature for system 4 +channel-type.nibeheatpump.f470-40006.label = EP22-BT2 Supply Temp S3 +channel-type.nibeheatpump.f470-40006.description = Supply temperature for system 3 +channel-type.nibeheatpump.f470-40007.label = EP21-BT2 Supply Temp S2 +channel-type.nibeheatpump.f470-40007.description = Supply temperature for system 2 +channel-type.nibeheatpump.f470-40008.label = BT2 Supply Temp S1 +channel-type.nibeheatpump.f470-40008.description = Supply temperature for system 1 +channel-type.nibeheatpump.f470-40012.label = EB100-EP14-BT3 Return Temp +channel-type.nibeheatpump.f470-40012.description = Return temperature +channel-type.nibeheatpump.f470-40013.label = BT7 HW Top +channel-type.nibeheatpump.f470-40013.description = Hot water top temperature, BT7 +channel-type.nibeheatpump.f470-40014.label = BT6 HW Load +channel-type.nibeheatpump.f470-40014.description = Hot water load temperature, BT6 +channel-type.nibeheatpump.f470-40020.label = EB100-BT16 Evaporator Temp +channel-type.nibeheatpump.f470-40022.label = EB100-EP14-BT17 Suction +channel-type.nibeheatpump.f470-40022.description = Suction temperature, BT17 +channel-type.nibeheatpump.f470-40023.label = EB100-BT18 Compressor Temp. +channel-type.nibeheatpump.f470-40023.description = Valid only for F3/470 +channel-type.nibeheatpump.f470-40024.label = EB100-BT19 Addition Temp. +channel-type.nibeheatpump.f470-40024.description = Valid only for F3/470 +channel-type.nibeheatpump.f470-40025.label = BT20 Exhaust Air Temp. 1 +channel-type.nibeheatpump.f470-40026.label = BT21 Vented Air Temp. 1 +channel-type.nibeheatpump.f470-40030.label = EP23-BT50 Room Temp S4 +channel-type.nibeheatpump.f470-40031.label = EP22-BT50 Room Temp S3 +channel-type.nibeheatpump.f470-40032.label = EP21-BT50 Room Temp S2 +channel-type.nibeheatpump.f470-40033.label = BT50 Room Temp S1 +channel-type.nibeheatpump.f470-40043.label = BT53 Solar Panel Temp +channel-type.nibeheatpump.f470-40043.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f470-40044.label = BT54 Solar Load Temp +channel-type.nibeheatpump.f470-40044.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f470-40054.label = EB100-FD1 Temperature Limiter +channel-type.nibeheatpump.f470-40067.label = BT1 Average +channel-type.nibeheatpump.f470-40067.description = EB100-BT1 Outdoor temperature average +channel-type.nibeheatpump.f470-40071.label = BT25 Ext. Supply +channel-type.nibeheatpump.f470-40071.description = External supply temperature, BT25 +channel-type.nibeheatpump.f470-40074.label = EB100-FR1 Anode Status +channel-type.nibeheatpump.f470-40075.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f470-40076.label = EP30-BT55 Solar Tank Top Temp +channel-type.nibeheatpump.f470-40079.label = EB100-BE3 Current +channel-type.nibeheatpump.f470-40081.label = EB100-BE2 Current +channel-type.nibeheatpump.f470-40083.label = EB100-BE1 Current +channel-type.nibeheatpump.f470-40122.label = BT52 External Water Heater Load Temp. +channel-type.nibeheatpump.f470-40122.description = Used in DEH and AHPS Docking accessories +channel-type.nibeheatpump.f470-40127.label = EP23-BT3 Return Temp S4 +channel-type.nibeheatpump.f470-40127.description = Return temperature for system 4 +channel-type.nibeheatpump.f470-40128.label = EP22-BT3 Return Temp S3 +channel-type.nibeheatpump.f470-40128.description = Return temperature for system 3 +channel-type.nibeheatpump.f470-40129.label = EP21-BT3 Return Temp S2 +channel-type.nibeheatpump.f470-40129.description = Return temperature for system 2 +channel-type.nibeheatpump.f470-40159.label = EP47-BT2 Supply Temp S8 +channel-type.nibeheatpump.f470-40159.description = Supply temperature for system 8 +channel-type.nibeheatpump.f470-40160.label = EP46-BT2 Supply Temp S7 +channel-type.nibeheatpump.f470-40160.description = Supply temperature for system 7 +channel-type.nibeheatpump.f470-40161.label = EP45-BT2 Supply Temp S6 +channel-type.nibeheatpump.f470-40161.description = Supply temperature for system 6 +channel-type.nibeheatpump.f470-40162.label = EP44-BT2 Supply Temp S5 +channel-type.nibeheatpump.f470-40162.description = Supply temperature for system 5 +channel-type.nibeheatpump.f470-40163.label = EP47-BT3 Return Temp S8 +channel-type.nibeheatpump.f470-40163.description = Return temperature for system 8 +channel-type.nibeheatpump.f470-40164.label = EP46-BT3 Return Temp S7 +channel-type.nibeheatpump.f470-40164.description = Return temperature for system 7 +channel-type.nibeheatpump.f470-40165.label = EP45-BT3 Return Temp S6 +channel-type.nibeheatpump.f470-40165.description = Return temperature for system 6 +channel-type.nibeheatpump.f470-40166.label = EP44-BT3 Return Temp S5 +channel-type.nibeheatpump.f470-40166.description = Return temperature for system 5 +channel-type.nibeheatpump.f470-40167.label = EP47-BT50 Room Temp S8 +channel-type.nibeheatpump.f470-40168.label = EP46-BT50 Room Temp S7 +channel-type.nibeheatpump.f470-40169.label = EP45-BT50 Room Temp S6 +channel-type.nibeheatpump.f470-40170.label = EP44-BT50 Room Temp S5 +channel-type.nibeheatpump.f470-40185.label = BT1 Average, 1h +channel-type.nibeheatpump.f470-40185.description = EB100-BT1 Outdoor temperature average, 1h +channel-type.nibeheatpump.f470-40188.label = EP47-BT50 Room Temp S8 Average +channel-type.nibeheatpump.f470-40189.label = EP46-BT50 Room Temp S7 Average +channel-type.nibeheatpump.f470-40190.label = EP45-BT50 Room Temp S6 Average +channel-type.nibeheatpump.f470-40191.label = EP44-BT50 Room Temp S5 Average +channel-type.nibeheatpump.f470-40192.label = EP23-BT50 Room Temp S4 Average +channel-type.nibeheatpump.f470-40193.label = EP22-BT50 Room Temp S3 Average +channel-type.nibeheatpump.f470-40194.label = EP21-BT50 Room Temp S2 Average +channel-type.nibeheatpump.f470-40195.label = BT50 Room Temp S1 Average +channel-type.nibeheatpump.f470-40212.label = BT74 Average +channel-type.nibeheatpump.f470-40212.description = BT74 heating cooling sensor average +channel-type.nibeheatpump.f470-40217.label = Calc. Supply S8 +channel-type.nibeheatpump.f470-40217.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-40218.label = Calc. Supply S7 +channel-type.nibeheatpump.f470-40218.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-40219.label = Calc. Supply S6 +channel-type.nibeheatpump.f470-40219.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-40220.label = Calculated Supply S5 +channel-type.nibeheatpump.f470-40220.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-40305.label = Mixing Valve State S8 +channel-type.nibeheatpump.f470-40305.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-40306.label = Mixing Valve State S7 +channel-type.nibeheatpump.f470-40306.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-40307.label = Mixing Valve State S6 +channel-type.nibeheatpump.f470-40307.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-40308.label = Mixing Valve State S5 +channel-type.nibeheatpump.f470-40308.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-40339.label = External Adjustment Activated Via Input S8 +channel-type.nibeheatpump.f470-40340.label = External Adjustment Activated Via Input S7 +channel-type.nibeheatpump.f470-40341.label = External Adjustment Activated Via Input S6 +channel-type.nibeheatpump.f470-40342.label = External Adjustment Activated Via Input S5 +channel-type.nibeheatpump.f470-40365.label = Extra Heating System Pump S8 +channel-type.nibeheatpump.f470-40366.label = Extra Heating System Pump S7 +channel-type.nibeheatpump.f470-40367.label = Extra Heating System Pump S6 +channel-type.nibeheatpump.f470-40368.label = Extra Heating System Pump S5 +channel-type.nibeheatpump.f470-40755.label = Tot. Ext. HW Add Op.time +channel-type.nibeheatpump.f470-40755.description = Total external hw-electric additive operation time +channel-type.nibeheatpump.f470-40868.label = +Adjust AUX Port +channel-type.nibeheatpump.f470-40870.label = +Adjust OP Mode +channel-type.nibeheatpump.f470-40870.description = Tells if plusadjust system calls for heat or cool +channel-type.nibeheatpump.f470-40871.label = +Adjust Comfort Mode +channel-type.nibeheatpump.f470-40871.description = Which comfort mode +channel-type.nibeheatpump.f470-40872.label = +Adjust Parallell Adjustment +channel-type.nibeheatpump.f470-40872.description = requested adjustment +channel-type.nibeheatpump.f470-40873.label = +Adjust Humidity +channel-type.nibeheatpump.f470-40873.description = Humidity +channel-type.nibeheatpump.f470-40874.label = +Adjust Temp Indoor +channel-type.nibeheatpump.f470-40874.description = Average of all room sensors +channel-type.nibeheatpump.f470-40875.label = +Adjust Temp Outdoor +channel-type.nibeheatpump.f470-40875.description = Outdoor temp +channel-type.nibeheatpump.f470-40876.label = +Adjust Version +channel-type.nibeheatpump.f470-40876.description = PCA input version +channel-type.nibeheatpump.f470-40877.label = +Adjust Activated +channel-type.nibeheatpump.f470-40877.description = If plusadjust accessory is activated +channel-type.nibeheatpump.f470-40878.label = +Adjust Need +channel-type.nibeheatpump.f470-40878.description = If plusadjust system calls for heat +channel-type.nibeheatpump.f470-40879.label = +Adjust Parallell Factor +channel-type.nibeheatpump.f470-40880.label = +Adjust Max Change +channel-type.nibeheatpump.f470-40880.description = Largest allowed change +channel-type.nibeheatpump.f470-40881.label = +Adjust Affect System8 +channel-type.nibeheatpump.f470-40881.description = System affected by paralell change +channel-type.nibeheatpump.f470-40882.label = +Adjust Affect System7 +channel-type.nibeheatpump.f470-40882.description = System affected by paralell change +channel-type.nibeheatpump.f470-40883.label = +Adjust Affect System6 +channel-type.nibeheatpump.f470-40883.description = System affected by paralell change +channel-type.nibeheatpump.f470-40884.label = +Adjust Affect System5 +channel-type.nibeheatpump.f470-40884.description = System affected by paralell change +channel-type.nibeheatpump.f470-40885.label = +Adjust Affect System4 +channel-type.nibeheatpump.f470-40885.description = System affected by paralell change +channel-type.nibeheatpump.f470-40886.label = +Adjust Affect System3 +channel-type.nibeheatpump.f470-40886.description = System affected by paralell change +channel-type.nibeheatpump.f470-40887.label = +Adjust Affect System2 +channel-type.nibeheatpump.f470-40887.description = System affected by paralell change +channel-type.nibeheatpump.f470-40888.label = +Adjust Affect System1 +channel-type.nibeheatpump.f470-40888.description = System affected by paralell change +channel-type.nibeheatpump.f470-40889.label = BT64 Average +channel-type.nibeheatpump.f470-40889.description = BT64 Cooling supply average +channel-type.nibeheatpump.f470-41027.label = Humidity Average +channel-type.nibeheatpump.f470-41027.description = Humidity average +channel-type.nibeheatpump.f470-41189.label = AA20-BE5 EME10 Current +channel-type.nibeheatpump.f470-41190.label = AA20-BE5 EME10 Average Current +channel-type.nibeheatpump.f470-41191.label = PV Panel State +channel-type.nibeheatpump.f470-41256.label = Fan Speed Current +channel-type.nibeheatpump.f470-41256.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f470-41257.label = Fan Speed Current +channel-type.nibeheatpump.f470-41257.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f470-41258.label = Fan Speed Current +channel-type.nibeheatpump.f470-41258.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f470-41265.label = Smart Home Mode +channel-type.nibeheatpump.f470-41265.description = Current smart home mode, 0=Default,1=Away from home,2=Vacation +channel-type.nibeheatpump.f470-41265.state.option.0 = Default +channel-type.nibeheatpump.f470-41265.state.option.1 = Away from home +channel-type.nibeheatpump.f470-41265.state.option.2 = Vacation +channel-type.nibeheatpump.f470-41266.label = Offset to Smart Home System +channel-type.nibeheatpump.f470-41266.description = Offset to smart home system +channel-type.nibeheatpump.f470-41267.label = Smart Home Ctrl Syst 8 +channel-type.nibeheatpump.f470-41267.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41268.label = Smart Home Ctrl Syst 7 +channel-type.nibeheatpump.f470-41268.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41269.label = Smart Home Ctrl Syst 6 +channel-type.nibeheatpump.f470-41269.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41270.label = Smart Home Ctrl Syst 5 +channel-type.nibeheatpump.f470-41270.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41271.label = Smart Home Ctrl Syst 4 +channel-type.nibeheatpump.f470-41271.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41272.label = Smart Home Ctrl Syst 3 +channel-type.nibeheatpump.f470-41272.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41273.label = Smart Home Ctrl Syst 2 +channel-type.nibeheatpump.f470-41273.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41274.label = Smart Home Ctrl Syst 1 +channel-type.nibeheatpump.f470-41274.description = Smart Home is controlling the system +channel-type.nibeheatpump.f470-41928.label = Smart Price Adaption Price +channel-type.nibeheatpump.f470-41928.description = The current electric price +channel-type.nibeheatpump.f470-41929.label = Smart Price Adaption Price Level +channel-type.nibeheatpump.f470-41929.description = Whether the current price is unknown (0), low (1), medium (2), high (3) +channel-type.nibeheatpump.f470-41930.label = AA23-BE5 Power 10 +channel-type.nibeheatpump.f470-41931.label = AA23-BE5 Power 9 +channel-type.nibeheatpump.f470-41932.label = AA23-BE5 Power 8 +channel-type.nibeheatpump.f470-41933.label = AA23-BE5 Power 7 +channel-type.nibeheatpump.f470-41934.label = AA23-BE5 Power 6 +channel-type.nibeheatpump.f470-41935.label = AA23-BE5 Power 5 +channel-type.nibeheatpump.f470-41936.label = AA23-BE5 Power 4 +channel-type.nibeheatpump.f470-41937.label = AA23-BE5 Power 3 +channel-type.nibeheatpump.f470-41938.label = AA23-BE5 Power 2 +channel-type.nibeheatpump.f470-41939.label = AA23-BE5 Power 1 +channel-type.nibeheatpump.f470-41940.label = AA23-BE5 Error High 10 +channel-type.nibeheatpump.f470-41941.label = AA23-BE5 Error High 9 +channel-type.nibeheatpump.f470-41942.label = AA23-BE5 Error High 8 +channel-type.nibeheatpump.f470-41943.label = AA23-BE5 Error High 7 +channel-type.nibeheatpump.f470-41944.label = AA23-BE5 Error High 6 +channel-type.nibeheatpump.f470-41945.label = AA23-BE5 Error High 5 +channel-type.nibeheatpump.f470-41946.label = AA23-BE5 Error High 4 +channel-type.nibeheatpump.f470-41947.label = AA23-BE5 Error High 3 +channel-type.nibeheatpump.f470-41948.label = AA23-BE5 Error High 2 +channel-type.nibeheatpump.f470-41949.label = AA23-BE5 Error High 1 +channel-type.nibeheatpump.f470-41950.label = AA23-BE5 Error Low 10 +channel-type.nibeheatpump.f470-41951.label = AA23-BE5 Error Low 9 +channel-type.nibeheatpump.f470-41952.label = AA23-BE5 Error Low 8 +channel-type.nibeheatpump.f470-41953.label = AA23-BE5 Error Low 7 +channel-type.nibeheatpump.f470-41954.label = AA23-BE5 Error Low 6 +channel-type.nibeheatpump.f470-41955.label = AA23-BE5 Error Low 5 +channel-type.nibeheatpump.f470-41956.label = AA23-BE5 Error Low 4 +channel-type.nibeheatpump.f470-41957.label = AA23-BE5 Error Low 3 +channel-type.nibeheatpump.f470-41958.label = AA23-BE5 Error Low 2 +channel-type.nibeheatpump.f470-41959.label = AA23-BE5 Error Low 1 +channel-type.nibeheatpump.f470-41960.label = AA23-BE5 Com Percentage 10 +channel-type.nibeheatpump.f470-41961.label = AA23-BE5 Com Percentage 9 +channel-type.nibeheatpump.f470-41962.label = AA23-BE5 Com Percentage 8 +channel-type.nibeheatpump.f470-41963.label = AA23-BE5 Com Percentage 7 +channel-type.nibeheatpump.f470-41964.label = AA23-BE5 Com Percentage 6 +channel-type.nibeheatpump.f470-41965.label = AA23-BE5 Com Percentage 5 +channel-type.nibeheatpump.f470-41966.label = AA23-BE5 Com Percentage 4 +channel-type.nibeheatpump.f470-41967.label = AA23-BE5 Com Percentage 3 +channel-type.nibeheatpump.f470-41968.label = AA23-BE5 Com Percentage 2 +channel-type.nibeheatpump.f470-41969.label = AA23-BE5 Com Percentage 1 +channel-type.nibeheatpump.f470-41980.label = AA23-BE5 Voltage1 10 +channel-type.nibeheatpump.f470-41981.label = AA23-BE5 Voltage1 9 +channel-type.nibeheatpump.f470-41982.label = AA23-BE5 Voltage1 8 +channel-type.nibeheatpump.f470-41983.label = AA23-BE5 Voltage1 7 +channel-type.nibeheatpump.f470-41984.label = AA23-BE5 Voltage1 6 +channel-type.nibeheatpump.f470-41985.label = AA23-BE5 Voltage1 5 +channel-type.nibeheatpump.f470-41986.label = AA23-BE5 Voltage1 4 +channel-type.nibeheatpump.f470-41987.label = AA23-BE5 Voltage1 3 +channel-type.nibeheatpump.f470-41988.label = AA23-BE5 Voltage1 2 +channel-type.nibeheatpump.f470-41989.label = AA23-BE5 Voltage1 1 +channel-type.nibeheatpump.f470-41990.label = AA23-BE5 Voltage2 10 +channel-type.nibeheatpump.f470-41991.label = AA23-BE5 Voltage2 9 +channel-type.nibeheatpump.f470-41992.label = AA23-BE5 Voltage2 8 +channel-type.nibeheatpump.f470-41993.label = AA23-BE5 Voltage2 7 +channel-type.nibeheatpump.f470-41994.label = AA23-BE5 Voltage2 6 +channel-type.nibeheatpump.f470-41995.label = AA23-BE5 Voltage2 5 +channel-type.nibeheatpump.f470-41996.label = AA23-BE5 Voltage2 4 +channel-type.nibeheatpump.f470-41997.label = AA23-BE5 Voltage2 3 +channel-type.nibeheatpump.f470-41998.label = AA23-BE5 Voltage2 2 +channel-type.nibeheatpump.f470-41999.label = AA23-BE5 Voltage2 1 +channel-type.nibeheatpump.f470-42000.label = AA23-BE5 Temperature 10 +channel-type.nibeheatpump.f470-42001.label = AA23-BE5 Temperature 9 +channel-type.nibeheatpump.f470-42002.label = AA23-BE5 Temperature 8 +channel-type.nibeheatpump.f470-42003.label = AA23-BE5 Temperature 7 +channel-type.nibeheatpump.f470-42004.label = AA23-BE5 Temperature 6 +channel-type.nibeheatpump.f470-42005.label = AA23-BE5 Temperature 5 +channel-type.nibeheatpump.f470-42006.label = AA23-BE5 Temperature 4 +channel-type.nibeheatpump.f470-42007.label = AA23-BE5 Temperature 3 +channel-type.nibeheatpump.f470-42008.label = AA23-BE5 Temperature 2 +channel-type.nibeheatpump.f470-42009.label = AA23-BE5 Temperature 1 +channel-type.nibeheatpump.f470-42010.label = AA23-BE5 Energy 10 +channel-type.nibeheatpump.f470-42012.label = AA23-BE5 Energy 9 +channel-type.nibeheatpump.f470-42014.label = AA23-BE5 Energy 8 +channel-type.nibeheatpump.f470-42016.label = AA23-BE5 Energy 7 +channel-type.nibeheatpump.f470-42018.label = AA23-BE5 Energy 6 +channel-type.nibeheatpump.f470-42020.label = AA23-BE5 Energy 5 +channel-type.nibeheatpump.f470-42022.label = AA23-BE5 Energy 4 +channel-type.nibeheatpump.f470-42024.label = AA23-BE5 Energy 3 +channel-type.nibeheatpump.f470-42026.label = AA23-BE5 Energy 2 +channel-type.nibeheatpump.f470-42028.label = AA23-BE5 Energy 1 +channel-type.nibeheatpump.f470-42030.label = AA23-BE5 EME20 Version +channel-type.nibeheatpump.f470-42033.label = PV Panel Heat Offset +channel-type.nibeheatpump.f470-42034.label = PV Panel Pool Offset +channel-type.nibeheatpump.f470-42035.label = AA23-BE5 EME20 Total Power +channel-type.nibeheatpump.f470-42037.label = AA23-BE5 EME20 Total Average Power +channel-type.nibeheatpump.f470-42075.label = AA23-BE5 EME20 Total Energy +channel-type.nibeheatpump.f470-42080.label = AA23-BE5 Alarm 504 +channel-type.nibeheatpump.f470-42081.label = AA23-BE5 Alarm 505 +channel-type.nibeheatpump.f470-42082.label = AA23-BE5 Alarm 506 +channel-type.nibeheatpump.f470-42083.label = AA23-BE5 Alarm 507 +channel-type.nibeheatpump.f470-42084.label = AA23-BE5 Alarm 508 +channel-type.nibeheatpump.f470-42085.label = AA23-BE5 Alarm 509 +channel-type.nibeheatpump.f470-42086.label = AA23-BE5 Alarm 510 +channel-type.nibeheatpump.f470-42087.label = AA23-BE5 Alarm 511 +channel-type.nibeheatpump.f470-42100.label = BT1 Average, 24h +channel-type.nibeheatpump.f470-42100.description = EB100-BT1 Outdoor temperature average, 24h +channel-type.nibeheatpump.f470-42101.label = Used Heating Power Average, 24h +channel-type.nibeheatpump.f470-42101.description = Used heating power average, 24h +channel-type.nibeheatpump.f470-42136.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f470-42137.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f470-42138.label = BT22 Supply Air Temp. +channel-type.nibeheatpump.f470-43001.label = Software Version +channel-type.nibeheatpump.f470-43006.label = Calc. Supply S4 +channel-type.nibeheatpump.f470-43006.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-43007.label = Calc. Supply S3 +channel-type.nibeheatpump.f470-43007.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-43008.label = Calc. Supply S2 +channel-type.nibeheatpump.f470-43008.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-43009.label = Calc. Supply S1 +channel-type.nibeheatpump.f470-43009.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f470-43013.label = Freeze Protection Status +channel-type.nibeheatpump.f470-43013.description = 1 = Freeze protection active +channel-type.nibeheatpump.f470-43013.state.option.1 = Freeze protection active +channel-type.nibeheatpump.f470-43081.label = Tot. Op.time Add. +channel-type.nibeheatpump.f470-43081.description = Total electric additive operation time +channel-type.nibeheatpump.f470-43084.label = Int. El.add. Power +channel-type.nibeheatpump.f470-43084.description = Current power from the internal electrical addition +channel-type.nibeheatpump.f470-43086.label = Prio +channel-type.nibeheatpump.f470-43086.description = Indicates what heating action (HW/heat/pool) currently prioritised 10=Off 20=Hot Water 30=Heat 40=Pool 41=Pool 2 50=Transfer 60=Cooling +channel-type.nibeheatpump.f470-43086.state.option.10 = Off +channel-type.nibeheatpump.f470-43086.state.option.20 = Hot Water +channel-type.nibeheatpump.f470-43086.state.option.30 = Heat +channel-type.nibeheatpump.f470-43086.state.option.40 = Pool +channel-type.nibeheatpump.f470-43086.state.option.41 = Pool 2 +channel-type.nibeheatpump.f470-43086.state.option.50 = Transfer +channel-type.nibeheatpump.f470-43086.state.option.60 = Cooling +channel-type.nibeheatpump.f470-43091.label = Int. El.add. State +channel-type.nibeheatpump.f470-43091.description = Number of steps active for internal step-controlled addition +channel-type.nibeheatpump.f470-43093.label = Mixing Valve State S4 +channel-type.nibeheatpump.f470-43093.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-43094.label = Mixing Valve State S3 +channel-type.nibeheatpump.f470-43094.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-43095.label = Mixing Valve State S2 +channel-type.nibeheatpump.f470-43095.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-43096.label = Mixing Valve State S1 +channel-type.nibeheatpump.f470-43096.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f470-43105.label = Status FJVM +channel-type.nibeheatpump.f470-43105.description = The state of the FJVM accessory +channel-type.nibeheatpump.f470-43108.label = Fan Speed Current +channel-type.nibeheatpump.f470-43108.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f470-43158.label = External Adjustment Activated Via Input S4 +channel-type.nibeheatpump.f470-43159.label = External Adjustment Activated Via Input S3 +channel-type.nibeheatpump.f470-43160.label = External Adjustment Activated Via Input S2 +channel-type.nibeheatpump.f470-43161.label = External Adjustment Activated Via Input S1 +channel-type.nibeheatpump.f470-43180.label = HWC Pump Status GP11 +channel-type.nibeheatpump.f470-43180.description = Hot water circulation pump status. 1=on, 0=off +channel-type.nibeheatpump.f470-43180.state.option.1 = on +channel-type.nibeheatpump.f470-43180.state.option.0 = off +channel-type.nibeheatpump.f470-43239.label = Tot. HW Op.time Add. +channel-type.nibeheatpump.f470-43239.description = Total electric additive operation time in hot water mode +channel-type.nibeheatpump.f470-43383.label = FJVM Relays +channel-type.nibeheatpump.f470-43383.description = Indicates the active relays on the FJVM accessory. The information is binary encoded +channel-type.nibeheatpump.f470-43416.label = Compressor Starts EB100-EP14 +channel-type.nibeheatpump.f470-43416.description = Number of compressorer starts +channel-type.nibeheatpump.f470-43420.label = Tot. Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f470-43420.description = Total compressorer operation time +channel-type.nibeheatpump.f470-43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f470-43424.description = Total compressorer operation time in hot water mode +channel-type.nibeheatpump.f470-43427.label = Compressor State EP14 +channel-type.nibeheatpump.f470-43427.description = 20 = Stopped, 40 = Starting, 60 = Running, 100 = Stopping +channel-type.nibeheatpump.f470-43427.state.option.20 = Stopped +channel-type.nibeheatpump.f470-43427.state.option.40 = Starting +channel-type.nibeheatpump.f470-43427.state.option.60 = Running +channel-type.nibeheatpump.f470-43427.state.option.100 = Stopping +channel-type.nibeheatpump.f470-43431.label = Supply Pump State EP14 +channel-type.nibeheatpump.f470-43431.description = 10=off,15=starting,20=on,40=10-day mode,80=calibration +channel-type.nibeheatpump.f470-43431.state.option.10 = off +channel-type.nibeheatpump.f470-43431.state.option.15 = starting +channel-type.nibeheatpump.f470-43431.state.option.20 = on +channel-type.nibeheatpump.f470-43431.state.option.40 = 10-day mode +channel-type.nibeheatpump.f470-43431.state.option.80 = calibration +channel-type.nibeheatpump.f470-43435.label = Cpr Status EP14 +channel-type.nibeheatpump.f470-43435.description = Status of the compressor. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.f470-43435.state.option.1 = on +channel-type.nibeheatpump.f470-43435.state.option.0 = off +channel-type.nibeheatpump.f470-43435.state.option.0 = Off +channel-type.nibeheatpump.f470-43435.state.option.1 = On +channel-type.nibeheatpump.f470-43460.label = State DEH +channel-type.nibeheatpump.f470-43460.description = The state of the DEH accessory +channel-type.nibeheatpump.f470-43514.label = EB100-EP14 PCA Base Relays +channel-type.nibeheatpump.f470-43514.description = Indicates active relays on the PCA Base card. Please refer to the wiring diagram for relay description. Binary encoded. 1=on, 0=off. Bit0=K4,Bit1=K3,Bit2=K2,Bit3=K1 +channel-type.nibeheatpump.f470-43514.state.option.1 = on +channel-type.nibeheatpump.f470-43514.state.option.0 = off. Bit0 K4 Bit1 K3 Bit2 K2 Bit3 K1 +channel-type.nibeheatpump.f470-43516.label = PCA-Power Relays EP14 +channel-type.nibeheatpump.f470-43516.description = Indicates the active relays on the PCA-Power card. The information is binary encoded +channel-type.nibeheatpump.f470-44331.label = Software Release +channel-type.nibeheatpump.f470-44744.label = Extra Heating System Pump S4 +channel-type.nibeheatpump.f470-44745.label = Extra Heating System Pump S3 +channel-type.nibeheatpump.f470-44746.label = Extra Heating System Pump S2 +channel-type.nibeheatpump.f470-44750.label = FJVM Pump +channel-type.nibeheatpump.f470-44874.label = State SG Ready +channel-type.nibeheatpump.f470-44878.label = SG Ready Input A +channel-type.nibeheatpump.f470-44879.label = SG Ready Input B +channel-type.nibeheatpump.f470-44896.label = Smart Price Adaption Heating Offset +channel-type.nibeheatpump.f470-44897.label = Smart Price Adaption HW Comfort Mode +channel-type.nibeheatpump.f470-44897.description = 0=Eco,1=Normal,2=Luxury,10=Normal+,20=Mini +channel-type.nibeheatpump.f470-44897.state.option.0 = Eco +channel-type.nibeheatpump.f470-44897.state.option.1 = Normal +channel-type.nibeheatpump.f470-44897.state.option.2 = Luxury +channel-type.nibeheatpump.f470-44897.state.option.10 = Normal+ +channel-type.nibeheatpump.f470-44897.state.option.20 = Mini +channel-type.nibeheatpump.f470-44898.label = Smart Price Adaption Pool Offset +channel-type.nibeheatpump.f470-44899.label = Smart Price Adaption Cool Offset +channel-type.nibeheatpump.f470-44908.label = State Smart Price Adaption +channel-type.nibeheatpump.f470-45001.label = Alarm +channel-type.nibeheatpump.f470-45001.description = Indicates the alarm number of the most severe current alarm +channel-type.nibeheatpump.f470-45171.label = Alarm Reset +channel-type.nibeheatpump.f470-45171.description = Reset alarm by setting value 1 +channel-type.nibeheatpump.f470-47004.label = Heat Curve S4 +channel-type.nibeheatpump.f470-47004.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-47005.label = Heat Curve S3 +channel-type.nibeheatpump.f470-47005.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-47006.label = Heat Curve S2 +channel-type.nibeheatpump.f470-47006.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-47007.label = Heat Curve S1 +channel-type.nibeheatpump.f470-47007.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-47008.label = Heat Offset S4 +channel-type.nibeheatpump.f470-47008.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-47009.label = Heat Offset S3 +channel-type.nibeheatpump.f470-47009.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-47010.label = Heat Offset S2 +channel-type.nibeheatpump.f470-47010.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-47011.label = Heat Offset S1 +channel-type.nibeheatpump.f470-47011.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-47012.label = Min Supply System 4 +channel-type.nibeheatpump.f470-47013.label = Min Supply System 3 +channel-type.nibeheatpump.f470-47014.label = Min Supply System 2 +channel-type.nibeheatpump.f470-47015.label = Min Supply System 1 +channel-type.nibeheatpump.f470-47016.label = Max Supply System 4 +channel-type.nibeheatpump.f470-47017.label = Max Supply System 3 +channel-type.nibeheatpump.f470-47018.label = Max Supply System 2 +channel-type.nibeheatpump.f470-47019.label = Max Supply System 1 +channel-type.nibeheatpump.f470-47020.label = Own Heating Curve P7 +channel-type.nibeheatpump.f470-47020.description = User defined heating curve point +channel-type.nibeheatpump.f470-47021.label = Own Heating Curve P6 +channel-type.nibeheatpump.f470-47021.description = User defined heating curve point +channel-type.nibeheatpump.f470-47022.label = Own Heating Curve P5 +channel-type.nibeheatpump.f470-47022.description = User defined heating curve point +channel-type.nibeheatpump.f470-47023.label = Own Heating Curve P4 +channel-type.nibeheatpump.f470-47023.description = User defined heating curve point +channel-type.nibeheatpump.f470-47024.label = Own Heating Curve P3 +channel-type.nibeheatpump.f470-47024.description = User defined heating curve point +channel-type.nibeheatpump.f470-47025.label = Own Heating Curve P2 +channel-type.nibeheatpump.f470-47025.description = User defined heating curve point +channel-type.nibeheatpump.f470-47026.label = Own Heating Curve P1 +channel-type.nibeheatpump.f470-47026.description = User defined heating curve point +channel-type.nibeheatpump.f470-47027.label = Point Offset Outdoor Temp. +channel-type.nibeheatpump.f470-47027.description = Outdoor temperature point where the heat curve is offset +channel-type.nibeheatpump.f470-47028.label = Point Offset +channel-type.nibeheatpump.f470-47028.description = Amount of offset at the point offset temperature +channel-type.nibeheatpump.f470-47029.label = External Adjustment S4 +channel-type.nibeheatpump.f470-47029.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-47030.label = External Adjustment S3 +channel-type.nibeheatpump.f470-47030.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-47031.label = External Adjustment S2 +channel-type.nibeheatpump.f470-47031.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-47032.label = External Adjustment S1 +channel-type.nibeheatpump.f470-47032.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-47033.label = External Adjustment with Room Sensor S4 +channel-type.nibeheatpump.f470-47033.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-47034.label = External Adjustment with Room Sensor S3 +channel-type.nibeheatpump.f470-47034.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-47035.label = External Adjustment with Room Sensor S2 +channel-type.nibeheatpump.f470-47035.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-47036.label = External Adjustment with Room Sensor S1 +channel-type.nibeheatpump.f470-47036.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-47041.label = Hot Water Comfort Mode +channel-type.nibeheatpump.f470-47041.description = Setting in menu 2.2. 0=Economy,1=Normal,2=Luxury,4=Smart Control 0=Economy 1=Normal 2=Luxury +channel-type.nibeheatpump.f470-47041.state.option.0 = Economy +channel-type.nibeheatpump.f470-47041.state.option.1 = Normal +channel-type.nibeheatpump.f470-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f470-47041.state.option.4 = Smart Control +channel-type.nibeheatpump.f470-47041.state.option.0 = Economy +channel-type.nibeheatpump.f470-47041.state.option.1 = Normal +channel-type.nibeheatpump.f470-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f470-47043.label = Start Temperature HW Luxury +channel-type.nibeheatpump.f470-47043.description = Start temperature for heating water +channel-type.nibeheatpump.f470-47044.label = Start Temperature HW Normal +channel-type.nibeheatpump.f470-47044.description = Start temperature for heating water +channel-type.nibeheatpump.f470-47045.label = Start Temperature HW Economy +channel-type.nibeheatpump.f470-47045.description = Start temperature for heating water +channel-type.nibeheatpump.f470-47046.label = Stop Temperature Periodic HW +channel-type.nibeheatpump.f470-47046.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f470-47047.label = Stop Temperature HW Luxury +channel-type.nibeheatpump.f470-47047.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f470-47048.label = Stop Temperature HW Normal +channel-type.nibeheatpump.f470-47048.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f470-47049.label = Stop Temperature HW Economy +channel-type.nibeheatpump.f470-47049.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f470-47050.label = Periodic HW +channel-type.nibeheatpump.f470-47050.description = Activates the periodic hot water generation +channel-type.nibeheatpump.f470-47051.label = Periodic HW Interval +channel-type.nibeheatpump.f470-47051.description = Interval between Periodic hot water sessions +channel-type.nibeheatpump.f470-47054.label = Run Time HWC +channel-type.nibeheatpump.f470-47054.description = Run time for the hot water circulation system +channel-type.nibeheatpump.f470-47055.label = Still Time HWC +channel-type.nibeheatpump.f470-47055.description = Still time for the hot water circulation system +channel-type.nibeheatpump.f470-47131.label = Language +channel-type.nibeheatpump.f470-47131.description = Display language in the heat pump 0=English 1=Svenska 2=Deutsch 3=Francais 4=Espanol 5=Suomi 6=Lietuviu 7=Cesky 8=Polski 9=Nederlands 10=Norsk 11=Dansk 12=Eesti 13=Latviesu 16=Magyar +channel-type.nibeheatpump.f470-47131.state.option.0 = English +channel-type.nibeheatpump.f470-47131.state.option.1 = Svenska +channel-type.nibeheatpump.f470-47131.state.option.2 = Deutsch +channel-type.nibeheatpump.f470-47131.state.option.3 = Francais +channel-type.nibeheatpump.f470-47131.state.option.4 = Espanol +channel-type.nibeheatpump.f470-47131.state.option.5 = Suomi +channel-type.nibeheatpump.f470-47131.state.option.6 = Lietuviu +channel-type.nibeheatpump.f470-47131.state.option.7 = Cesky +channel-type.nibeheatpump.f470-47131.state.option.8 = Polski +channel-type.nibeheatpump.f470-47131.state.option.9 = Nederlands +channel-type.nibeheatpump.f470-47131.state.option.10 = Norsk +channel-type.nibeheatpump.f470-47131.state.option.11 = Dansk +channel-type.nibeheatpump.f470-47131.state.option.12 = Eesti +channel-type.nibeheatpump.f470-47131.state.option.13 = Latviesu +channel-type.nibeheatpump.f470-47131.state.option.16 = Magyar +channel-type.nibeheatpump.f470-47137.label = Operational Mode +channel-type.nibeheatpump.f470-47137.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.f470-47137.state.option.0 = Auto +channel-type.nibeheatpump.f470-47137.state.option.1 = Manual +channel-type.nibeheatpump.f470-47137.state.option.2 = Add. heat only +channel-type.nibeheatpump.f470-47138.label = Operational Mode Heat Medium Pump +channel-type.nibeheatpump.f470-47138.description = 10=Intermittent 20=Continous 30=Economy 40=Auto +channel-type.nibeheatpump.f470-47138.state.option.10 = Intermittent +channel-type.nibeheatpump.f470-47138.state.option.20 = Continous +channel-type.nibeheatpump.f470-47138.state.option.30 = Economy +channel-type.nibeheatpump.f470-47138.state.option.40 = Auto +channel-type.nibeheatpump.f470-47212.label = Max Int Add. Power +channel-type.nibeheatpump.f470-47214.label = Fuse +channel-type.nibeheatpump.f470-47214.description = Size of the fuse that the HP is connected to +channel-type.nibeheatpump.f470-47261.label = Exhaust Fan Speed 4 +channel-type.nibeheatpump.f470-47262.label = Exhaust Fan Speed 3 +channel-type.nibeheatpump.f470-47263.label = Exhaust Fan Speed 2 +channel-type.nibeheatpump.f470-47264.label = Exhaust Fan Speed 1 +channel-type.nibeheatpump.f470-47265.label = Exhaust Fan Speed Normal +channel-type.nibeheatpump.f470-47266.label = Supply Fan Speed 4 +channel-type.nibeheatpump.f470-47267.label = Supply Fan Speed 3 +channel-type.nibeheatpump.f470-47268.label = Supply Fan Speed 2 +channel-type.nibeheatpump.f470-47269.label = Supply Fan Speed 1 +channel-type.nibeheatpump.f470-47270.label = Supply Fan Speed Normal +channel-type.nibeheatpump.f470-47271.label = Fan Return Time 4 +channel-type.nibeheatpump.f470-47271.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f470-47272.label = Fan Return Time 3 +channel-type.nibeheatpump.f470-47272.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f470-47273.label = Fan Return Time 2 +channel-type.nibeheatpump.f470-47273.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f470-47274.label = Fan Return Time 1 +channel-type.nibeheatpump.f470-47274.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f470-47275.label = Filter Reminder Period +channel-type.nibeheatpump.f470-47275.description = Time between the reminder of filter replacement/cleaning. +channel-type.nibeheatpump.f470-47276.label = Floor Drying +channel-type.nibeheatpump.f470-47276.description = 0=Off 1=On +channel-type.nibeheatpump.f470-47277.label = Floor Drying Period 7 +channel-type.nibeheatpump.f470-47277.description = Days each period is active +channel-type.nibeheatpump.f470-47278.label = Floor Drying Period 6 +channel-type.nibeheatpump.f470-47278.description = Days each period is active +channel-type.nibeheatpump.f470-47279.label = Floor Drying Period 5 +channel-type.nibeheatpump.f470-47279.description = Days each period is active +channel-type.nibeheatpump.f470-47280.label = Floor Drying Period 4 +channel-type.nibeheatpump.f470-47280.description = Days each period is active +channel-type.nibeheatpump.f470-47281.label = Floor Drying Period 3 +channel-type.nibeheatpump.f470-47281.description = Days each period is active +channel-type.nibeheatpump.f470-47282.label = Floor Drying Period 2 +channel-type.nibeheatpump.f470-47282.description = Days each period is active +channel-type.nibeheatpump.f470-47283.label = Floor Drying Period 1 +channel-type.nibeheatpump.f470-47283.description = Days each period is active +channel-type.nibeheatpump.f470-47284.label = Floor Drying Temp. 7 +channel-type.nibeheatpump.f470-47284.description = Supply temperature each period +channel-type.nibeheatpump.f470-47285.label = Floor Drying Temp. 6 +channel-type.nibeheatpump.f470-47285.description = Supply temperature each period +channel-type.nibeheatpump.f470-47286.label = Floor Drying Temp. 5 +channel-type.nibeheatpump.f470-47286.description = Supply temperature each period +channel-type.nibeheatpump.f470-47287.label = Floor Drying Temp. 4 +channel-type.nibeheatpump.f470-47287.description = Supply temperature each period +channel-type.nibeheatpump.f470-47288.label = Floor Drying Temp. 3 +channel-type.nibeheatpump.f470-47288.description = Supply temperature each period +channel-type.nibeheatpump.f470-47289.label = Floor Drying Temp. 2 +channel-type.nibeheatpump.f470-47289.description = Supply temperature each period +channel-type.nibeheatpump.f470-47290.label = Floor Drying Temp. 1 +channel-type.nibeheatpump.f470-47290.description = Supply temperature each period +channel-type.nibeheatpump.f470-47291.label = Floor Drying Timer +channel-type.nibeheatpump.f470-47292.label = Trend Temperature +channel-type.nibeheatpump.f470-47292.description = Above the set outdoor temperature the addition activation time is limited to give the compressor more time to raise the hot water temperature. +channel-type.nibeheatpump.f470-47293.label = Transfer Time HW-Heat +channel-type.nibeheatpump.f470-47293.description = Time between hot water and heating operating mode +channel-type.nibeheatpump.f470-47300.label = DOT +channel-type.nibeheatpump.f470-47300.description = Dimensioning outdoor temperature +channel-type.nibeheatpump.f470-47301.label = Delta T At DOT +channel-type.nibeheatpump.f470-47301.description = Delta T (BT12-BT3)at dimensioning outdoor temperature +channel-type.nibeheatpump.f470-47302.label = Climate System 2 Accessory +channel-type.nibeheatpump.f470-47302.description = Activates the climate system 2 accessory 0=Off 1=On +channel-type.nibeheatpump.f470-47303.label = Climate System 3 Accessory +channel-type.nibeheatpump.f470-47303.description = Activates the climate system 3 accessory 0=Off 1=On +channel-type.nibeheatpump.f470-47304.label = Climate System 4 Accessory +channel-type.nibeheatpump.f470-47304.description = Activates the climate system 4 accessory 0=Off 1=On +channel-type.nibeheatpump.f470-47305.label = Climate System 4 Mixing Valve Amp. +channel-type.nibeheatpump.f470-47305.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-47306.label = Climate System 3 Mixing Valve Amp. +channel-type.nibeheatpump.f470-47306.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-47307.label = Climate System 2 Mixing Valve Amp. +channel-type.nibeheatpump.f470-47307.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-47308.label = Climate System 4 Shunt Wait +channel-type.nibeheatpump.f470-47308.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-47309.label = Climate System 3 Shunt Wait +channel-type.nibeheatpump.f470-47309.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-47310.label = Climate System 2 Shunt Wait +channel-type.nibeheatpump.f470-47310.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-47351.label = FJVM Accessory +channel-type.nibeheatpump.f470-47351.description = Activates the FJVM accessory 0=Off 1=On +channel-type.nibeheatpump.f470-47352.label = SMS40 Accessory +channel-type.nibeheatpump.f470-47352.description = Activates the SMS40 accessory +channel-type.nibeheatpump.f470-47365.label = RMU System 1 +channel-type.nibeheatpump.f470-47365.description = Activates the RMU accessory for system 1 +channel-type.nibeheatpump.f470-47366.label = RMU System 2 +channel-type.nibeheatpump.f470-47366.description = Activates the RMU accessory for system 2 +channel-type.nibeheatpump.f470-47367.label = RMU System 3 +channel-type.nibeheatpump.f470-47367.description = Activates the RMU accessory for system 3 +channel-type.nibeheatpump.f470-47368.label = RMU System 4 +channel-type.nibeheatpump.f470-47368.description = Activates the RMU accessory for system 4 +channel-type.nibeheatpump.f470-47370.label = Allow Additive Heating +channel-type.nibeheatpump.f470-47370.description = Whether to allow additive heating (only valid for operational mode Manual) +channel-type.nibeheatpump.f470-47371.label = Allow Heating +channel-type.nibeheatpump.f470-47371.description = Whether to allow heating (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f470-47372.label = Allow Cooling +channel-type.nibeheatpump.f470-47372.description = Whether to allow cooling (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f470-47374.label = Start Temperature Cooling +channel-type.nibeheatpump.f470-47374.description = Start temperature for cooling, as set in menu 4.9.2 0=Off 1=On +channel-type.nibeheatpump.f470-47374.state.option.0 = Off +channel-type.nibeheatpump.f470-47374.state.option.1 = On +channel-type.nibeheatpump.f470-47375.label = Stop Temperature Heating +channel-type.nibeheatpump.f470-47375.description = Stop temperature for heating, as set in menu 4.9.2 +channel-type.nibeheatpump.f470-47376.label = Stop Temperature Additive +channel-type.nibeheatpump.f470-47376.description = Stop temperature for additive, as set in menu 4.9.2 +channel-type.nibeheatpump.f470-47377.label = Outdoor Filter Time +channel-type.nibeheatpump.f470-47377.description = 12=12 Hours 24=24 Hours +channel-type.nibeheatpump.f470-47377.state.option.12 = Hours 24 +channel-type.nibeheatpump.f470-47377.state.option.24 = Hours +channel-type.nibeheatpump.f470-47378.label = Max Diff. Comp. +channel-type.nibeheatpump.f470-47379.label = Max Diff. Add. +channel-type.nibeheatpump.f470-47384.label = Date Format +channel-type.nibeheatpump.f470-47384.description = 1=DD-MM-YY 2=YY-MM-DD +channel-type.nibeheatpump.f470-47384.state.option.1 = DD-MM-YY +channel-type.nibeheatpump.f470-47384.state.option.2 = YY-MM-DD +channel-type.nibeheatpump.f470-47385.label = Time Format +channel-type.nibeheatpump.f470-47385.description = 12=12 hours 24=24 Hours +channel-type.nibeheatpump.f470-47385.state.option.12 = hours 24 +channel-type.nibeheatpump.f470-47385.state.option.24 = Hours +channel-type.nibeheatpump.f470-47387.label = HW Production +channel-type.nibeheatpump.f470-47387.description = Activates hot water production where applicable 0=Off 1=On +channel-type.nibeheatpump.f470-47388.label = Alarm Lower Room Temp. +channel-type.nibeheatpump.f470-47388.description = Lowers the room temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f470-47389.label = Alarm Lower HW Temp. +channel-type.nibeheatpump.f470-47389.description = Lowers the hot water temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f470-47391.label = Use Room Sensor S4 +channel-type.nibeheatpump.f470-47391.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f470-47392.label = Use Room Sensor S3 +channel-type.nibeheatpump.f470-47392.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f470-47393.label = Use Room Sensor S2 +channel-type.nibeheatpump.f470-47393.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f470-47394.label = Use Room Sensor S1 +channel-type.nibeheatpump.f470-47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f470-47395.label = Room Sensor Setpoint S4 +channel-type.nibeheatpump.f470-47395.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-47396.label = Room Sensor Setpoint S3 +channel-type.nibeheatpump.f470-47396.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-47397.label = Room Sensor Setpoint S2 +channel-type.nibeheatpump.f470-47397.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-47398.label = Room Sensor Setpoint S1 +channel-type.nibeheatpump.f470-47398.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-47399.label = Room Sensor Factor S4 +channel-type.nibeheatpump.f470-47399.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-47400.label = Room Sensor Factor S3 +channel-type.nibeheatpump.f470-47400.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-47401.label = Room Sensor Factor S2 +channel-type.nibeheatpump.f470-47401.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-47402.label = Room Sensor Factor S1 +channel-type.nibeheatpump.f470-47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-47442.label = Preset Flow Clim. Sys. +channel-type.nibeheatpump.f470-47442.description = Preset flow setting for climate system. 0 = manual setting, 1 = radiator, 2 = floor heating, 3 = radiator + floor heating. +channel-type.nibeheatpump.f470-47442.state.option.0 = manual setting +channel-type.nibeheatpump.f470-47442.state.option.1 = radiator +channel-type.nibeheatpump.f470-47442.state.option.2 = floor heating +channel-type.nibeheatpump.f470-47442.state.option.3 = radiator + floor heating. +channel-type.nibeheatpump.f470-47525.label = Heat Curve S8 +channel-type.nibeheatpump.f470-47525.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-47536.label = Fan Synch Mode +channel-type.nibeheatpump.f470-47536.description = If the fan should have a lower speed when the compressor is not running 0=Off 1=On +channel-type.nibeheatpump.f470-47537.label = Night Cooling +channel-type.nibeheatpump.f470-47537.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. 0=Off 1=On +channel-type.nibeheatpump.f470-47538.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f470-47539.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f470-47539.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f470-47556.label = DEH Accessory +channel-type.nibeheatpump.f470-47556.description = Activates the DEH accessory +channel-type.nibeheatpump.f470-47564.label = Allow Heating Sys1 +channel-type.nibeheatpump.f470-47564.description = Whether to allow heating for system 1 (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f470-47565.label = Allow Heating Sys2 +channel-type.nibeheatpump.f470-47565.description = Whether to allow heating for system 2 (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f470-47567.label = Heat Curve S7 +channel-type.nibeheatpump.f470-47567.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-48043.label = Holiday - Activated +channel-type.nibeheatpump.f470-48043.description = 0=inactive, 10=active +channel-type.nibeheatpump.f470-48043.state.option.0 = inactive +channel-type.nibeheatpump.f470-48043.state.option.10 = active +channel-type.nibeheatpump.f470-48132.label = Temporary Lux +channel-type.nibeheatpump.f470-48132.description = 0=Off, 1=3h, 2=6h, 3=12h, 4=One time increase +channel-type.nibeheatpump.f470-48132.state.option.0 = Off +channel-type.nibeheatpump.f470-48132.state.option.1 = 3h +channel-type.nibeheatpump.f470-48132.state.option.2 = 6h +channel-type.nibeheatpump.f470-48132.state.option.3 = 12h +channel-type.nibeheatpump.f470-48132.state.option.4 = One time increase +channel-type.nibeheatpump.f470-48282.label = SG Ready Heating +channel-type.nibeheatpump.f470-48282.description = Sets whether or not SG Ready should affect heating +channel-type.nibeheatpump.f470-48283.label = SG Ready Cooling +channel-type.nibeheatpump.f470-48283.description = Sets whether or not SG Ready should affect cooling +channel-type.nibeheatpump.f470-48284.label = SG Ready Hot Water +channel-type.nibeheatpump.f470-48284.description = Sets whether or not SG Ready should affect hot water +channel-type.nibeheatpump.f470-48285.label = SG Ready Pool +channel-type.nibeheatpump.f470-48285.description = Sets whether or not SG Ready should affect pool +channel-type.nibeheatpump.f470-48488.label = Heat Curve S6 +channel-type.nibeheatpump.f470-48488.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-48489.label = Heat Curve S5 +channel-type.nibeheatpump.f470-48489.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f470-48491.label = Heat Offset S8 +channel-type.nibeheatpump.f470-48491.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-48492.label = Heat Offset S7 +channel-type.nibeheatpump.f470-48492.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-48493.label = Heat Offset S6 +channel-type.nibeheatpump.f470-48493.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-48494.label = Heat Offset S5 +channel-type.nibeheatpump.f470-48494.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f470-48495.label = Min Supply System 8 +channel-type.nibeheatpump.f470-48496.label = Min Supply System 7 +channel-type.nibeheatpump.f470-48497.label = Min Supply System 6 +channel-type.nibeheatpump.f470-48498.label = Min Supply System 5 +channel-type.nibeheatpump.f470-48499.label = Max Supply System 8 +channel-type.nibeheatpump.f470-48500.label = Max Supply System 7 +channel-type.nibeheatpump.f470-48501.label = Max Supply System 6 +channel-type.nibeheatpump.f470-48502.label = Max Supply System 5 +channel-type.nibeheatpump.f470-48503.label = External Adjustment S8 +channel-type.nibeheatpump.f470-48503.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-48504.label = External Adjustment S7 +channel-type.nibeheatpump.f470-48504.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-48505.label = External Adjustment S6 +channel-type.nibeheatpump.f470-48505.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-48506.label = External Adjustment S5 +channel-type.nibeheatpump.f470-48506.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f470-48507.label = External Adjustment with Room Sensor S8 +channel-type.nibeheatpump.f470-48507.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-48508.label = External Adjustment with Room Sensor S7 +channel-type.nibeheatpump.f470-48508.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-48509.label = External Adjustment with Room Sensor S6 +channel-type.nibeheatpump.f470-48509.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-48510.label = External Adjustment with Room Sensor S5 +channel-type.nibeheatpump.f470-48510.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f470-48569.label = Climate System 5 Accessory +channel-type.nibeheatpump.f470-48569.description = Activates the climate system 5 accessory +channel-type.nibeheatpump.f470-48570.label = Climate System 6 Accessory +channel-type.nibeheatpump.f470-48570.description = Activates the climate system 6 accessory +channel-type.nibeheatpump.f470-48571.label = Climate System 7 Accessory +channel-type.nibeheatpump.f470-48571.description = Activates the climate system 7 accessory +channel-type.nibeheatpump.f470-48572.label = Climate System 8 Accessory +channel-type.nibeheatpump.f470-48572.description = Activates the climate system 8 accessory +channel-type.nibeheatpump.f470-48573.label = Climate System 8 Mixing Valve Amp. +channel-type.nibeheatpump.f470-48573.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-48574.label = Climate System 7 Mixing Valve Amp. +channel-type.nibeheatpump.f470-48574.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-48575.label = Climate System 6 Mixing Valve Amp. +channel-type.nibeheatpump.f470-48575.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-48576.label = Climate System 5 Mixing Valve Amp. +channel-type.nibeheatpump.f470-48576.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f470-48577.label = Climate System 8 Shunt Wait +channel-type.nibeheatpump.f470-48577.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-48578.label = Climate System 7 Shunt Wait +channel-type.nibeheatpump.f470-48578.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-48579.label = Climate System 6 Shunt Wait +channel-type.nibeheatpump.f470-48579.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-48580.label = Climate System 5 Shunt Wait +channel-type.nibeheatpump.f470-48580.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f470-48675.label = Use Room Sensor S8 +channel-type.nibeheatpump.f470-48675.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f470-48676.label = Use Room Sensor S7 +channel-type.nibeheatpump.f470-48676.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f470-48677.label = Use Room Sensor S6 +channel-type.nibeheatpump.f470-48677.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f470-48678.label = Use Room Sensor S5 +channel-type.nibeheatpump.f470-48678.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f470-48680.label = Room Sensor Setpoint S8 +channel-type.nibeheatpump.f470-48680.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-48681.label = Room Sensor Setpoint S7 +channel-type.nibeheatpump.f470-48681.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-48682.label = Room Sensor Setpoint S6 +channel-type.nibeheatpump.f470-48682.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-48683.label = Room Sensor Setpoint S5 +channel-type.nibeheatpump.f470-48683.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f470-48685.label = Room Sensor Factor S8 +channel-type.nibeheatpump.f470-48685.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-48686.label = Room Sensor Factor S7 +channel-type.nibeheatpump.f470-48686.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-48687.label = Room Sensor Factor S6 +channel-type.nibeheatpump.f470-48687.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-48688.label = Room Sensor Factor S5 +channel-type.nibeheatpump.f470-48688.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f470-48732.label = Cool Offset S8 +channel-type.nibeheatpump.f470-48732.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48733.label = Cool Offset S7 +channel-type.nibeheatpump.f470-48733.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48734.label = Cool Offset S6 +channel-type.nibeheatpump.f470-48734.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48735.label = Cool Offset S5 +channel-type.nibeheatpump.f470-48735.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48736.label = Cool Offset S4 +channel-type.nibeheatpump.f470-48736.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48737.label = Cool Offset S3 +channel-type.nibeheatpump.f470-48737.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48738.label = Cool Offset S2 +channel-type.nibeheatpump.f470-48738.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48739.label = Cool Offset S1 +channel-type.nibeheatpump.f470-48739.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f470-48755.label = Transformer Ratio +channel-type.nibeheatpump.f470-48755.description = Ratio of the current measurement transformers +channel-type.nibeheatpump.f470-48794.label = RH Set Value +channel-type.nibeheatpump.f470-48794.description = RH set value +channel-type.nibeheatpump.f470-48810.label = Prevent Humidity S8 +channel-type.nibeheatpump.f470-48811.label = Prevent Humidity S7 +channel-type.nibeheatpump.f470-48812.label = Prevent Humidity S6 +channel-type.nibeheatpump.f470-48813.label = Prevent Humidity S5 +channel-type.nibeheatpump.f470-48814.label = Prevent Humidity S4 +channel-type.nibeheatpump.f470-48815.label = Prevent Humidity S3 +channel-type.nibeheatpump.f470-48816.label = Prevent Humidity S2 +channel-type.nibeheatpump.f470-48817.label = Prevent Humidity S1 +channel-type.nibeheatpump.f470-48889.label = MODBUS40 Disable LOG.SET +channel-type.nibeheatpump.f470-48889.description = If set, the system will ignore the existing LOG.SET on the USB stick.1=ignore LOG.SET,0=use LOG.SET +channel-type.nibeheatpump.f470-48926.label = Humidity Factor +channel-type.nibeheatpump.f470-48926.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature. +channel-type.nibeheatpump.f470-48927.label = Humidity Cool Factor +channel-type.nibeheatpump.f470-48927.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f470-48930.label = EME10 Activated +channel-type.nibeheatpump.f470-48930.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f470-48931.label = EME PV Panel Affect Heating +channel-type.nibeheatpump.f470-48931.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f470-48932.label = EME PV Panel Affect Hot Water +channel-type.nibeheatpump.f470-48932.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f470-48968.label = FLM 1 Set Point, Cooling +channel-type.nibeheatpump.f470-48968.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f470-48970.label = Outdoor Air Mixing Function +channel-type.nibeheatpump.f470-48970.description = Activates the Outdoor Air Mixing function. +channel-type.nibeheatpump.f470-48976.label = Smart Home Room Control +channel-type.nibeheatpump.f470-49289.label = Ground Water Pump Speed Control +channel-type.nibeheatpump.f470-49297.label = EME20 Activated +channel-type.nibeheatpump.f470-49297.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f470-49298.label = EME PV Panel Affect Pool +channel-type.nibeheatpump.f470-49298.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f470-49298.state.option.0 = not affecting +channel-type.nibeheatpump.f470-49298.state.option.1 = affecting +channel-type.nibeheatpump.f470-49358.label = Night Cooling +channel-type.nibeheatpump.f470-49358.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f470-49359.label = Night Cooling +channel-type.nibeheatpump.f470-49359.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f470-49360.label = Night Cooling +channel-type.nibeheatpump.f470-49360.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f470-49361.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f470-49362.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f470-49363.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f470-49364.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f470-49364.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f470-49365.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f470-49365.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f470-49366.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f470-49366.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f470-49431.label = Stop Temperature Supply Air Heating +channel-type.nibeheatpump.f470-49431.description = Stop temperature for supply air heating +channel-type.nibeheatpump.f750-32260.label = NIBE Inverter 216-state +channel-type.nibeheatpump.f750-40004.label = BT1 Outdoor Temperature +channel-type.nibeheatpump.f750-40004.description = Current outdoor temperature +channel-type.nibeheatpump.f750-40005.label = EP23-BT2 Supply Temp S4 +channel-type.nibeheatpump.f750-40005.description = Supply temperature for system 4 +channel-type.nibeheatpump.f750-40006.label = EP22-BT2 Supply Temp S3 +channel-type.nibeheatpump.f750-40006.description = Supply temperature for system 3 +channel-type.nibeheatpump.f750-40007.label = EP21-BT2 Supply Temp S2 +channel-type.nibeheatpump.f750-40007.description = Supply temperature for system 2 +channel-type.nibeheatpump.f750-40008.label = BT2 Supply Temp S1 +channel-type.nibeheatpump.f750-40008.description = Supply temperature for system 1 +channel-type.nibeheatpump.f750-40012.label = EB100-EP14-BT3 Return Temp +channel-type.nibeheatpump.f750-40012.description = Return temperature +channel-type.nibeheatpump.f750-40013.label = BT7 HW Top +channel-type.nibeheatpump.f750-40013.description = Hot water top temperature, BT7 +channel-type.nibeheatpump.f750-40014.label = BT6 HW Load +channel-type.nibeheatpump.f750-40014.description = Hot water load temperature, BT6 +channel-type.nibeheatpump.f750-40017.label = EB100-EP14-BT12 Condensor Out +channel-type.nibeheatpump.f750-40017.description = Condensor out temperature, BT12 +channel-type.nibeheatpump.f750-40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.f750-40018.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.f750-40019.label = EB100-EP14-BT15 Liquid Line +channel-type.nibeheatpump.f750-40019.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.f750-40020.label = EB100-BT16 Evaporator Temp +channel-type.nibeheatpump.f750-40022.label = EB100-EP14-BT17 Suction +channel-type.nibeheatpump.f750-40022.description = Suction temperature, BT17 +channel-type.nibeheatpump.f750-40025.label = BT20 Exhaust Air Temp. 1 +channel-type.nibeheatpump.f750-40026.label = BT21 Vented Air Temp. 1 +channel-type.nibeheatpump.f750-40030.label = EP23-BT50 Room Temp S4 +channel-type.nibeheatpump.f750-40031.label = EP22-BT50 Room Temp S3 +channel-type.nibeheatpump.f750-40032.label = EP21-BT50 Room Temp S2 +channel-type.nibeheatpump.f750-40033.label = BT50 Room Temp S1 +channel-type.nibeheatpump.f750-40043.label = BT53 Solar Panel Temp +channel-type.nibeheatpump.f750-40043.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f750-40044.label = BT54 Solar Load Temp +channel-type.nibeheatpump.f750-40044.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.f750-40047.label = EB100-BT61 Supply Radiator Temp +channel-type.nibeheatpump.f750-40048.label = EB100-BT62 Return Radiator Temp +channel-type.nibeheatpump.f750-40050.label = EB100-BS1 Air Flow +channel-type.nibeheatpump.f750-40051.label = EB100-BS1 Air Flow Unfiltered +channel-type.nibeheatpump.f750-40051.description = Unfiltered air flow value +channel-type.nibeheatpump.f750-40054.label = EB100-FD1 Temperature Limiter +channel-type.nibeheatpump.f750-40067.label = BT1 Average +channel-type.nibeheatpump.f750-40067.description = EB100-BT1 Outdoor temperature average +channel-type.nibeheatpump.f750-40071.label = BT25 Ext. Supply +channel-type.nibeheatpump.f750-40071.description = External supply temperature, BT25 +channel-type.nibeheatpump.f750-40072.label = BF1 EP14 Flow +channel-type.nibeheatpump.f750-40072.description = Current flow EP14|Current flow EP15 +channel-type.nibeheatpump.f750-40074.label = EB100-FR1 Anode Status +channel-type.nibeheatpump.f750-40077.label = BT6 External Water Heater Load Temp. +channel-type.nibeheatpump.f750-40077.description = Used in DEW, SCA and AHPS Docking accessories +channel-type.nibeheatpump.f750-40078.label = BT7 External Water Heater Top Temp. +channel-type.nibeheatpump.f750-40078.description = Used in DEW, SCA and AHPS Docking accessories +channel-type.nibeheatpump.f750-40079.label = EB100-BE3 Current +channel-type.nibeheatpump.f750-40081.label = EB100-BE2 Current +channel-type.nibeheatpump.f750-40083.label = EB100-BE1 Current +channel-type.nibeheatpump.f750-40122.label = BT52 External Water Heater Load Temp. +channel-type.nibeheatpump.f750-40122.description = Used in DEH and AHPS Docking accessories +channel-type.nibeheatpump.f750-40127.label = EP23-BT3 Return Temp S4 +channel-type.nibeheatpump.f750-40127.description = Return temperature for system 4 +channel-type.nibeheatpump.f750-40128.label = EP22-BT3 Return Temp S3 +channel-type.nibeheatpump.f750-40128.description = Return temperature for system 3 +channel-type.nibeheatpump.f750-40129.label = EP21-BT3 Return Temp S2 +channel-type.nibeheatpump.f750-40129.description = Return temperature for system 2 +channel-type.nibeheatpump.f750-40141.label = AZ2-BT22 Supply Air Temp. SAM +channel-type.nibeheatpump.f750-40142.label = AZ2-BT23 Outdoor Temp. SAM +channel-type.nibeheatpump.f750-40143.label = AZ2-BT68 Flow Temp. SAM +channel-type.nibeheatpump.f750-40143.description = Heat medium flow temperature to SAM module +channel-type.nibeheatpump.f750-40144.label = AZ2-BT69 Return Temp. SAM +channel-type.nibeheatpump.f750-40144.description = Heat medium return temperature from SAM module +channel-type.nibeheatpump.f750-40157.label = EP30-BT53 Solar Panel Temp +channel-type.nibeheatpump.f750-40158.label = EP30-BT54 Solar Load Temp +channel-type.nibeheatpump.f750-40159.label = EP47-BT2 Supply Temp S8 +channel-type.nibeheatpump.f750-40159.description = Supply temperature for system 8 +channel-type.nibeheatpump.f750-40160.label = EP46-BT2 Supply Temp S7 +channel-type.nibeheatpump.f750-40160.description = Supply temperature for system 7 +channel-type.nibeheatpump.f750-40161.label = EP45-BT2 Supply Temp S6 +channel-type.nibeheatpump.f750-40161.description = Supply temperature for system 6 +channel-type.nibeheatpump.f750-40162.label = EP44-BT2 Supply Temp S5 +channel-type.nibeheatpump.f750-40162.description = Supply temperature for system 5 +channel-type.nibeheatpump.f750-40163.label = EP47-BT3 Return Temp S8 +channel-type.nibeheatpump.f750-40163.description = Return temperature for system 8 +channel-type.nibeheatpump.f750-40164.label = EP46-BT3 Return Temp S7 +channel-type.nibeheatpump.f750-40164.description = Return temperature for system 7 +channel-type.nibeheatpump.f750-40165.label = EP45-BT3 Return Temp S6 +channel-type.nibeheatpump.f750-40165.description = Return temperature for system 6 +channel-type.nibeheatpump.f750-40166.label = EP44-BT3 Return Temp S5 +channel-type.nibeheatpump.f750-40166.description = Return temperature for system 5 +channel-type.nibeheatpump.f750-40167.label = EP47-BT50 Room Temp S8 +channel-type.nibeheatpump.f750-40168.label = EP46-BT50 Room Temp S7 +channel-type.nibeheatpump.f750-40169.label = EP45-BT50 Room Temp S6 +channel-type.nibeheatpump.f750-40170.label = EP44-BT50 Room Temp S5 +channel-type.nibeheatpump.f750-40185.label = BT1 Average, 1h +channel-type.nibeheatpump.f750-40185.description = EB100-BT1 Outdoor temperature average, 1h +channel-type.nibeheatpump.f750-40188.label = EP47-BT50 Room Temp S8 Average +channel-type.nibeheatpump.f750-40189.label = EP46-BT50 Room Temp S7 Average +channel-type.nibeheatpump.f750-40190.label = EP45-BT50 Room Temp S6 Average +channel-type.nibeheatpump.f750-40191.label = EP44-BT50 Room Temp S5 Average +channel-type.nibeheatpump.f750-40192.label = EP23-BT50 Room Temp S4 Average +channel-type.nibeheatpump.f750-40193.label = EP22-BT50 Room Temp S3 Average +channel-type.nibeheatpump.f750-40194.label = EP21-BT50 Room Temp S2 Average +channel-type.nibeheatpump.f750-40195.label = BT50 Room Temp S1 Average +channel-type.nibeheatpump.f750-40212.label = BT74 Average +channel-type.nibeheatpump.f750-40212.description = BT74 heating cooling sensor average +channel-type.nibeheatpump.f750-40217.label = Calc. Supply S8 +channel-type.nibeheatpump.f750-40217.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-40218.label = Calc. Supply S7 +channel-type.nibeheatpump.f750-40218.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-40219.label = Calc. Supply S6 +channel-type.nibeheatpump.f750-40219.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-40220.label = Calculated Supply S5 +channel-type.nibeheatpump.f750-40220.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-40305.label = Mixing Valve State S8 +channel-type.nibeheatpump.f750-40305.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-40306.label = Mixing Valve State S7 +channel-type.nibeheatpump.f750-40306.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-40307.label = Mixing Valve State S6 +channel-type.nibeheatpump.f750-40307.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-40308.label = Mixing Valve State S5 +channel-type.nibeheatpump.f750-40308.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-40316.label = Inverter Limit Status +channel-type.nibeheatpump.f750-40317.label = Inverter Drive Status +channel-type.nibeheatpump.f750-40321.label = Compressor Frequency, Request +channel-type.nibeheatpump.f750-40321.description = The compressor frequency that has been requested by the system +channel-type.nibeheatpump.f750-40322.label = Max Compressor Frequency, Heating +channel-type.nibeheatpump.f750-40322.description = The maximum frequency of the compressor in heating mode +channel-type.nibeheatpump.f750-40323.label = Inverter Alarm Code +channel-type.nibeheatpump.f750-40324.label = Inverter Fault Code +channel-type.nibeheatpump.f750-40326.label = Inverter Drive Command +channel-type.nibeheatpump.f750-40327.label = NIBE Inverter Pic Version +channel-type.nibeheatpump.f750-40328.label = NIBE Inverter 8051 Version +channel-type.nibeheatpump.f750-40329.label = NIBE Inverter Def. Wizard +channel-type.nibeheatpump.f750-40330.label = NIBE Inverter Mce Version +channel-type.nibeheatpump.f750-40331.label = NIBE Inverter Hw Version +channel-type.nibeheatpump.f750-40332.label = NIBE Inverter Hw Type +channel-type.nibeheatpump.f750-40339.label = External Adjustment Activated Via Input S8 +channel-type.nibeheatpump.f750-40340.label = External Adjustment Activated Via Input S7 +channel-type.nibeheatpump.f750-40341.label = External Adjustment Activated Via Input S6 +channel-type.nibeheatpump.f750-40342.label = External Adjustment Activated Via Input S5 +channel-type.nibeheatpump.f750-40364.label = AHPS Docking Blocked +channel-type.nibeheatpump.f750-40364.description = 0 = unblocked, 1 = blocked +channel-type.nibeheatpump.f750-40364.state.option.0 = unblocked +channel-type.nibeheatpump.f750-40364.state.option.1 = blocked +channel-type.nibeheatpump.f750-40365.label = Extra Heating System Pump S8 +channel-type.nibeheatpump.f750-40366.label = Extra Heating System Pump S7 +channel-type.nibeheatpump.f750-40367.label = Extra Heating System Pump S6 +channel-type.nibeheatpump.f750-40368.label = Extra Heating System Pump S5 +channel-type.nibeheatpump.f750-40370.label = AHPS Docking Accessory Relays +channel-type.nibeheatpump.f750-40370.description = 0=Off, 1=On. b0:EM1-GP4, b1:Cool need, b2:QN32, b3:QN11 close, b4:EP30-GP4, b5:QN11 open ,b6:Ext add +channel-type.nibeheatpump.f750-40370.state.option.0 = Off +channel-type.nibeheatpump.f750-40370.state.option.1 = On. b0:EM1-GP4 b1:Cool need b2:QN32 b3:QN11 close b4:EP30-GP4 b5:QN11 open b6:Ext add +channel-type.nibeheatpump.f750-40755.label = Tot. Ext. HW Add Op.time +channel-type.nibeheatpump.f750-40755.description = Total external hw-electric additive operation time +channel-type.nibeheatpump.f750-40760.label = Hz Unlimited +channel-type.nibeheatpump.f750-40762.label = Reg. State AHPS Docking Shunt +channel-type.nibeheatpump.f750-40762.description = 10 = Off, 20 = Running +channel-type.nibeheatpump.f750-40762.state.option.10 = Off +channel-type.nibeheatpump.f750-40762.state.option.20 = Running +channel-type.nibeheatpump.f750-40763.label = AHPS Docking Calc. Supply Temp. +channel-type.nibeheatpump.f750-40771.label = Heat Meter - Pool2 Cpr EP14 +channel-type.nibeheatpump.f750-40771.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-40868.label = +Adjust AUX Port +channel-type.nibeheatpump.f750-40870.label = +Adjust OP Mode +channel-type.nibeheatpump.f750-40870.description = Tells if plusadjust system calls for heat or cool +channel-type.nibeheatpump.f750-40871.label = +Adjust Comfort Mode +channel-type.nibeheatpump.f750-40871.description = Which comfort mode +channel-type.nibeheatpump.f750-40872.label = +Adjust Parallell Adjustment +channel-type.nibeheatpump.f750-40872.description = requested adjustment +channel-type.nibeheatpump.f750-40873.label = +Adjust Humidity +channel-type.nibeheatpump.f750-40873.description = Humidity +channel-type.nibeheatpump.f750-40874.label = +Adjust Temp Indoor +channel-type.nibeheatpump.f750-40874.description = Average of all room sensors +channel-type.nibeheatpump.f750-40875.label = +Adjust Temp Outdoor +channel-type.nibeheatpump.f750-40875.description = Outdoor temp +channel-type.nibeheatpump.f750-40876.label = +Adjust Version +channel-type.nibeheatpump.f750-40876.description = PCA input version +channel-type.nibeheatpump.f750-40877.label = +Adjust Activated +channel-type.nibeheatpump.f750-40877.description = If plusadjust accessory is activated +channel-type.nibeheatpump.f750-40878.label = +Adjust Need +channel-type.nibeheatpump.f750-40878.description = If plusadjust system calls for heat +channel-type.nibeheatpump.f750-40879.label = +Adjust Parallell Factor +channel-type.nibeheatpump.f750-40880.label = +Adjust Max Change +channel-type.nibeheatpump.f750-40880.description = Largest allowed change +channel-type.nibeheatpump.f750-40881.label = +Adjust Affect System8 +channel-type.nibeheatpump.f750-40881.description = System affected by paralell change +channel-type.nibeheatpump.f750-40882.label = +Adjust Affect System7 +channel-type.nibeheatpump.f750-40882.description = System affected by paralell change +channel-type.nibeheatpump.f750-40883.label = +Adjust Affect System6 +channel-type.nibeheatpump.f750-40883.description = System affected by paralell change +channel-type.nibeheatpump.f750-40884.label = +Adjust Affect System5 +channel-type.nibeheatpump.f750-40884.description = System affected by paralell change +channel-type.nibeheatpump.f750-40885.label = +Adjust Affect System4 +channel-type.nibeheatpump.f750-40885.description = System affected by paralell change +channel-type.nibeheatpump.f750-40886.label = +Adjust Affect System3 +channel-type.nibeheatpump.f750-40886.description = System affected by paralell change +channel-type.nibeheatpump.f750-40887.label = +Adjust Affect System2 +channel-type.nibeheatpump.f750-40887.description = System affected by paralell change +channel-type.nibeheatpump.f750-40888.label = +Adjust Affect System1 +channel-type.nibeheatpump.f750-40888.description = System affected by paralell change +channel-type.nibeheatpump.f750-40889.label = BT64 Average +channel-type.nibeheatpump.f750-40889.description = BT64 Cooling supply average +channel-type.nibeheatpump.f750-40918.label = EB100-FD3 Temperature Limiter +channel-type.nibeheatpump.f750-40932.label = Kind of Defrost +channel-type.nibeheatpump.f750-40932.description = Kind of defrost: 0 = No defrost, 1 = Passive defrost, 2 = Active defrost +channel-type.nibeheatpump.f750-40932.state.option.0 = No defrost +channel-type.nibeheatpump.f750-40932.state.option.1 = Passive defrost +channel-type.nibeheatpump.f750-40932.state.option.2 = Active defrost +channel-type.nibeheatpump.f750-40934.label = Active Defrosting Time +channel-type.nibeheatpump.f750-40934.description = Calculated time for active defrosting of the compressor. +channel-type.nibeheatpump.f750-40935.label = Passive Defrosting Time +channel-type.nibeheatpump.f750-40935.description = Calculated time for passive defrosting of the compressor. +channel-type.nibeheatpump.f750-40940.label = Degree Minutes (32 Bit) +channel-type.nibeheatpump.f750-40940.description = Degree minutes, 32bit value. Full resolution. +channel-type.nibeheatpump.f750-40993.label = Inverter Min Speed +channel-type.nibeheatpump.f750-40994.label = Inverter Max Speed +channel-type.nibeheatpump.f750-40995.label = External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.f750-40997.label = External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.f750-41026.label = EB100-Adjusted BS1 Air Flow +channel-type.nibeheatpump.f750-41027.label = Humidity Average +channel-type.nibeheatpump.f750-41027.description = Humidity average +channel-type.nibeheatpump.f750-41189.label = AA20-BE5 EME10 Current +channel-type.nibeheatpump.f750-41190.label = AA20-BE5 EME10 Average Current +channel-type.nibeheatpump.f750-41191.label = PV Panel State +channel-type.nibeheatpump.f750-41214.label = OEK Accessory Block Status +channel-type.nibeheatpump.f750-41214.description = Indicates if the OEK accessory is externally blocked. +channel-type.nibeheatpump.f750-41256.label = Fan Speed Current +channel-type.nibeheatpump.f750-41256.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f750-41257.label = Fan Speed Current +channel-type.nibeheatpump.f750-41257.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f750-41258.label = Fan Speed Current +channel-type.nibeheatpump.f750-41258.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f750-41265.label = Smart Home Mode +channel-type.nibeheatpump.f750-41265.description = Current smart home mode, 0=Default,1=Away from home,2=Vacation +channel-type.nibeheatpump.f750-41265.state.option.0 = Default +channel-type.nibeheatpump.f750-41265.state.option.1 = Away from home +channel-type.nibeheatpump.f750-41265.state.option.2 = Vacation +channel-type.nibeheatpump.f750-41266.label = Offset to Smart Home System +channel-type.nibeheatpump.f750-41266.description = Offset to smart home system +channel-type.nibeheatpump.f750-41267.label = Smart Home Ctrl Syst 8 +channel-type.nibeheatpump.f750-41267.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41268.label = Smart Home Ctrl Syst 7 +channel-type.nibeheatpump.f750-41268.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41269.label = Smart Home Ctrl Syst 6 +channel-type.nibeheatpump.f750-41269.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41270.label = Smart Home Ctrl Syst 5 +channel-type.nibeheatpump.f750-41270.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41271.label = Smart Home Ctrl Syst 4 +channel-type.nibeheatpump.f750-41271.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41272.label = Smart Home Ctrl Syst 3 +channel-type.nibeheatpump.f750-41272.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41273.label = Smart Home Ctrl Syst 2 +channel-type.nibeheatpump.f750-41273.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41274.label = Smart Home Ctrl Syst 1 +channel-type.nibeheatpump.f750-41274.description = Smart Home is controlling the system +channel-type.nibeheatpump.f750-41928.label = Smart Price Adaption Price +channel-type.nibeheatpump.f750-41928.description = The current electric price +channel-type.nibeheatpump.f750-41929.label = Smart Price Adaption Price Level +channel-type.nibeheatpump.f750-41929.description = Whether the current price is unknown (0), low (1), medium (2), high (3) +channel-type.nibeheatpump.f750-41930.label = AA23-BE5 Power 10 +channel-type.nibeheatpump.f750-41931.label = AA23-BE5 Power 9 +channel-type.nibeheatpump.f750-41932.label = AA23-BE5 Power 8 +channel-type.nibeheatpump.f750-41933.label = AA23-BE5 Power 7 +channel-type.nibeheatpump.f750-41934.label = AA23-BE5 Power 6 +channel-type.nibeheatpump.f750-41935.label = AA23-BE5 Power 5 +channel-type.nibeheatpump.f750-41936.label = AA23-BE5 Power 4 +channel-type.nibeheatpump.f750-41937.label = AA23-BE5 Power 3 +channel-type.nibeheatpump.f750-41938.label = AA23-BE5 Power 2 +channel-type.nibeheatpump.f750-41939.label = AA23-BE5 Power 1 +channel-type.nibeheatpump.f750-41940.label = AA23-BE5 Error High 10 +channel-type.nibeheatpump.f750-41941.label = AA23-BE5 Error High 9 +channel-type.nibeheatpump.f750-41942.label = AA23-BE5 Error High 8 +channel-type.nibeheatpump.f750-41943.label = AA23-BE5 Error High 7 +channel-type.nibeheatpump.f750-41944.label = AA23-BE5 Error High 6 +channel-type.nibeheatpump.f750-41945.label = AA23-BE5 Error High 5 +channel-type.nibeheatpump.f750-41946.label = AA23-BE5 Error High 4 +channel-type.nibeheatpump.f750-41947.label = AA23-BE5 Error High 3 +channel-type.nibeheatpump.f750-41948.label = AA23-BE5 Error High 2 +channel-type.nibeheatpump.f750-41949.label = AA23-BE5 Error High 1 +channel-type.nibeheatpump.f750-41950.label = AA23-BE5 Error Low 10 +channel-type.nibeheatpump.f750-41951.label = AA23-BE5 Error Low 9 +channel-type.nibeheatpump.f750-41952.label = AA23-BE5 Error Low 8 +channel-type.nibeheatpump.f750-41953.label = AA23-BE5 Error Low 7 +channel-type.nibeheatpump.f750-41954.label = AA23-BE5 Error Low 6 +channel-type.nibeheatpump.f750-41955.label = AA23-BE5 Error Low 5 +channel-type.nibeheatpump.f750-41956.label = AA23-BE5 Error Low 4 +channel-type.nibeheatpump.f750-41957.label = AA23-BE5 Error Low 3 +channel-type.nibeheatpump.f750-41958.label = AA23-BE5 Error Low 2 +channel-type.nibeheatpump.f750-41959.label = AA23-BE5 Error Low 1 +channel-type.nibeheatpump.f750-41960.label = AA23-BE5 Com Percentage 10 +channel-type.nibeheatpump.f750-41961.label = AA23-BE5 Com Percentage 9 +channel-type.nibeheatpump.f750-41962.label = AA23-BE5 Com Percentage 8 +channel-type.nibeheatpump.f750-41963.label = AA23-BE5 Com Percentage 7 +channel-type.nibeheatpump.f750-41964.label = AA23-BE5 Com Percentage 6 +channel-type.nibeheatpump.f750-41965.label = AA23-BE5 Com Percentage 5 +channel-type.nibeheatpump.f750-41966.label = AA23-BE5 Com Percentage 4 +channel-type.nibeheatpump.f750-41967.label = AA23-BE5 Com Percentage 3 +channel-type.nibeheatpump.f750-41968.label = AA23-BE5 Com Percentage 2 +channel-type.nibeheatpump.f750-41969.label = AA23-BE5 Com Percentage 1 +channel-type.nibeheatpump.f750-41980.label = AA23-BE5 Voltage1 10 +channel-type.nibeheatpump.f750-41981.label = AA23-BE5 Voltage1 9 +channel-type.nibeheatpump.f750-41982.label = AA23-BE5 Voltage1 8 +channel-type.nibeheatpump.f750-41983.label = AA23-BE5 Voltage1 7 +channel-type.nibeheatpump.f750-41984.label = AA23-BE5 Voltage1 6 +channel-type.nibeheatpump.f750-41985.label = AA23-BE5 Voltage1 5 +channel-type.nibeheatpump.f750-41986.label = AA23-BE5 Voltage1 4 +channel-type.nibeheatpump.f750-41987.label = AA23-BE5 Voltage1 3 +channel-type.nibeheatpump.f750-41988.label = AA23-BE5 Voltage1 2 +channel-type.nibeheatpump.f750-41989.label = AA23-BE5 Voltage1 1 +channel-type.nibeheatpump.f750-41990.label = AA23-BE5 Voltage2 10 +channel-type.nibeheatpump.f750-41991.label = AA23-BE5 Voltage2 9 +channel-type.nibeheatpump.f750-41992.label = AA23-BE5 Voltage2 8 +channel-type.nibeheatpump.f750-41993.label = AA23-BE5 Voltage2 7 +channel-type.nibeheatpump.f750-41994.label = AA23-BE5 Voltage2 6 +channel-type.nibeheatpump.f750-41995.label = AA23-BE5 Voltage2 5 +channel-type.nibeheatpump.f750-41996.label = AA23-BE5 Voltage2 4 +channel-type.nibeheatpump.f750-41997.label = AA23-BE5 Voltage2 3 +channel-type.nibeheatpump.f750-41998.label = AA23-BE5 Voltage2 2 +channel-type.nibeheatpump.f750-41999.label = AA23-BE5 Voltage2 1 +channel-type.nibeheatpump.f750-42000.label = AA23-BE5 Temperature 10 +channel-type.nibeheatpump.f750-42001.label = AA23-BE5 Temperature 9 +channel-type.nibeheatpump.f750-42002.label = AA23-BE5 Temperature 8 +channel-type.nibeheatpump.f750-42003.label = AA23-BE5 Temperature 7 +channel-type.nibeheatpump.f750-42004.label = AA23-BE5 Temperature 6 +channel-type.nibeheatpump.f750-42005.label = AA23-BE5 Temperature 5 +channel-type.nibeheatpump.f750-42006.label = AA23-BE5 Temperature 4 +channel-type.nibeheatpump.f750-42007.label = AA23-BE5 Temperature 3 +channel-type.nibeheatpump.f750-42008.label = AA23-BE5 Temperature 2 +channel-type.nibeheatpump.f750-42009.label = AA23-BE5 Temperature 1 +channel-type.nibeheatpump.f750-42010.label = AA23-BE5 Energy 10 +channel-type.nibeheatpump.f750-42012.label = AA23-BE5 Energy 9 +channel-type.nibeheatpump.f750-42014.label = AA23-BE5 Energy 8 +channel-type.nibeheatpump.f750-42016.label = AA23-BE5 Energy 7 +channel-type.nibeheatpump.f750-42018.label = AA23-BE5 Energy 6 +channel-type.nibeheatpump.f750-42020.label = AA23-BE5 Energy 5 +channel-type.nibeheatpump.f750-42022.label = AA23-BE5 Energy 4 +channel-type.nibeheatpump.f750-42024.label = AA23-BE5 Energy 3 +channel-type.nibeheatpump.f750-42026.label = AA23-BE5 Energy 2 +channel-type.nibeheatpump.f750-42028.label = AA23-BE5 Energy 1 +channel-type.nibeheatpump.f750-42030.label = AA23-BE5 EME20 Version +channel-type.nibeheatpump.f750-42033.label = PV Panel Heat Offset +channel-type.nibeheatpump.f750-42034.label = PV Panel Pool Offset +channel-type.nibeheatpump.f750-42035.label = AA23-BE5 EME20 Total Power +channel-type.nibeheatpump.f750-42037.label = AA23-BE5 EME20 Total Average Power +channel-type.nibeheatpump.f750-42075.label = AA23-BE5 EME20 Total Energy +channel-type.nibeheatpump.f750-42080.label = AA23-BE5 Alarm 504 +channel-type.nibeheatpump.f750-42081.label = AA23-BE5 Alarm 505 +channel-type.nibeheatpump.f750-42082.label = AA23-BE5 Alarm 506 +channel-type.nibeheatpump.f750-42083.label = AA23-BE5 Alarm 507 +channel-type.nibeheatpump.f750-42084.label = AA23-BE5 Alarm 508 +channel-type.nibeheatpump.f750-42085.label = AA23-BE5 Alarm 509 +channel-type.nibeheatpump.f750-42086.label = AA23-BE5 Alarm 510 +channel-type.nibeheatpump.f750-42087.label = AA23-BE5 Alarm 511 +channel-type.nibeheatpump.f750-42093.label = External SAM Accessory GQ3 Speed +channel-type.nibeheatpump.f750-42093.description = Indicates the speed of the GQ3 fan speed in the SAM accessory. +channel-type.nibeheatpump.f750-42100.label = BT1 Average, 24h +channel-type.nibeheatpump.f750-42100.description = EB100-BT1 Outdoor temperature average, 24h +channel-type.nibeheatpump.f750-42101.label = Used Heating Power Average, 24h +channel-type.nibeheatpump.f750-42101.description = Used heating power average, 24h +channel-type.nibeheatpump.f750-42437.label = Heat Meter - HW Cpr and Add - Total System +channel-type.nibeheatpump.f750-42437.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f750-42439.label = Heat Meter - Heat Cpr and Add - Total System +channel-type.nibeheatpump.f750-42439.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f750-42443.label = Heat Meter - Pool Cpr - Total System +channel-type.nibeheatpump.f750-42443.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f750-42445.label = Heat Meter - HW Cpr - Total System +channel-type.nibeheatpump.f750-42445.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f750-42447.label = Heat Meter - Heat Cpr - Total System +channel-type.nibeheatpump.f750-42447.description = Accumulated energy production as calculated by the heat meter, summaries of all heat pumps in system +channel-type.nibeheatpump.f750-42504.label = External Energy Meter Accumulated System +channel-type.nibeheatpump.f750-43001.label = Software Version +channel-type.nibeheatpump.f750-43005.label = Degree Minutes (16 Bit) +channel-type.nibeheatpump.f750-43005.description = Degree minutes, 16bit value (-32768 < x < 32767). Values outside valid values are rounded to the closest valid value. +channel-type.nibeheatpump.f750-43006.label = Calc. Supply S4 +channel-type.nibeheatpump.f750-43006.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-43007.label = Calc. Supply S3 +channel-type.nibeheatpump.f750-43007.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-43008.label = Calc. Supply S2 +channel-type.nibeheatpump.f750-43008.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-43009.label = Calc. Supply S1 +channel-type.nibeheatpump.f750-43009.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.f750-43013.label = Freeze Protection Status +channel-type.nibeheatpump.f750-43013.description = 1 = Freeze protection active +channel-type.nibeheatpump.f750-43013.state.option.1 = Freeze protection active +channel-type.nibeheatpump.f750-43061.label = T. After Start Timer +channel-type.nibeheatpump.f750-43062.label = T. After Mode Change +channel-type.nibeheatpump.f750-43062.description = Time after mode change +channel-type.nibeheatpump.f750-43064.label = Heat Medium Flow DT Set Point +channel-type.nibeheatpump.f750-43064.description = Set point delta T for the heat medium flow +channel-type.nibeheatpump.f750-43065.label = Heat Medium Flow DT Actual +channel-type.nibeheatpump.f750-43065.description = Current value of the delta T for the heat medium flow +channel-type.nibeheatpump.f750-43066.label = Defrosting Time +channel-type.nibeheatpump.f750-43066.description = Defrosting time +channel-type.nibeheatpump.f750-43081.label = Tot. Op.time Add. +channel-type.nibeheatpump.f750-43081.description = Total electric additive operation time +channel-type.nibeheatpump.f750-43084.label = Int. El.add. Power +channel-type.nibeheatpump.f750-43084.description = Current power from the internal electrical addition +channel-type.nibeheatpump.f750-43086.label = Prio +channel-type.nibeheatpump.f750-43086.description = Indicates what heating action (HW/heat/pool) currently prioritised 10=Off 20=Hot Water 30=Heat 40=Pool 41=Pool 2 50=Transfer 60=Cooling +channel-type.nibeheatpump.f750-43086.state.option.10 = Off +channel-type.nibeheatpump.f750-43086.state.option.20 = Hot Water +channel-type.nibeheatpump.f750-43086.state.option.30 = Heat +channel-type.nibeheatpump.f750-43086.state.option.40 = Pool +channel-type.nibeheatpump.f750-43086.state.option.41 = Pool 2 +channel-type.nibeheatpump.f750-43086.state.option.50 = Transfer +channel-type.nibeheatpump.f750-43086.state.option.60 = Cooling +channel-type.nibeheatpump.f750-43091.label = Int. El.add. State +channel-type.nibeheatpump.f750-43091.description = Number of steps active for internal step-controlled addition +channel-type.nibeheatpump.f750-43093.label = Mixing Valve State S4 +channel-type.nibeheatpump.f750-43093.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-43094.label = Mixing Valve State S3 +channel-type.nibeheatpump.f750-43094.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-43095.label = Mixing Valve State S2 +channel-type.nibeheatpump.f750-43095.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-43096.label = Mixing Valve State S1 +channel-type.nibeheatpump.f750-43096.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.f750-43097.label = Status of the Shunt Controlled Additional Heat Accessory +channel-type.nibeheatpump.f750-43097.description = 10 = Off, 20 = Running, 30 = Passive +channel-type.nibeheatpump.f750-43097.state.option.10 = Off +channel-type.nibeheatpump.f750-43097.state.option.20 = Running +channel-type.nibeheatpump.f750-43097.state.option.30 = Passive +channel-type.nibeheatpump.f750-43108.label = Fan Speed Current +channel-type.nibeheatpump.f750-43108.description = The current fan speed after scheduling and blocks are considered +channel-type.nibeheatpump.f750-43122.label = Compr. Current Min.freq. +channel-type.nibeheatpump.f750-43122.description = The current minimum frequency of the compressor +channel-type.nibeheatpump.f750-43123.label = Compr. Current Max.freq. +channel-type.nibeheatpump.f750-43123.description = The current maximum frequency of the compressor +channel-type.nibeheatpump.f750-43124.label = Airflow Ref. +channel-type.nibeheatpump.f750-43124.description = Reference value for the airflow. +channel-type.nibeheatpump.f750-43132.label = Inverter Com. Timer +channel-type.nibeheatpump.f750-43132.description = This value shows the time since last communication with the inverter +channel-type.nibeheatpump.f750-43136.label = Compressor Frequency, Actual +channel-type.nibeheatpump.f750-43136.description = The compressor frequency the compressor is currently running at +channel-type.nibeheatpump.f750-43140.label = Inverter Temperature +channel-type.nibeheatpump.f750-43140.description = Current inverter temparture +channel-type.nibeheatpump.f750-43141.label = Compr. in Power +channel-type.nibeheatpump.f750-43141.description = The power delivered from the inverter to the compressor +channel-type.nibeheatpump.f750-43144.label = Compr. Energy Total +channel-type.nibeheatpump.f750-43144.description = Total compressor energy in kWh +channel-type.nibeheatpump.f750-43147.label = Compr. in Current +channel-type.nibeheatpump.f750-43147.description = The current delivered from the inverter to the compressor +channel-type.nibeheatpump.f750-43158.label = External Adjustment Activated Via Input S4 +channel-type.nibeheatpump.f750-43159.label = External Adjustment Activated Via Input S3 +channel-type.nibeheatpump.f750-43160.label = External Adjustment Activated Via Input S2 +channel-type.nibeheatpump.f750-43161.label = External Adjustment Activated Via Input S1 +channel-type.nibeheatpump.f750-43180.label = HWC Pump Status GP11 +channel-type.nibeheatpump.f750-43180.description = Hot water circulation pump status. 1=on, 0=off +channel-type.nibeheatpump.f750-43180.state.option.1 = on +channel-type.nibeheatpump.f750-43180.state.option.0 = off +channel-type.nibeheatpump.f750-43181.label = Chargepump Speed +channel-type.nibeheatpump.f750-43182.label = Compressor Frequency, Target +channel-type.nibeheatpump.f750-43182.description = The targeted compressor frequency, before excluding any blocked frequencies +channel-type.nibeheatpump.f750-43239.label = Tot. HW Op.time Add. +channel-type.nibeheatpump.f750-43239.description = Total electric additive operation time in hot water mode +channel-type.nibeheatpump.f750-43305.label = Compr. Energy HW +channel-type.nibeheatpump.f750-43305.description = Compressor energy during hot water production in kWh +channel-type.nibeheatpump.f750-43371.label = Hot Gas Limit Status +channel-type.nibeheatpump.f750-43372.label = Evaporater Limit Status +channel-type.nibeheatpump.f750-43375.label = Compr. in Power Mean +channel-type.nibeheatpump.f750-43375.description = Mean power delivered from the inverter to the compressor. Mean is calculated every 10 seconds. +channel-type.nibeheatpump.f750-43382.label = Inverter Mem Error Code +channel-type.nibeheatpump.f750-43416.label = Compressor Starts EB100-EP14 +channel-type.nibeheatpump.f750-43416.description = Number of compressorer starts +channel-type.nibeheatpump.f750-43420.label = Tot. Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f750-43420.description = Total compressorer operation time +channel-type.nibeheatpump.f750-43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-type.nibeheatpump.f750-43424.description = Total compressorer operation time in hot water mode +channel-type.nibeheatpump.f750-43427.label = Compressor State EP14 +channel-type.nibeheatpump.f750-43427.description = 20 = Stopped, 40 = Starting, 60 = Running, 100 = Stopping +channel-type.nibeheatpump.f750-43427.state.option.20 = Stopped +channel-type.nibeheatpump.f750-43427.state.option.40 = Starting +channel-type.nibeheatpump.f750-43427.state.option.60 = Running +channel-type.nibeheatpump.f750-43427.state.option.100 = Stopping +channel-type.nibeheatpump.f750-43431.label = Supply Pump State EP14 +channel-type.nibeheatpump.f750-43431.description = 10=off,15=starting,20=on,40=10-day mode,80=calibration +channel-type.nibeheatpump.f750-43431.state.option.10 = off +channel-type.nibeheatpump.f750-43431.state.option.15 = starting +channel-type.nibeheatpump.f750-43431.state.option.20 = on +channel-type.nibeheatpump.f750-43431.state.option.40 = 10-day mode +channel-type.nibeheatpump.f750-43431.state.option.80 = calibration +channel-type.nibeheatpump.f750-43435.label = Cpr Status EP14 +channel-type.nibeheatpump.f750-43435.description = Status of the compressor. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.f750-43435.state.option.1 = on +channel-type.nibeheatpump.f750-43435.state.option.0 = off +channel-type.nibeheatpump.f750-43435.state.option.0 = Off +channel-type.nibeheatpump.f750-43435.state.option.1 = On +channel-type.nibeheatpump.f750-43437.label = Supply Pump Speed EP14 +channel-type.nibeheatpump.f750-43437.description = Supply pump speed in % +channel-type.nibeheatpump.f750-43444.label = State OEK +channel-type.nibeheatpump.f750-43444.description = The state of the OEK accessory +channel-type.nibeheatpump.f750-43514.label = EB100-EP14 PCA Base Relays +channel-type.nibeheatpump.f750-43514.description = Indicates active relays on the PCA Base card. Please refer to the wiring diagram for relay description. Binary encoded. 1=on, 0=off. Bit0=K4,Bit1=K3,Bit2=K2,Bit3=K1 +channel-type.nibeheatpump.f750-43514.state.option.1 = on +channel-type.nibeheatpump.f750-43514.state.option.0 = off. Bit0 K4 Bit1 K3 Bit2 K2 Bit3 K1 +channel-type.nibeheatpump.f750-43516.label = PCA-Power Relays EP14 +channel-type.nibeheatpump.f750-43516.description = Indicates the active relays on the PCA-Power card. The information is binary encoded +channel-type.nibeheatpump.f750-43542.label = Calculated Supply Air Temp. +channel-type.nibeheatpump.f750-43561.label = Pool 1 Blocked +channel-type.nibeheatpump.f750-44258.label = External Supply Air Accessory Relays +channel-type.nibeheatpump.f750-44258.description = Indicates the status of the relays on the external supply air accessory. The information is binary encoded. B0: relay K1 (QN40 close signal). B1: relay K2 (QN40 open signal) +channel-type.nibeheatpump.f750-44298.label = Heat Meter - HW Cpr and Add EP14 +channel-type.nibeheatpump.f750-44298.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-44300.label = Heat Meter - Heat Cpr and Add EP14 +channel-type.nibeheatpump.f750-44300.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-44304.label = Heat Meter - Pool Cpr EP14 +channel-type.nibeheatpump.f750-44304.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-44306.label = Heat Meter - HW Cpr EP14 +channel-type.nibeheatpump.f750-44306.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-44308.label = Heat Meter - Heat Cpr EP14 +channel-type.nibeheatpump.f750-44308.description = Accumulated energy production as calculated by the heat meter +channel-type.nibeheatpump.f750-44317.label = SCA Accessory Relays +channel-type.nibeheatpump.f750-44317.description = Indicates the status of the relays on the SCA accessory. The information is binary encoded. B0: relay K1 (Solar pump). B1: relay K2 (Solar Cooling Pump) B2: relay K3 (QN28) +channel-type.nibeheatpump.f750-44331.label = Software Release +channel-type.nibeheatpump.f750-44744.label = Extra Heating System Pump S4 +channel-type.nibeheatpump.f750-44745.label = Extra Heating System Pump S3 +channel-type.nibeheatpump.f750-44746.label = Extra Heating System Pump S2 +channel-type.nibeheatpump.f750-44755.label = DEW Hot Water Valve +channel-type.nibeheatpump.f750-44757.label = SCA Hot Water Valve +channel-type.nibeheatpump.f750-44874.label = State SG Ready +channel-type.nibeheatpump.f750-44878.label = SG Ready Input A +channel-type.nibeheatpump.f750-44879.label = SG Ready Input B +channel-type.nibeheatpump.f750-44896.label = Smart Price Adaption Heating Offset +channel-type.nibeheatpump.f750-44897.label = Smart Price Adaption HW Comfort Mode +channel-type.nibeheatpump.f750-44897.description = 0=Eco,1=Normal,2=Luxury,10=Normal+,20=Mini +channel-type.nibeheatpump.f750-44897.state.option.0 = Eco +channel-type.nibeheatpump.f750-44897.state.option.1 = Normal +channel-type.nibeheatpump.f750-44897.state.option.2 = Luxury +channel-type.nibeheatpump.f750-44897.state.option.10 = Normal+ +channel-type.nibeheatpump.f750-44897.state.option.20 = Mini +channel-type.nibeheatpump.f750-44898.label = Smart Price Adaption Pool Offset +channel-type.nibeheatpump.f750-44899.label = Smart Price Adaption Cool Offset +channel-type.nibeheatpump.f750-44908.label = State Smart Price Adaption +channel-type.nibeheatpump.f750-45001.label = Alarm +channel-type.nibeheatpump.f750-45001.description = Indicates the alarm number of the most severe current alarm +channel-type.nibeheatpump.f750-45171.label = Alarm Reset +channel-type.nibeheatpump.f750-45171.description = Reset alarm by setting value 1 +channel-type.nibeheatpump.f750-47004.label = Heat Curve S4 +channel-type.nibeheatpump.f750-47004.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-47005.label = Heat Curve S3 +channel-type.nibeheatpump.f750-47005.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-47006.label = Heat Curve S2 +channel-type.nibeheatpump.f750-47006.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-47007.label = Heat Curve S1 +channel-type.nibeheatpump.f750-47007.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-47008.label = Heat Offset S4 +channel-type.nibeheatpump.f750-47008.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-47009.label = Heat Offset S3 +channel-type.nibeheatpump.f750-47009.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-47010.label = Heat Offset S2 +channel-type.nibeheatpump.f750-47010.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-47011.label = Heat Offset S1 +channel-type.nibeheatpump.f750-47011.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-47012.label = Min Supply System 4 +channel-type.nibeheatpump.f750-47013.label = Min Supply System 3 +channel-type.nibeheatpump.f750-47014.label = Min Supply System 2 +channel-type.nibeheatpump.f750-47015.label = Min Supply System 1 +channel-type.nibeheatpump.f750-47016.label = Max Supply System 4 +channel-type.nibeheatpump.f750-47017.label = Max Supply System 3 +channel-type.nibeheatpump.f750-47018.label = Max Supply System 2 +channel-type.nibeheatpump.f750-47019.label = Max Supply System 1 +channel-type.nibeheatpump.f750-47020.label = Own Heating Curve P7 +channel-type.nibeheatpump.f750-47020.description = User defined heating curve point +channel-type.nibeheatpump.f750-47021.label = Own Heating Curve P6 +channel-type.nibeheatpump.f750-47021.description = User defined heating curve point +channel-type.nibeheatpump.f750-47022.label = Own Heating Curve P5 +channel-type.nibeheatpump.f750-47022.description = User defined heating curve point +channel-type.nibeheatpump.f750-47023.label = Own Heating Curve P4 +channel-type.nibeheatpump.f750-47023.description = User defined heating curve point +channel-type.nibeheatpump.f750-47024.label = Own Heating Curve P3 +channel-type.nibeheatpump.f750-47024.description = User defined heating curve point +channel-type.nibeheatpump.f750-47025.label = Own Heating Curve P2 +channel-type.nibeheatpump.f750-47025.description = User defined heating curve point +channel-type.nibeheatpump.f750-47026.label = Own Heating Curve P1 +channel-type.nibeheatpump.f750-47026.description = User defined heating curve point +channel-type.nibeheatpump.f750-47027.label = Point Offset Outdoor Temp. +channel-type.nibeheatpump.f750-47027.description = Outdoor temperature point where the heat curve is offset +channel-type.nibeheatpump.f750-47028.label = Point Offset +channel-type.nibeheatpump.f750-47028.description = Amount of offset at the point offset temperature +channel-type.nibeheatpump.f750-47029.label = External Adjustment S4 +channel-type.nibeheatpump.f750-47029.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-47030.label = External Adjustment S3 +channel-type.nibeheatpump.f750-47030.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-47031.label = External Adjustment S2 +channel-type.nibeheatpump.f750-47031.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-47032.label = External Adjustment S1 +channel-type.nibeheatpump.f750-47032.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-47033.label = External Adjustment with Room Sensor S4 +channel-type.nibeheatpump.f750-47033.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-47034.label = External Adjustment with Room Sensor S3 +channel-type.nibeheatpump.f750-47034.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-47035.label = External Adjustment with Room Sensor S2 +channel-type.nibeheatpump.f750-47035.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-47036.label = External Adjustment with Room Sensor S1 +channel-type.nibeheatpump.f750-47036.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-47041.label = Hot Water Comfort Mode +channel-type.nibeheatpump.f750-47041.description = Setting in menu 2.2. 0=Economy,1=Normal,2=Luxury,4=Smart Control 0=Economy 1=Normal 2=Luxury +channel-type.nibeheatpump.f750-47041.state.option.0 = Economy +channel-type.nibeheatpump.f750-47041.state.option.1 = Normal +channel-type.nibeheatpump.f750-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f750-47041.state.option.4 = Smart Control +channel-type.nibeheatpump.f750-47041.state.option.0 = Economy +channel-type.nibeheatpump.f750-47041.state.option.1 = Normal +channel-type.nibeheatpump.f750-47041.state.option.2 = Luxury +channel-type.nibeheatpump.f750-47043.label = Start Temperature HW Luxury +channel-type.nibeheatpump.f750-47043.description = Start temperature for heating water +channel-type.nibeheatpump.f750-47044.label = Start Temperature HW Normal +channel-type.nibeheatpump.f750-47044.description = Start temperature for heating water +channel-type.nibeheatpump.f750-47045.label = Start Temperature HW Economy +channel-type.nibeheatpump.f750-47045.description = Start temperature for heating water +channel-type.nibeheatpump.f750-47046.label = Stop Temperature Periodic HW +channel-type.nibeheatpump.f750-47046.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f750-47047.label = Stop Temperature HW Luxury +channel-type.nibeheatpump.f750-47047.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f750-47048.label = Stop Temperature HW Normal +channel-type.nibeheatpump.f750-47048.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f750-47049.label = Stop Temperature HW Economy +channel-type.nibeheatpump.f750-47049.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.f750-47050.label = Periodic HW +channel-type.nibeheatpump.f750-47050.description = Activates the periodic hot water generation +channel-type.nibeheatpump.f750-47051.label = Periodic HW Interval +channel-type.nibeheatpump.f750-47051.description = Interval between Periodic hot water sessions +channel-type.nibeheatpump.f750-47054.label = Run Time HWC +channel-type.nibeheatpump.f750-47054.description = Run time for the hot water circulation system +channel-type.nibeheatpump.f750-47055.label = Still Time HWC +channel-type.nibeheatpump.f750-47055.description = Still time for the hot water circulation system +channel-type.nibeheatpump.f750-47062.label = HW Charge Offset +channel-type.nibeheatpump.f750-47062.description = Offset of HW charge temperature from the stop temperature +channel-type.nibeheatpump.f750-47092.label = Manual Compfreq HW +channel-type.nibeheatpump.f750-47092.description = Should the compressor frequency be manual set in HW? +channel-type.nibeheatpump.f750-47093.label = Manual Compfreq Speed HW +channel-type.nibeheatpump.f750-47093.description = Manual compressor frequency in HW? +channel-type.nibeheatpump.f750-47094.label = Sec Per Compfreq Step +channel-type.nibeheatpump.f750-47094.description = Time between changes of the copmpressor frequency +channel-type.nibeheatpump.f750-47095.label = Max Compfreq Step +channel-type.nibeheatpump.f750-47095.description = Largest allowed change of compressor frequency in normal run +channel-type.nibeheatpump.f750-47096.label = Manual Compfreq Heating +channel-type.nibeheatpump.f750-47096.description = Should the compressor frequency be manual set in Heating? +channel-type.nibeheatpump.f750-47097.label = Min Speed After Start +channel-type.nibeheatpump.f750-47097.description = Time with minimum compressor frequency when heating demand occurs +channel-type.nibeheatpump.f750-47098.label = Min Speed After HW +channel-type.nibeheatpump.f750-47098.description = Should the compressor frequency be manual set in HW? +channel-type.nibeheatpump.f750-47099.label = GMz +channel-type.nibeheatpump.f750-47099.description = Compressor frequency regulator GMz +channel-type.nibeheatpump.f750-47100.label = Max Diff VBF-BerVBF +channel-type.nibeheatpump.f750-47100.description = Largest allowed difference between Supply and calc supply +channel-type.nibeheatpump.f750-47101.label = Comp Freq Reg P +channel-type.nibeheatpump.f750-47101.description = Compressor frequency regulator P +channel-type.nibeheatpump.f750-47102.label = Comp Freq Max Delta F +channel-type.nibeheatpump.f750-47102.description = Maximum change of copmpressor frequency in compressor frequency regulator +channel-type.nibeheatpump.f750-47103.label = Min Comp Freq +channel-type.nibeheatpump.f750-47103.description = Minimum allowed compressor frequency +channel-type.nibeheatpump.f750-47104.label = Max Comp Freq +channel-type.nibeheatpump.f750-47104.description = Maximum allowed compressor frequency +channel-type.nibeheatpump.f750-47105.label = Comp Freq Heating +channel-type.nibeheatpump.f750-47105.description = Compressor frequency used in heating mode +channel-type.nibeheatpump.f750-47131.label = Language +channel-type.nibeheatpump.f750-47131.description = Display language in the heat pump 0=English 1=Svenska 2=Deutsch 3=Francais 4=Espanol 5=Suomi 6=Lietuviu 7=Cesky 8=Polski 9=Nederlands 10=Norsk 11=Dansk 12=Eesti 13=Latviesu 16=Magyar +channel-type.nibeheatpump.f750-47131.state.option.0 = English +channel-type.nibeheatpump.f750-47131.state.option.1 = Svenska +channel-type.nibeheatpump.f750-47131.state.option.2 = Deutsch +channel-type.nibeheatpump.f750-47131.state.option.3 = Francais +channel-type.nibeheatpump.f750-47131.state.option.4 = Espanol +channel-type.nibeheatpump.f750-47131.state.option.5 = Suomi +channel-type.nibeheatpump.f750-47131.state.option.6 = Lietuviu +channel-type.nibeheatpump.f750-47131.state.option.7 = Cesky +channel-type.nibeheatpump.f750-47131.state.option.8 = Polski +channel-type.nibeheatpump.f750-47131.state.option.9 = Nederlands +channel-type.nibeheatpump.f750-47131.state.option.10 = Norsk +channel-type.nibeheatpump.f750-47131.state.option.11 = Dansk +channel-type.nibeheatpump.f750-47131.state.option.12 = Eesti +channel-type.nibeheatpump.f750-47131.state.option.13 = Latviesu +channel-type.nibeheatpump.f750-47131.state.option.16 = Magyar +channel-type.nibeheatpump.f750-47134.label = Period HW +channel-type.nibeheatpump.f750-47135.label = Period Heat +channel-type.nibeheatpump.f750-47137.label = Operational Mode +channel-type.nibeheatpump.f750-47137.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.f750-47137.state.option.0 = Auto +channel-type.nibeheatpump.f750-47137.state.option.1 = Manual +channel-type.nibeheatpump.f750-47137.state.option.2 = Add. heat only +channel-type.nibeheatpump.f750-47138.label = Operational Mode Heat Medium Pump +channel-type.nibeheatpump.f750-47138.description = 10=Intermittent 20=Continous 30=Economy 40=Auto +channel-type.nibeheatpump.f750-47138.state.option.10 = Intermittent +channel-type.nibeheatpump.f750-47138.state.option.20 = Continous +channel-type.nibeheatpump.f750-47138.state.option.30 = Economy +channel-type.nibeheatpump.f750-47138.state.option.40 = Auto +channel-type.nibeheatpump.f750-47206.label = DM Start Heating +channel-type.nibeheatpump.f750-47206.description = The value the degree minutes needed to be reached for the pump to start heating +channel-type.nibeheatpump.f750-47209.label = DM Between Add. Steps +channel-type.nibeheatpump.f750-47209.description = The number of degree minutes between start of each electric addition step +channel-type.nibeheatpump.f750-47210.label = DM Start Add. with Shunt +channel-type.nibeheatpump.f750-47212.label = Max Int Add. Power +channel-type.nibeheatpump.f750-47214.label = Fuse +channel-type.nibeheatpump.f750-47214.description = Size of the fuse that the HP is connected to +channel-type.nibeheatpump.f750-47261.label = Exhaust Fan Speed 4 +channel-type.nibeheatpump.f750-47262.label = Exhaust Fan Speed 3 +channel-type.nibeheatpump.f750-47263.label = Exhaust Fan Speed 2 +channel-type.nibeheatpump.f750-47264.label = Exhaust Fan Speed 1 +channel-type.nibeheatpump.f750-47265.label = Exhaust Fan Speed Normal +channel-type.nibeheatpump.f750-47266.label = Supply Fan Speed 4 +channel-type.nibeheatpump.f750-47267.label = Supply Fan Speed 3 +channel-type.nibeheatpump.f750-47268.label = Supply Fan Speed 2 +channel-type.nibeheatpump.f750-47269.label = Supply Fan Speed 1 +channel-type.nibeheatpump.f750-47270.label = Supply Fan Speed Normal +channel-type.nibeheatpump.f750-47271.label = Fan Return Time 4 +channel-type.nibeheatpump.f750-47271.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f750-47272.label = Fan Return Time 3 +channel-type.nibeheatpump.f750-47272.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f750-47273.label = Fan Return Time 2 +channel-type.nibeheatpump.f750-47273.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f750-47274.label = Fan Return Time 1 +channel-type.nibeheatpump.f750-47274.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.f750-47275.label = Filter Reminder Period +channel-type.nibeheatpump.f750-47275.description = Time between the reminder of filter replacement/cleaning. +channel-type.nibeheatpump.f750-47276.label = Floor Drying +channel-type.nibeheatpump.f750-47276.description = 0=Off 1=On +channel-type.nibeheatpump.f750-47277.label = Floor Drying Period 7 +channel-type.nibeheatpump.f750-47277.description = Days each period is active +channel-type.nibeheatpump.f750-47278.label = Floor Drying Period 6 +channel-type.nibeheatpump.f750-47278.description = Days each period is active +channel-type.nibeheatpump.f750-47279.label = Floor Drying Period 5 +channel-type.nibeheatpump.f750-47279.description = Days each period is active +channel-type.nibeheatpump.f750-47280.label = Floor Drying Period 4 +channel-type.nibeheatpump.f750-47280.description = Days each period is active +channel-type.nibeheatpump.f750-47281.label = Floor Drying Period 3 +channel-type.nibeheatpump.f750-47281.description = Days each period is active +channel-type.nibeheatpump.f750-47282.label = Floor Drying Period 2 +channel-type.nibeheatpump.f750-47282.description = Days each period is active +channel-type.nibeheatpump.f750-47283.label = Floor Drying Period 1 +channel-type.nibeheatpump.f750-47283.description = Days each period is active +channel-type.nibeheatpump.f750-47284.label = Floor Drying Temp. 7 +channel-type.nibeheatpump.f750-47284.description = Supply temperature each period +channel-type.nibeheatpump.f750-47285.label = Floor Drying Temp. 6 +channel-type.nibeheatpump.f750-47285.description = Supply temperature each period +channel-type.nibeheatpump.f750-47286.label = Floor Drying Temp. 5 +channel-type.nibeheatpump.f750-47286.description = Supply temperature each period +channel-type.nibeheatpump.f750-47287.label = Floor Drying Temp. 4 +channel-type.nibeheatpump.f750-47287.description = Supply temperature each period +channel-type.nibeheatpump.f750-47288.label = Floor Drying Temp. 3 +channel-type.nibeheatpump.f750-47288.description = Supply temperature each period +channel-type.nibeheatpump.f750-47289.label = Floor Drying Temp. 2 +channel-type.nibeheatpump.f750-47289.description = Supply temperature each period +channel-type.nibeheatpump.f750-47290.label = Floor Drying Temp. 1 +channel-type.nibeheatpump.f750-47290.description = Supply temperature each period +channel-type.nibeheatpump.f750-47291.label = Floor Drying Timer +channel-type.nibeheatpump.f750-47294.label = Use Airflow Defrost +channel-type.nibeheatpump.f750-47294.description = If reduced airflow should start defrost +channel-type.nibeheatpump.f750-47295.label = Airflow Reduction Trig +channel-type.nibeheatpump.f750-47295.description = How much the airflow is allowed to be reduced before a defrost is trigged +channel-type.nibeheatpump.f750-47296.label = Airflow Defrost Done +channel-type.nibeheatpump.f750-47296.description = How much the airflow has to raise before a defrost is ended +channel-type.nibeheatpump.f750-47299.label = Min Time Defrost +channel-type.nibeheatpump.f750-47299.description = Minimum duration of the defrost +channel-type.nibeheatpump.f750-47300.label = DOT +channel-type.nibeheatpump.f750-47300.description = Dimensioning outdoor temperature +channel-type.nibeheatpump.f750-47301.label = Delta T At DOT +channel-type.nibeheatpump.f750-47301.description = Delta T (BT12-BT3)at dimensioning outdoor temperature +channel-type.nibeheatpump.f750-47302.label = Climate System 2 Accessory +channel-type.nibeheatpump.f750-47302.description = Activates the climate system 2 accessory 0=Off 1=On +channel-type.nibeheatpump.f750-47303.label = Climate System 3 Accessory +channel-type.nibeheatpump.f750-47303.description = Activates the climate system 3 accessory 0=Off 1=On +channel-type.nibeheatpump.f750-47304.label = Climate System 4 Accessory +channel-type.nibeheatpump.f750-47304.description = Activates the climate system 4 accessory 0=Off 1=On +channel-type.nibeheatpump.f750-47305.label = Climate System 4 Mixing Valve Amp. +channel-type.nibeheatpump.f750-47305.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-47306.label = Climate System 3 Mixing Valve Amp. +channel-type.nibeheatpump.f750-47306.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-47307.label = Climate System 2 Mixing Valve Amp. +channel-type.nibeheatpump.f750-47307.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-47308.label = Climate System 4 Shunt Wait +channel-type.nibeheatpump.f750-47308.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-47309.label = Climate System 3 Shunt Wait +channel-type.nibeheatpump.f750-47309.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-47310.label = Climate System 2 Shunt Wait +channel-type.nibeheatpump.f750-47310.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-47317.label = Shunt Controlled Add. Accessory +channel-type.nibeheatpump.f750-47317.description = Activates the shunt controlled addition accessory. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.f750-47318.label = Shunt Controlled Add. Min. Temp. +channel-type.nibeheatpump.f750-47319.label = Shunt Controlled Add. Min. Runtime +channel-type.nibeheatpump.f750-47320.label = Shunt Controlled Add. Mixing Valve Amp. +channel-type.nibeheatpump.f750-47320.description = Mixing valve amplification for shunt controlled add. +channel-type.nibeheatpump.f750-47321.label = Shunt Controlled Add. Mixing Valve Wait +channel-type.nibeheatpump.f750-47321.description = Wait time between changes of the shunt in shunt controlled add. +channel-type.nibeheatpump.f750-47352.label = SMS40 Accessory +channel-type.nibeheatpump.f750-47352.description = Activates the SMS40 accessory +channel-type.nibeheatpump.f750-47365.label = RMU System 1 +channel-type.nibeheatpump.f750-47365.description = Activates the RMU accessory for system 1 +channel-type.nibeheatpump.f750-47366.label = RMU System 2 +channel-type.nibeheatpump.f750-47366.description = Activates the RMU accessory for system 2 +channel-type.nibeheatpump.f750-47367.label = RMU System 3 +channel-type.nibeheatpump.f750-47367.description = Activates the RMU accessory for system 3 +channel-type.nibeheatpump.f750-47368.label = RMU System 4 +channel-type.nibeheatpump.f750-47368.description = Activates the RMU accessory for system 4 +channel-type.nibeheatpump.f750-47370.label = Allow Additive Heating +channel-type.nibeheatpump.f750-47370.description = Whether to allow additive heating (only valid for operational mode Manual) +channel-type.nibeheatpump.f750-47371.label = Allow Heating +channel-type.nibeheatpump.f750-47371.description = Whether to allow heating (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.f750-47374.label = Start Temperature Cooling +channel-type.nibeheatpump.f750-47374.description = Start temperature for cooling, as set in menu 4.9.2 0=Off 1=On +channel-type.nibeheatpump.f750-47374.state.option.0 = Off +channel-type.nibeheatpump.f750-47374.state.option.1 = On +channel-type.nibeheatpump.f750-47375.label = Stop Temperature Heating +channel-type.nibeheatpump.f750-47375.description = Stop temperature for heating, as set in menu 4.9.2 +channel-type.nibeheatpump.f750-47376.label = Stop Temperature Additive +channel-type.nibeheatpump.f750-47376.description = Stop temperature for additive, as set in menu 4.9.2 +channel-type.nibeheatpump.f750-47377.label = Outdoor Filter Time +channel-type.nibeheatpump.f750-47377.description = 12=12 Hours 24=24 Hours +channel-type.nibeheatpump.f750-47377.state.option.12 = Hours 24 +channel-type.nibeheatpump.f750-47377.state.option.24 = Hours +channel-type.nibeheatpump.f750-47378.label = Max Diff. Comp. +channel-type.nibeheatpump.f750-47379.label = Max Diff. Add. +channel-type.nibeheatpump.f750-47384.label = Date Format +channel-type.nibeheatpump.f750-47384.description = 1=DD-MM-YY 2=YY-MM-DD +channel-type.nibeheatpump.f750-47384.state.option.1 = DD-MM-YY +channel-type.nibeheatpump.f750-47384.state.option.2 = YY-MM-DD +channel-type.nibeheatpump.f750-47385.label = Time Format +channel-type.nibeheatpump.f750-47385.description = 12=12 hours 24=24 Hours +channel-type.nibeheatpump.f750-47385.state.option.12 = hours 24 +channel-type.nibeheatpump.f750-47385.state.option.24 = Hours +channel-type.nibeheatpump.f750-47387.label = HW Production +channel-type.nibeheatpump.f750-47387.description = Activates hot water production where applicable 0=Off 1=On +channel-type.nibeheatpump.f750-47388.label = Alarm Lower Room Temp. +channel-type.nibeheatpump.f750-47388.description = Lowers the room temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f750-47389.label = Alarm Lower HW Temp. +channel-type.nibeheatpump.f750-47389.description = Lowers the hot water temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.f750-47391.label = Use Room Sensor S4 +channel-type.nibeheatpump.f750-47391.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f750-47392.label = Use Room Sensor S3 +channel-type.nibeheatpump.f750-47392.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f750-47393.label = Use Room Sensor S2 +channel-type.nibeheatpump.f750-47393.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f750-47394.label = Use Room Sensor S1 +channel-type.nibeheatpump.f750-47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.f750-47395.label = Room Sensor Setpoint S4 +channel-type.nibeheatpump.f750-47395.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-47396.label = Room Sensor Setpoint S3 +channel-type.nibeheatpump.f750-47396.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-47397.label = Room Sensor Setpoint S2 +channel-type.nibeheatpump.f750-47397.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-47398.label = Room Sensor Setpoint S1 +channel-type.nibeheatpump.f750-47398.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-47399.label = Room Sensor Factor S4 +channel-type.nibeheatpump.f750-47399.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-47400.label = Room Sensor Factor S3 +channel-type.nibeheatpump.f750-47400.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-47401.label = Room Sensor Factor S2 +channel-type.nibeheatpump.f750-47401.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-47402.label = Room Sensor Factor S1 +channel-type.nibeheatpump.f750-47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-47442.label = Preset Flow Clim. Sys. +channel-type.nibeheatpump.f750-47442.description = Preset flow setting for climate system. 0 = manual setting, 1 = radiator, 2 = floor heating, 3 = radiator + floor heating. +channel-type.nibeheatpump.f750-47442.state.option.0 = manual setting +channel-type.nibeheatpump.f750-47442.state.option.1 = radiator +channel-type.nibeheatpump.f750-47442.state.option.2 = floor heating +channel-type.nibeheatpump.f750-47442.state.option.3 = radiator + floor heating. +channel-type.nibeheatpump.f750-47473.label = Max Time Defrost +channel-type.nibeheatpump.f750-47473.description = Maximum duration of the defrost +channel-type.nibeheatpump.f750-47525.label = Heat Curve S8 +channel-type.nibeheatpump.f750-47525.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-47537.label = Night Cooling +channel-type.nibeheatpump.f750-47537.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. 0=Off 1=On +channel-type.nibeheatpump.f750-47538.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f750-47539.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f750-47539.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f750-47555.label = DEW Accessory +channel-type.nibeheatpump.f750-47555.description = Activates the DEW accessory +channel-type.nibeheatpump.f750-47567.label = Heat Curve S7 +channel-type.nibeheatpump.f750-47567.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-48043.label = Holiday - Activated +channel-type.nibeheatpump.f750-48043.description = 0=inactive, 10=active +channel-type.nibeheatpump.f750-48043.state.option.0 = inactive +channel-type.nibeheatpump.f750-48043.state.option.10 = active +channel-type.nibeheatpump.f750-48072.label = DM Diff Start Add. +channel-type.nibeheatpump.f750-48072.description = The value below the last compressor step the degree minutes needed to be reached for the pump to start electric addition +channel-type.nibeheatpump.f750-48132.label = Temporary Lux +channel-type.nibeheatpump.f750-48132.description = 0=Off, 1=3h, 2=6h, 3=12h, 4=One time increase +channel-type.nibeheatpump.f750-48132.state.option.0 = Off +channel-type.nibeheatpump.f750-48132.state.option.1 = 3h +channel-type.nibeheatpump.f750-48132.state.option.2 = 6h +channel-type.nibeheatpump.f750-48132.state.option.3 = 12h +channel-type.nibeheatpump.f750-48132.state.option.4 = One time increase +channel-type.nibeheatpump.f750-48139.label = DM Startdiff Add. with Shunt +channel-type.nibeheatpump.f750-48158.label = SAM Supply Air Curve: Outdoor Temp T3 +channel-type.nibeheatpump.f750-48158.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48159.label = SAM Supply Air Curve: Outdoor Temp T2 +channel-type.nibeheatpump.f750-48159.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48160.label = SAM Supply Air Curve: Outdoor Temp T1 +channel-type.nibeheatpump.f750-48160.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48161.label = SAM Supply Air Curve: Supply Air Temp At T3 +channel-type.nibeheatpump.f750-48161.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48162.label = SAM Supply Air Curve: Supply Air Temp At T2 +channel-type.nibeheatpump.f750-48162.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48163.label = SAM Supply Air Curve: Supply Air Temp At T1 +channel-type.nibeheatpump.f750-48163.description = The supply air curve is defined by 3 supply air temperatures at 3 different outdoor temperatures T1, T2 and T3. +channel-type.nibeheatpump.f750-48201.label = SCA Accessory +channel-type.nibeheatpump.f750-48201.description = Activates the SCA accessory +channel-type.nibeheatpump.f750-48206.label = Silent Mode Status +channel-type.nibeheatpump.f750-48206.description = 1 = active, 0 = inactive +channel-type.nibeheatpump.f750-48206.state.option.1 = active +channel-type.nibeheatpump.f750-48206.state.option.0 = inactive +channel-type.nibeheatpump.f750-48275.label = Max Charge Pump Reg Speed +channel-type.nibeheatpump.f750-48275.description = Max heat medium pump reg speed +channel-type.nibeheatpump.f750-48282.label = SG Ready Heating +channel-type.nibeheatpump.f750-48282.description = Sets whether or not SG Ready should affect heating +channel-type.nibeheatpump.f750-48283.label = SG Ready Cooling +channel-type.nibeheatpump.f750-48283.description = Sets whether or not SG Ready should affect cooling +channel-type.nibeheatpump.f750-48284.label = SG Ready Hot Water +channel-type.nibeheatpump.f750-48284.description = Sets whether or not SG Ready should affect hot water +channel-type.nibeheatpump.f750-48285.label = SG Ready Pool +channel-type.nibeheatpump.f750-48285.description = Sets whether or not SG Ready should affect pool +channel-type.nibeheatpump.f750-48452.label = Auto Heat Medium Pump Speed, Hw +channel-type.nibeheatpump.f750-48452.description = Auto heat medium pump speed hw +channel-type.nibeheatpump.f750-48453.label = Auto Heat Medium Pump Speed, Heat +channel-type.nibeheatpump.f750-48453.description = Auto heat medium pump speed heat +channel-type.nibeheatpump.f750-48454.label = Auto Heat Medium Pump Speed, Pool +channel-type.nibeheatpump.f750-48454.description = Auto heat medium pump speed pool +channel-type.nibeheatpump.f750-48455.label = Auto Heat Medium Pump Speed, Cool +channel-type.nibeheatpump.f750-48455.description = Auto heat medium pump speed cool +channel-type.nibeheatpump.f750-48488.label = Heat Curve S6 +channel-type.nibeheatpump.f750-48488.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-48489.label = Heat Curve S5 +channel-type.nibeheatpump.f750-48489.description = Heat curve, see manual for more information +channel-type.nibeheatpump.f750-48491.label = Heat Offset S8 +channel-type.nibeheatpump.f750-48491.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-48492.label = Heat Offset S7 +channel-type.nibeheatpump.f750-48492.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-48493.label = Heat Offset S6 +channel-type.nibeheatpump.f750-48493.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-48494.label = Heat Offset S5 +channel-type.nibeheatpump.f750-48494.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.f750-48495.label = Min Supply System 8 +channel-type.nibeheatpump.f750-48496.label = Min Supply System 7 +channel-type.nibeheatpump.f750-48497.label = Min Supply System 6 +channel-type.nibeheatpump.f750-48498.label = Min Supply System 5 +channel-type.nibeheatpump.f750-48499.label = Max Supply System 8 +channel-type.nibeheatpump.f750-48500.label = Max Supply System 7 +channel-type.nibeheatpump.f750-48501.label = Max Supply System 6 +channel-type.nibeheatpump.f750-48502.label = Max Supply System 5 +channel-type.nibeheatpump.f750-48503.label = External Adjustment S8 +channel-type.nibeheatpump.f750-48503.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-48504.label = External Adjustment S7 +channel-type.nibeheatpump.f750-48504.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-48505.label = External Adjustment S6 +channel-type.nibeheatpump.f750-48505.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-48506.label = External Adjustment S5 +channel-type.nibeheatpump.f750-48506.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.f750-48507.label = External Adjustment with Room Sensor S8 +channel-type.nibeheatpump.f750-48507.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-48508.label = External Adjustment with Room Sensor S7 +channel-type.nibeheatpump.f750-48508.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-48509.label = External Adjustment with Room Sensor S6 +channel-type.nibeheatpump.f750-48509.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-48510.label = External Adjustment with Room Sensor S5 +channel-type.nibeheatpump.f750-48510.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.f750-48567.label = Initiate Inverter +channel-type.nibeheatpump.f750-48567.description = Start initiation process of the inverter +channel-type.nibeheatpump.f750-48568.label = Force Inverter Init +channel-type.nibeheatpump.f750-48568.description = Force inverter initiation process of the inverter +channel-type.nibeheatpump.f750-48569.label = Climate System 5 Accessory +channel-type.nibeheatpump.f750-48569.description = Activates the climate system 5 accessory +channel-type.nibeheatpump.f750-48570.label = Climate System 6 Accessory +channel-type.nibeheatpump.f750-48570.description = Activates the climate system 6 accessory +channel-type.nibeheatpump.f750-48571.label = Climate System 7 Accessory +channel-type.nibeheatpump.f750-48571.description = Activates the climate system 7 accessory +channel-type.nibeheatpump.f750-48572.label = Climate System 8 Accessory +channel-type.nibeheatpump.f750-48572.description = Activates the climate system 8 accessory +channel-type.nibeheatpump.f750-48573.label = Climate System 8 Mixing Valve Amp. +channel-type.nibeheatpump.f750-48573.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-48574.label = Climate System 7 Mixing Valve Amp. +channel-type.nibeheatpump.f750-48574.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-48575.label = Climate System 6 Mixing Valve Amp. +channel-type.nibeheatpump.f750-48575.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-48576.label = Climate System 5 Mixing Valve Amp. +channel-type.nibeheatpump.f750-48576.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.f750-48577.label = Climate System 8 Shunt Wait +channel-type.nibeheatpump.f750-48577.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-48578.label = Climate System 7 Shunt Wait +channel-type.nibeheatpump.f750-48578.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-48579.label = Climate System 6 Shunt Wait +channel-type.nibeheatpump.f750-48579.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-48580.label = Climate System 5 Shunt Wait +channel-type.nibeheatpump.f750-48580.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.f750-48637.label = AHPS Docking Accessory +channel-type.nibeheatpump.f750-48637.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48638.label = AHPS Docking: Solar Heating +channel-type.nibeheatpump.f750-48638.description = The specific AHPS docking: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48639.label = AHPS Docking: Prioritized Add. +channel-type.nibeheatpump.f750-48639.description = The specific AHPS docking: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48640.label = AHPS Docking: Ext. Addition +channel-type.nibeheatpump.f750-48640.description = The specific AHPS docking: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48641.label = AHPS Docking: Ext. Hot Water +channel-type.nibeheatpump.f750-48641.description = The specific AHPS docking: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48659.label = Cut Off Frequency Activated 2 +channel-type.nibeheatpump.f750-48659.description = Cut off frequency activated +channel-type.nibeheatpump.f750-48660.label = Cut Off Frequency Activated 1 +channel-type.nibeheatpump.f750-48660.description = Cut off frequency activated +channel-type.nibeheatpump.f750-48661.label = Cut Off Frequency Start 2 +channel-type.nibeheatpump.f750-48661.description = Cut off frequency start +channel-type.nibeheatpump.f750-48662.label = Cut Off Frequency Start 1 +channel-type.nibeheatpump.f750-48662.description = Cut off frequency start +channel-type.nibeheatpump.f750-48663.label = Cut Off Frequency Stop 2 +channel-type.nibeheatpump.f750-48663.description = Cut off frequency stop +channel-type.nibeheatpump.f750-48664.label = Cut Off Frequency Stop 1 +channel-type.nibeheatpump.f750-48664.description = Cut off frequency stop +channel-type.nibeheatpump.f750-48675.label = Use Room Sensor S8 +channel-type.nibeheatpump.f750-48675.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f750-48676.label = Use Room Sensor S7 +channel-type.nibeheatpump.f750-48676.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f750-48677.label = Use Room Sensor S6 +channel-type.nibeheatpump.f750-48677.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f750-48678.label = Use Room Sensor S5 +channel-type.nibeheatpump.f750-48678.description = When activated the system uses the room sensor +channel-type.nibeheatpump.f750-48680.label = Room Sensor Setpoint S8 +channel-type.nibeheatpump.f750-48680.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-48681.label = Room Sensor Setpoint S7 +channel-type.nibeheatpump.f750-48681.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-48682.label = Room Sensor Setpoint S6 +channel-type.nibeheatpump.f750-48682.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-48683.label = Room Sensor Setpoint S5 +channel-type.nibeheatpump.f750-48683.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.f750-48685.label = Room Sensor Factor S8 +channel-type.nibeheatpump.f750-48685.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-48686.label = Room Sensor Factor S7 +channel-type.nibeheatpump.f750-48686.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-48687.label = Room Sensor Factor S6 +channel-type.nibeheatpump.f750-48687.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-48688.label = Room Sensor Factor S5 +channel-type.nibeheatpump.f750-48688.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.f750-48732.label = Cool Offset S8 +channel-type.nibeheatpump.f750-48732.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48733.label = Cool Offset S7 +channel-type.nibeheatpump.f750-48733.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48734.label = Cool Offset S6 +channel-type.nibeheatpump.f750-48734.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48735.label = Cool Offset S5 +channel-type.nibeheatpump.f750-48735.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48736.label = Cool Offset S4 +channel-type.nibeheatpump.f750-48736.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48737.label = Cool Offset S3 +channel-type.nibeheatpump.f750-48737.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48738.label = Cool Offset S2 +channel-type.nibeheatpump.f750-48738.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48739.label = Cool Offset S1 +channel-type.nibeheatpump.f750-48739.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.f750-48743.label = Hot Water High Power Mode +channel-type.nibeheatpump.f750-48755.label = Transformer Ratio +channel-type.nibeheatpump.f750-48755.description = Ratio of the current measurement transformers +channel-type.nibeheatpump.f750-48794.label = RH Set Value +channel-type.nibeheatpump.f750-48794.description = RH set value +channel-type.nibeheatpump.f750-48810.label = Prevent Humidity S8 +channel-type.nibeheatpump.f750-48811.label = Prevent Humidity S7 +channel-type.nibeheatpump.f750-48812.label = Prevent Humidity S6 +channel-type.nibeheatpump.f750-48813.label = Prevent Humidity S5 +channel-type.nibeheatpump.f750-48814.label = Prevent Humidity S4 +channel-type.nibeheatpump.f750-48815.label = Prevent Humidity S3 +channel-type.nibeheatpump.f750-48816.label = Prevent Humidity S2 +channel-type.nibeheatpump.f750-48817.label = Prevent Humidity S1 +channel-type.nibeheatpump.f750-48852.label = Modbus40 Word Swap +channel-type.nibeheatpump.f750-48852.description = If set, swapping the words in 32-bit variables when value requested via ''read holding register'' commando. +channel-type.nibeheatpump.f750-48889.label = MODBUS40 Disable LOG.SET +channel-type.nibeheatpump.f750-48889.description = If set, the system will ignore the existing LOG.SET on the USB stick.1=ignore LOG.SET,0=use LOG.SET +channel-type.nibeheatpump.f750-48891.label = Setting up Ventilation +channel-type.nibeheatpump.f750-48891.description = Setting up ventilation for normal speed. +channel-type.nibeheatpump.f750-48908.label = Energy Meter Factor X23 +channel-type.nibeheatpump.f750-48908.description = Energy meter factor X23, energy per pulse +channel-type.nibeheatpump.f750-48909.label = Energy Meter Factor X22 +channel-type.nibeheatpump.f750-48909.description = Energy meter factor X22, energy per pulse +channel-type.nibeheatpump.f750-48910.label = Energy Meter X23 +channel-type.nibeheatpump.f750-48910.description = Activates the external energy meter +channel-type.nibeheatpump.f750-48911.label = Energy Meter X22 +channel-type.nibeheatpump.f750-48911.description = Activates the external energy meter +channel-type.nibeheatpump.f750-48914.label = Max Int Add. Power, SG Ready +channel-type.nibeheatpump.f750-48915.label = Real Air Flow +channel-type.nibeheatpump.f750-48915.description = Externally measured air flow during ventilation adjustments. +channel-type.nibeheatpump.f750-48926.label = Humidity Factor +channel-type.nibeheatpump.f750-48926.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature. +channel-type.nibeheatpump.f750-48927.label = Humidity Cool Factor +channel-type.nibeheatpump.f750-48927.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.f750-48930.label = EME10 Activated +channel-type.nibeheatpump.f750-48930.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f750-48931.label = EME PV Panel Affect Heating +channel-type.nibeheatpump.f750-48931.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f750-48932.label = EME PV Panel Affect Hot Water +channel-type.nibeheatpump.f750-48932.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f750-48968.label = FLM 1 Set Point, Cooling +channel-type.nibeheatpump.f750-48968.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.f750-48969.label = AUX Block OPT +channel-type.nibeheatpump.f750-48969.description = AUX block OPT +channel-type.nibeheatpump.f750-48970.label = Outdoor Air Mixing Function +channel-type.nibeheatpump.f750-48970.description = Activates the Outdoor Air Mixing function. +channel-type.nibeheatpump.f750-48972.label = Outdoor Air Min. Temp. +channel-type.nibeheatpump.f750-48972.description = Minimum outdoor air temperature set. +channel-type.nibeheatpump.f750-48973.label = Reduced Ventilation +channel-type.nibeheatpump.f750-48973.description = Outdoor air reduced ventilation. 0 = deactivated, 1 = activated. +channel-type.nibeheatpump.f750-48975.label = OEK Accessory +channel-type.nibeheatpump.f750-48975.description = Activates the OEK Accessory. +channel-type.nibeheatpump.f750-48976.label = Smart Home Room Control +channel-type.nibeheatpump.f750-49223.label = SCA Solar Heating +channel-type.nibeheatpump.f750-49223.description = SCA solar heating: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-49224.label = SCA Ext. Hot Water +channel-type.nibeheatpump.f750-49224.description = SCA external hot water: 0=not activated, 1=activated +channel-type.nibeheatpump.f750-49227.label = Block Top Frequencies +channel-type.nibeheatpump.f750-49227.description = Block compressor top frequencies +channel-type.nibeheatpump.f750-49281.label = SAM Fan Model +channel-type.nibeheatpump.f750-49281.description = SAM fan model +channel-type.nibeheatpump.f750-49282.label = Silent Mode Max Speed +channel-type.nibeheatpump.f750-49285.label = Energy Meter Pulses Per KWh X23 +channel-type.nibeheatpump.f750-49285.description = Energy meter factor X23, pulses per kWh +channel-type.nibeheatpump.f750-49286.label = Energy Meter Pulses Per KWh X22 +channel-type.nibeheatpump.f750-49286.description = Energy meter factor X22, pulses per kWh +channel-type.nibeheatpump.f750-49287.label = Energy Meter Mode X23 +channel-type.nibeheatpump.f750-49287.description = Energy meter X23 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.f750-49288.label = Energy Meter Mode X22 +channel-type.nibeheatpump.f750-49288.description = Energy meter X22 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.f750-49289.label = Ground Water Pump Speed Control +channel-type.nibeheatpump.f750-49295.label = AHPS External Addition Start Temperature. +channel-type.nibeheatpump.f750-49296.label = AHPS External Addition Stop Temperature. +channel-type.nibeheatpump.f750-49297.label = EME20 Activated +channel-type.nibeheatpump.f750-49297.description = 0=not activated, 1=activated +channel-type.nibeheatpump.f750-49298.label = EME PV Panel Affect Pool +channel-type.nibeheatpump.f750-49298.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.f750-49298.state.option.0 = not affecting +channel-type.nibeheatpump.f750-49298.state.option.1 = affecting +channel-type.nibeheatpump.f750-49358.label = Night Cooling +channel-type.nibeheatpump.f750-49358.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f750-49359.label = Night Cooling +channel-type.nibeheatpump.f750-49359.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f750-49360.label = Night Cooling +channel-type.nibeheatpump.f750-49360.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.f750-49361.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f750-49362.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f750-49363.label = Start Room Temp. Night Cooling +channel-type.nibeheatpump.f750-49364.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f750-49364.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f750-49365.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f750-49365.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.f750-49366.label = Night Cooling Min. Diff. +channel-type.nibeheatpump.f750-49366.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.smo40-40004.label = BT1 Outdoor Temperature +channel-type.nibeheatpump.smo40-40004.description = Current outdoor temperature +channel-type.nibeheatpump.smo40-40005.label = EP23-BT2 Supply temp S4 +channel-type.nibeheatpump.smo40-40005.description = Supply temperature for system 4 +channel-type.nibeheatpump.smo40-40006.label = EP22-BT2 Supply temp S3 +channel-type.nibeheatpump.smo40-40006.description = Supply temperature for system 3 +channel-type.nibeheatpump.smo40-40007.label = EP21-BT2 Supply temp S2 +channel-type.nibeheatpump.smo40-40007.description = Supply temperature for system 2 +channel-type.nibeheatpump.smo40-40012.label = EB100-EP14-BT3 Return temp +channel-type.nibeheatpump.smo40-40012.description = Return temperature +channel-type.nibeheatpump.smo40-40013.label = BT7 HW Top +channel-type.nibeheatpump.smo40-40013.description = Hot water top temperature, BT7 +channel-type.nibeheatpump.smo40-40014.label = BT6 HW Load +channel-type.nibeheatpump.smo40-40014.description = Hot water load temperature, BT6 +channel-type.nibeheatpump.smo40-40025.label = BT20 Exhaust air temp. 1 +channel-type.nibeheatpump.smo40-40026.label = BT21 Vented air temp. 1 +channel-type.nibeheatpump.smo40-40030.label = EP23-BT50 Room Temp S4 +channel-type.nibeheatpump.smo40-40031.label = EP22-BT50 Room Temp S3 +channel-type.nibeheatpump.smo40-40032.label = EP21-BT50 Room Temp S2 +channel-type.nibeheatpump.smo40-40033.label = BT50 Room Temp S1 +channel-type.nibeheatpump.smo40-40042.label = CL11-BT51 Pool 1 Temp +channel-type.nibeheatpump.smo40-40042.description = Pool temperature for Pool 1, BT51 +channel-type.nibeheatpump.smo40-40043.label = BT53 Solar Panel Temp +channel-type.nibeheatpump.smo40-40043.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.smo40-40044.label = BT54 Solar Load Temp +channel-type.nibeheatpump.smo40-40044.description = Used in Solar and AHPS Docking accessories +channel-type.nibeheatpump.smo40-40045.label = EQ1-BT64 Cool Supply Temp +channel-type.nibeheatpump.smo40-40045.description = Cool supply temperature, BT64 +channel-type.nibeheatpump.smo40-40054.label = EB100-FD1 Temperature limiter +channel-type.nibeheatpump.smo40-40067.label = BT1 Average +channel-type.nibeheatpump.smo40-40067.description = EB100-BT1 Outdoor temperature average +channel-type.nibeheatpump.smo40-40070.label = EM1-BT52 Boiler Temperature +channel-type.nibeheatpump.smo40-40070.description = Boiler temperature, BT52 +channel-type.nibeheatpump.smo40-40071.label = BT25 Ext. Supply +channel-type.nibeheatpump.smo40-40071.description = External supply temperature, BT25 +channel-type.nibeheatpump.smo40-40072.label = BF1 EP14 Flow +channel-type.nibeheatpump.smo40-40072.description = Current flow EP14|Current flow EP15 +channel-type.nibeheatpump.smo40-40074.label = EB100-FR1 Anode Status +channel-type.nibeheatpump.smo40-40075.label = BT22 Supply air temp. +channel-type.nibeheatpump.smo40-40079.label = EB100-BE3 Current +channel-type.nibeheatpump.smo40-40081.label = EB100-BE2 Current +channel-type.nibeheatpump.smo40-40083.label = EB100-BE1 Current +channel-type.nibeheatpump.smo40-40106.label = CL12-BT51 Pool 2 Temp +channel-type.nibeheatpump.smo40-40106.description = Pool temperature for Pool 2, BT51 +channel-type.nibeheatpump.smo40-40121.label = BT63 Add Supply Temp +channel-type.nibeheatpump.smo40-40127.label = EP23-BT3 Return temp S4 +channel-type.nibeheatpump.smo40-40127.description = Return temperature for system 4 +channel-type.nibeheatpump.smo40-40128.label = EP22-BT3 Return temp S3 +channel-type.nibeheatpump.smo40-40128.description = Return temperature for system 3 +channel-type.nibeheatpump.smo40-40129.label = EP21-BT3 Return temp S2 +channel-type.nibeheatpump.smo40-40129.description = Return temperature for system 2 +channel-type.nibeheatpump.smo40-40147.label = BT70 HW Comfort Supply Temp. +channel-type.nibeheatpump.smo40-40147.description = Hot water comfort supply temperature, BT70 +channel-type.nibeheatpump.smo40-40152.label = BT71 Ext. Return Temp +channel-type.nibeheatpump.smo40-40152.description = External return temperature, BT71 +channel-type.nibeheatpump.smo40-40159.label = EP47-BT2 Supply temp S8 +channel-type.nibeheatpump.smo40-40159.description = Supply temperature for system 8 +channel-type.nibeheatpump.smo40-40160.label = EP46-BT2 Supply temp S7 +channel-type.nibeheatpump.smo40-40160.description = Supply temperature for system 7 +channel-type.nibeheatpump.smo40-40161.label = EP45-BT2 Supply temp S6 +channel-type.nibeheatpump.smo40-40161.description = Supply temperature for system 6 +channel-type.nibeheatpump.smo40-40162.label = EP44-BT2 Supply temp S5 +channel-type.nibeheatpump.smo40-40162.description = Supply temperature for system 5 +channel-type.nibeheatpump.smo40-40163.label = EP47-BT3 Return temp S8 +channel-type.nibeheatpump.smo40-40163.description = Return temperature for system 8 +channel-type.nibeheatpump.smo40-40164.label = EP46-BT3 Return temp S7 +channel-type.nibeheatpump.smo40-40164.description = Return temperature for system 7 +channel-type.nibeheatpump.smo40-40165.label = EP45-BT3 Return temp S6 +channel-type.nibeheatpump.smo40-40165.description = Return temperature for system 6 +channel-type.nibeheatpump.smo40-40166.label = EP44-BT3 Return temp S5 +channel-type.nibeheatpump.smo40-40166.description = Return temperature for system 5 +channel-type.nibeheatpump.smo40-40167.label = EP47-BT50 Room Temp S8 +channel-type.nibeheatpump.smo40-40168.label = EP46-BT50 Room Temp S7 +channel-type.nibeheatpump.smo40-40169.label = EP45-BT50 Room Temp S6 +channel-type.nibeheatpump.smo40-40170.label = EP44-BT50 Room Temp S5 +channel-type.nibeheatpump.smo40-40183.label = AZ30-BT23 Outdoor temp. ERS 1 +channel-type.nibeheatpump.smo40-40185.label = BT1 Average, 1h +channel-type.nibeheatpump.smo40-40185.description = EB100-BT1 Outdoor temperature average, 1h +channel-type.nibeheatpump.smo40-40188.label = EP47-BT50 Room Temp S8 Average +channel-type.nibeheatpump.smo40-40189.label = EP46-BT50 Room Temp S7 Average +channel-type.nibeheatpump.smo40-40190.label = EP45-BT50 Room Temp S6 Average +channel-type.nibeheatpump.smo40-40191.label = EP44-BT50 Room Temp S5 Average +channel-type.nibeheatpump.smo40-40192.label = EP23-BT50 Room Temp S4 Average +channel-type.nibeheatpump.smo40-40193.label = EP22-BT50 Room Temp S3 Average +channel-type.nibeheatpump.smo40-40194.label = EP21-BT50 Room Temp S2 Average +channel-type.nibeheatpump.smo40-40195.label = BT50 Room Temp S1 Average +channel-type.nibeheatpump.smo40-40212.label = BT74 Average +channel-type.nibeheatpump.smo40-40212.description = BT74 heating cooling sensor average +channel-type.nibeheatpump.smo40-40216.label = BT25 Ext. supply temp, cooling +channel-type.nibeheatpump.smo40-40217.label = Calc. Supply S8 +channel-type.nibeheatpump.smo40-40217.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-40218.label = Calc. Supply S7 +channel-type.nibeheatpump.smo40-40218.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-40219.label = Calc. Supply S6 +channel-type.nibeheatpump.smo40-40219.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-40220.label = Calculated Supply S5 +channel-type.nibeheatpump.smo40-40220.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-40221.label = Calc. Cooling Supply S8 +channel-type.nibeheatpump.smo40-40221.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-40222.label = Calc. Cooling Supply S7 +channel-type.nibeheatpump.smo40-40222.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-40223.label = Calc. Cooling Supply S6 +channel-type.nibeheatpump.smo40-40223.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-40224.label = Calc. Cooling Supply S5 +channel-type.nibeheatpump.smo40-40224.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-40305.label = Mixing Valve State S8 +channel-type.nibeheatpump.smo40-40305.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-40306.label = Mixing Valve State S7 +channel-type.nibeheatpump.smo40-40306.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-40307.label = Mixing Valve State S6 +channel-type.nibeheatpump.smo40-40307.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-40308.label = Mixing Valve State S5 +channel-type.nibeheatpump.smo40-40308.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-40310.label = External ERS 1 accessory relays +channel-type.nibeheatpump.smo40-40310.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.smo40-40311.label = External ERS 1 accessory GQ2 speed +channel-type.nibeheatpump.smo40-40311.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-40312.label = External ERS 1 accessory GQ3 speed +channel-type.nibeheatpump.smo40-40312.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-40339.label = External adjustment activated via input S8 +channel-type.nibeheatpump.smo40-40340.label = External adjustment activated via input S7 +channel-type.nibeheatpump.smo40-40341.label = External adjustment activated via input S6 +channel-type.nibeheatpump.smo40-40342.label = External adjustment activated via input S5 +channel-type.nibeheatpump.smo40-40365.label = Extra heating system pump S8 +channel-type.nibeheatpump.smo40-40366.label = Extra heating system pump S7 +channel-type.nibeheatpump.smo40-40367.label = Extra heating system pump S6 +channel-type.nibeheatpump.smo40-40368.label = Extra heating system pump S5 +channel-type.nibeheatpump.smo40-40625.label = BT82 HW Comfort Return Temp +channel-type.nibeheatpump.smo40-40626.label = BT83 HW Comfort Cylinder Temp +channel-type.nibeheatpump.smo40-40653.label = EB108-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40655.label = EB108-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40657.label = EB108-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40665.label = EB107-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40667.label = EB107-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40669.label = EB107-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40677.label = EB106-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40679.label = EB106-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40681.label = EB106-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40689.label = EB105-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40691.label = EB105-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40693.label = EB105-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40701.label = EB104-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40703.label = EB104-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40705.label = EB104-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40713.label = EB103-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40715.label = EB103-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40717.label = EB103-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40725.label = EB102-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40727.label = EB102-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40729.label = EB102-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40737.label = EB101-EP14 Tot. Cooling op.time compr +channel-type.nibeheatpump.smo40-40739.label = EB101-EP14 Tot. Pool1 op.time compr +channel-type.nibeheatpump.smo40-40741.label = EB101-EP14 Tot. Pool2 op.time compr +channel-type.nibeheatpump.smo40-40755.label = Tot. ext. HW add op.time +channel-type.nibeheatpump.smo40-40755.description = Total external hw-electric additive operation time +channel-type.nibeheatpump.smo40-40775.label = EB108 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40775.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40776.label = EB107 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40776.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40777.label = EB106 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40777.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40778.label = EB105 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40778.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40779.label = EB104 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40779.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40780.label = EB103 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40780.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40781.label = EB102 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40781.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40782.label = EB101 Cpr Frequency Desired F2040 +channel-type.nibeheatpump.smo40-40782.description = The desired frequency as shown in service info +channel-type.nibeheatpump.smo40-40792.label = OPT state +channel-type.nibeheatpump.smo40-40792.description = Indicates the state of the boiler connected through the OPT accessory. +channel-type.nibeheatpump.smo40-40793.label = OPT version +channel-type.nibeheatpump.smo40-40793.description = Version of the OPT PCBA software +channel-type.nibeheatpump.smo40-40801.label = OPT rel. modulation level +channel-type.nibeheatpump.smo40-40801.description = OPT relative modulation level +channel-type.nibeheatpump.smo40-40802.label = OPT boiler temperature +channel-type.nibeheatpump.smo40-40802.description = OPT boiler temperature +channel-type.nibeheatpump.smo40-40806.label = OPT boiler op. time +channel-type.nibeheatpump.smo40-40806.description = OPT boiler operation time +channel-type.nibeheatpump.smo40-40818.label = Available Heat Compressors +channel-type.nibeheatpump.smo40-40818.description = Number of compressors available for heating +channel-type.nibeheatpump.smo40-40819.label = Available Hot Water Compressors +channel-type.nibeheatpump.smo40-40819.description = Number of compressors available for to hot water +channel-type.nibeheatpump.smo40-40820.label = Available Pool 1 Compressors +channel-type.nibeheatpump.smo40-40820.description = Number of compressors available for pool 1 +channel-type.nibeheatpump.smo40-40821.label = Available Pool 2 Compressors +channel-type.nibeheatpump.smo40-40821.description = Number of compressors available for pool 2 +channel-type.nibeheatpump.smo40-40822.label = Available Cool Compressors +channel-type.nibeheatpump.smo40-40822.description = Number of compressors available for cooling +channel-type.nibeheatpump.smo40-40834.label = BM1 Humidity +channel-type.nibeheatpump.smo40-40856.label = BM1 BT50 Room temp. +channel-type.nibeheatpump.smo40-40857.label = BM1 Pressure +channel-type.nibeheatpump.smo40-40858.label = BM1 Dewpoint +channel-type.nibeheatpump.smo40-40889.label = BT64 Average +channel-type.nibeheatpump.smo40-40889.description = BT64 Cooling supply average +channel-type.nibeheatpump.smo40-40928.label = AZ10 Number of Starts +channel-type.nibeheatpump.smo40-40930.label = AZ10 Total Operating Time +channel-type.nibeheatpump.smo40-40940.label = Degree Minutes (32 bit) +channel-type.nibeheatpump.smo40-40940.description = Degree minutes, 32bit value. Full resolution. +channel-type.nibeheatpump.smo40-40942.label = External ERS 1 accessory block status +channel-type.nibeheatpump.smo40-40942.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.smo40-40943.label = External ERS 1 accessory EB17 +channel-type.nibeheatpump.smo40-40943.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.smo40-40943.state.option.0 = open. +channel-type.nibeheatpump.smo40-40947.label = F135 AZ10-BT12 Cond. out +channel-type.nibeheatpump.smo40-40948.label = F135 AZ10-BT13 Cond. in +channel-type.nibeheatpump.smo40-40949.label = F135 AZ10-BT16 Evaporator temp +channel-type.nibeheatpump.smo40-40950.label = F135 AZ10-BT76 Defrosting temp +channel-type.nibeheatpump.smo40-40951.label = F135 AZ10-BT77 Air in temp +channel-type.nibeheatpump.smo40-40952.label = F135 AZ10 Active Alarm Number +channel-type.nibeheatpump.smo40-40954.label = F135 AZ10 Defrosting +channel-type.nibeheatpump.smo40-40954.description = 1 = Yes, 0 = No +channel-type.nibeheatpump.smo40-40954.state.option.1 = Yes +channel-type.nibeheatpump.smo40-40954.state.option.0 = No +channel-type.nibeheatpump.smo40-40955.label = F135 AZ10 Relay Status +channel-type.nibeheatpump.smo40-40961.label = F135 AZ10 Pump Speed +channel-type.nibeheatpump.smo40-40962.label = F135 AZ10 Fan Speed +channel-type.nibeheatpump.smo40-40964.label = F135 AZ10 Version +channel-type.nibeheatpump.smo40-40995.label = External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-40997.label = External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-41000.label = EB101 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41002.label = EB101 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41002.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41003.label = EB101 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41003.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41004.label = EB101 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41004.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41005.label = EB101 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41005.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41006.label = EB101 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41006.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41007.label = EB101 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41007.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41008.label = EB101 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41027.label = Humidity average +channel-type.nibeheatpump.smo40-41027.description = Humidity average +channel-type.nibeheatpump.smo40-41050.label = EB108-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41051.label = EB108-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41052.label = EB108-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41053.label = EB108-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41054.label = EB108-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41055.label = EB108-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41056.label = EB108-EP14 Fan Status +channel-type.nibeheatpump.smo40-41057.label = EB108-EP14 Fan Set +channel-type.nibeheatpump.smo40-41066.label = EB107-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41067.label = EB107-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41068.label = EB107-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41069.label = EB107-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41070.label = EB107-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41071.label = EB107-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41072.label = EB107-EP14 Fan Status +channel-type.nibeheatpump.smo40-41073.label = EB107-EP14 Fan Set +channel-type.nibeheatpump.smo40-41082.label = EB106-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41083.label = EB106-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41084.label = EB106-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41085.label = EB106-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41086.label = EB106-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41087.label = EB106-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41088.label = EB106-EP14 Fan Status +channel-type.nibeheatpump.smo40-41089.label = EB106-EP14 Fan Set +channel-type.nibeheatpump.smo40-41098.label = EB105-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41099.label = EB105-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41100.label = EB105-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41101.label = EB105-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41102.label = EB105-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41103.label = EB105-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41104.label = EB105-EP14 Fan Status +channel-type.nibeheatpump.smo40-41105.label = EB105-EP14 Fan Set +channel-type.nibeheatpump.smo40-41114.label = EB104-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41115.label = EB104-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41116.label = EB104-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41117.label = EB104-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41118.label = EB104-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41119.label = EB104-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41120.label = EB104-EP14 Fan Status +channel-type.nibeheatpump.smo40-41121.label = EB104-EP14 Fan Set +channel-type.nibeheatpump.smo40-41130.label = EB103-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41131.label = EB103-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41132.label = EB103-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41133.label = EB103-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41134.label = EB103-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41135.label = EB103-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41136.label = EB103-EP14 Fan Status +channel-type.nibeheatpump.smo40-41137.label = EB103-EP14 Fan Set +channel-type.nibeheatpump.smo40-41146.label = EB102-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41147.label = EB102-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41148.label = EB102-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41149.label = EB102-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41150.label = EB102-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41151.label = EB102-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41152.label = EB102-EP14 Fan Status +channel-type.nibeheatpump.smo40-41153.label = EB102-EP14 Fan Set +channel-type.nibeheatpump.smo40-41162.label = EB101-EP14-BP8 LP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41163.label = EB101-EP14-BP9 HP Dew Pressure Sensor +channel-type.nibeheatpump.smo40-41164.label = EB101-EP14-BT81 Evi Temp +channel-type.nibeheatpump.smo40-41165.label = EB101-EP14-BP11 Evi Pressure +channel-type.nibeheatpump.smo40-41166.label = EB101-EP14-BP11 Evi Dew Pressure +channel-type.nibeheatpump.smo40-41167.label = EB101-EP14-BT84 Evaptor temp +channel-type.nibeheatpump.smo40-41168.label = EB101-EP14 Fan Status +channel-type.nibeheatpump.smo40-41169.label = EB101-EP14 Fan Set +channel-type.nibeheatpump.smo40-41186.label = Set point OPT boiler +channel-type.nibeheatpump.smo40-41186.description = Set point OPT boiler +channel-type.nibeheatpump.smo40-41187.label = AZ10 High Condenser Out Alarm +channel-type.nibeheatpump.smo40-41188.label = AZ10 High Condenser In Alarm +channel-type.nibeheatpump.smo40-41191.label = PV Panel State +channel-type.nibeheatpump.smo40-41265.label = Smart Home Mode +channel-type.nibeheatpump.smo40-41265.description = Current smart home mode, 0=Default,1=Away from home,2=Vacation +channel-type.nibeheatpump.smo40-41265.state.option.0 = Default +channel-type.nibeheatpump.smo40-41265.state.option.1 = Away from home +channel-type.nibeheatpump.smo40-41265.state.option.2 = Vacation +channel-type.nibeheatpump.smo40-41266.label = Offset to smart home system +channel-type.nibeheatpump.smo40-41266.description = Offset to smart home system +channel-type.nibeheatpump.smo40-41267.label = Smart Home ctrl syst 8 +channel-type.nibeheatpump.smo40-41267.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41268.label = Smart Home ctrl syst 7 +channel-type.nibeheatpump.smo40-41268.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41269.label = Smart Home ctrl syst 6 +channel-type.nibeheatpump.smo40-41269.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41270.label = Smart Home ctrl syst 5 +channel-type.nibeheatpump.smo40-41270.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41271.label = Smart Home ctrl syst 4 +channel-type.nibeheatpump.smo40-41271.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41272.label = Smart Home ctrl syst 3 +channel-type.nibeheatpump.smo40-41272.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41273.label = Smart Home ctrl syst 2 +channel-type.nibeheatpump.smo40-41273.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41274.label = Smart Home ctrl syst 1 +channel-type.nibeheatpump.smo40-41274.description = Smart Home is controlling the system +channel-type.nibeheatpump.smo40-41287.label = OPT boiler has priority hot water +channel-type.nibeheatpump.smo40-41287.description = OPT boiler has priority hot water +channel-type.nibeheatpump.smo40-41393.label = Smart energy source, energy source prio 7, start DM +channel-type.nibeheatpump.smo40-41393.description = Energy source prio 7, start DM +channel-type.nibeheatpump.smo40-41395.label = Smart energy source, energy source prio 6, start DM +channel-type.nibeheatpump.smo40-41395.description = Energy source prio 6, start DM +channel-type.nibeheatpump.smo40-41397.label = Smart energy source, energy source prio 5, start DM +channel-type.nibeheatpump.smo40-41397.description = Energy source prio 5, start DM +channel-type.nibeheatpump.smo40-41399.label = Smart energy source, energy source prio 4, start DM +channel-type.nibeheatpump.smo40-41399.description = Energy source prio 4, start DM +channel-type.nibeheatpump.smo40-41401.label = Smart energy source, energy source prio 3, start DM +channel-type.nibeheatpump.smo40-41401.description = Energy source prio 3, start DM +channel-type.nibeheatpump.smo40-41403.label = Smart energy source, energy source prio 2, start DM +channel-type.nibeheatpump.smo40-41403.description = Energy source prio 2, start DM +channel-type.nibeheatpump.smo40-41405.label = Smart energy source, energy source prio 1, start DM +channel-type.nibeheatpump.smo40-41405.description = Energy source prio 1, start DM +channel-type.nibeheatpump.smo40-41421.label = Smart energy source, degree minute min value +channel-type.nibeheatpump.smo40-41421.description = Smart energy source, degree minute min value in Smart energy source system +channel-type.nibeheatpump.smo40-41424.label = Smart energy source, actual OPT10 addition price +channel-type.nibeheatpump.smo40-41424.description = Smart energy source, actual OPT10 addition price. +channel-type.nibeheatpump.smo40-41425.label = Smart energy source, actual shunt add price +channel-type.nibeheatpump.smo40-41425.description = Smart energy source, actual external step addition price. +channel-type.nibeheatpump.smo40-41426.label = Smart energy source, actual ext. step add price +channel-type.nibeheatpump.smo40-41426.description = Smart energy source, actual external step add price. +channel-type.nibeheatpump.smo40-41427.label = Smart energy source, actual electricity price +channel-type.nibeheatpump.smo40-41427.description = Smart energy source, actual electricity price. +channel-type.nibeheatpump.smo40-41446.label = Smart energy source prioritze OPT10 in hot water +channel-type.nibeheatpump.smo40-41468.label = EB108 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41469.label = EB108 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41469.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41470.label = EB108 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41470.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41471.label = EB108 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41471.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41472.label = EB108 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41472.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41473.label = EB108 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41473.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41474.label = EB108 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41474.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41475.label = EB108 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41493.label = EB107 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41494.label = EB107 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41494.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41495.label = EB107 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41495.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41496.label = EB107 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41496.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41497.label = EB107 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41497.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41498.label = EB107 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41498.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41499.label = EB107 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41499.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41500.label = EB107 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41518.label = EB106 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41519.label = EB106 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41519.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41520.label = EB106 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41520.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41521.label = EB106 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41521.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41522.label = EB106 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41522.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41523.label = EB106 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41523.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41524.label = EB106 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41524.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41525.label = EB106 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41543.label = EB105 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41544.label = EB105 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41544.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41545.label = EB105 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41545.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41546.label = EB105 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41546.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41547.label = EB105 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41547.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41548.label = EB105 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41548.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41549.label = EB105 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41549.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41550.label = EB105 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41568.label = EB104 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41569.label = EB104 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41569.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41570.label = EB104 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41570.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41571.label = EB104 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41571.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41572.label = EB104 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41572.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41573.label = EB104 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41573.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41574.label = EB104 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41574.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41575.label = EB104 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41593.label = EB103 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41594.label = EB103 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41594.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41595.label = EB103 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41595.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41596.label = EB103 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41596.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41597.label = EB103 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41597.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41598.label = EB103 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41598.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41599.label = EB103 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41599.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41600.label = EB103 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41618.label = EB102 F2120 Alarm Number +channel-type.nibeheatpump.smo40-41619.label = EB102 F2120 Fan Speed +channel-type.nibeheatpump.smo40-41619.description = F2120 Current Fan Speed +channel-type.nibeheatpump.smo40-41620.label = EB102 F2120 Max Fan Speed +channel-type.nibeheatpump.smo40-41620.description = F2120 Current Max Fan Speed +channel-type.nibeheatpump.smo40-41621.label = EB102 F2120 Min Fan Speed +channel-type.nibeheatpump.smo40-41621.description = F2120 Current Min Fan Speed +channel-type.nibeheatpump.smo40-41622.label = EB102 F2120 Max Compressor Speed +channel-type.nibeheatpump.smo40-41622.description = F2120 Current Max Compressor Speed +channel-type.nibeheatpump.smo40-41623.label = EB102 F2120 Min Compressor Speed +channel-type.nibeheatpump.smo40-41623.description = F2120 Current Min Compressor Speed +channel-type.nibeheatpump.smo40-41624.label = EB102 F2120 Calculated Power +channel-type.nibeheatpump.smo40-41624.description = F2120 Current Calculated Power +channel-type.nibeheatpump.smo40-41625.label = EB102 F2120 Time To Defrost +channel-type.nibeheatpump.smo40-41705.label = Smart energy source prioritze in hot water +channel-type.nibeheatpump.smo40-41705.description = Smart energy source prioritze in hot water, 0 = Compressor, 1 = OPT10, 2 = Internal addition +channel-type.nibeheatpump.smo40-41705.state.option.0 = Compressor +channel-type.nibeheatpump.smo40-41705.state.option.1 = OPT10 +channel-type.nibeheatpump.smo40-41705.state.option.2 = Internal addition +channel-type.nibeheatpump.smo40-41744.label = EB108-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41744.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41745.label = EB108-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41745.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41748.label = EB107-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41748.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41749.label = EB107-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41749.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41752.label = EB106-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41752.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41753.label = EB106-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41753.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41756.label = EB105-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41756.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41757.label = EB105-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41757.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41760.label = EB104-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41760.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41761.label = EB104-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41761.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41764.label = EB103-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41764.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41765.label = EB103-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41765.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41768.label = EB102-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41768.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41769.label = EB102-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41769.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41772.label = EB101-EP14 Alarm condensor in level +channel-type.nibeheatpump.smo40-41772.description = Alarm condensor in level +channel-type.nibeheatpump.smo40-41773.label = EB101-EP14 Alarm condensor out level +channel-type.nibeheatpump.smo40-41773.description = Alarm condensor out level +channel-type.nibeheatpump.smo40-41928.label = Smart Price Adaption Price +channel-type.nibeheatpump.smo40-41928.description = The current electric price +channel-type.nibeheatpump.smo40-41929.label = Smart Price Adaption Price Level +channel-type.nibeheatpump.smo40-41929.description = Whether the current price is unknown (0), low (1), medium (2), high (3) +channel-type.nibeheatpump.smo40-41930.label = AA23-BE5 Power 10 +channel-type.nibeheatpump.smo40-41931.label = AA23-BE5 Power 9 +channel-type.nibeheatpump.smo40-41932.label = AA23-BE5 Power 8 +channel-type.nibeheatpump.smo40-41933.label = AA23-BE5 Power 7 +channel-type.nibeheatpump.smo40-41934.label = AA23-BE5 Power 6 +channel-type.nibeheatpump.smo40-41935.label = AA23-BE5 Power 5 +channel-type.nibeheatpump.smo40-41936.label = AA23-BE5 Power 4 +channel-type.nibeheatpump.smo40-41937.label = AA23-BE5 Power 3 +channel-type.nibeheatpump.smo40-41938.label = AA23-BE5 Power 2 +channel-type.nibeheatpump.smo40-41939.label = AA23-BE5 Power 1 +channel-type.nibeheatpump.smo40-41940.label = AA23-BE5 Error High 10 +channel-type.nibeheatpump.smo40-41941.label = AA23-BE5 Error High 9 +channel-type.nibeheatpump.smo40-41942.label = AA23-BE5 Error High 8 +channel-type.nibeheatpump.smo40-41943.label = AA23-BE5 Error High 7 +channel-type.nibeheatpump.smo40-41944.label = AA23-BE5 Error High 6 +channel-type.nibeheatpump.smo40-41945.label = AA23-BE5 Error High 5 +channel-type.nibeheatpump.smo40-41946.label = AA23-BE5 Error High 4 +channel-type.nibeheatpump.smo40-41947.label = AA23-BE5 Error High 3 +channel-type.nibeheatpump.smo40-41948.label = AA23-BE5 Error High 2 +channel-type.nibeheatpump.smo40-41949.label = AA23-BE5 Error High 1 +channel-type.nibeheatpump.smo40-41950.label = AA23-BE5 Error Low 10 +channel-type.nibeheatpump.smo40-41951.label = AA23-BE5 Error Low 9 +channel-type.nibeheatpump.smo40-41952.label = AA23-BE5 Error Low 8 +channel-type.nibeheatpump.smo40-41953.label = AA23-BE5 Error Low 7 +channel-type.nibeheatpump.smo40-41954.label = AA23-BE5 Error Low 6 +channel-type.nibeheatpump.smo40-41955.label = AA23-BE5 Error Low 5 +channel-type.nibeheatpump.smo40-41956.label = AA23-BE5 Error Low 4 +channel-type.nibeheatpump.smo40-41957.label = AA23-BE5 Error Low 3 +channel-type.nibeheatpump.smo40-41958.label = AA23-BE5 Error Low 2 +channel-type.nibeheatpump.smo40-41959.label = AA23-BE5 Error Low 1 +channel-type.nibeheatpump.smo40-41960.label = AA23-BE5 Com Percentage 10 +channel-type.nibeheatpump.smo40-41961.label = AA23-BE5 Com Percentage 9 +channel-type.nibeheatpump.smo40-41962.label = AA23-BE5 Com Percentage 8 +channel-type.nibeheatpump.smo40-41963.label = AA23-BE5 Com Percentage 7 +channel-type.nibeheatpump.smo40-41964.label = AA23-BE5 Com Percentage 6 +channel-type.nibeheatpump.smo40-41965.label = AA23-BE5 Com Percentage 5 +channel-type.nibeheatpump.smo40-41966.label = AA23-BE5 Com Percentage 4 +channel-type.nibeheatpump.smo40-41967.label = AA23-BE5 Com Percentage 3 +channel-type.nibeheatpump.smo40-41968.label = AA23-BE5 Com Percentage 2 +channel-type.nibeheatpump.smo40-41969.label = AA23-BE5 Com Percentage 1 +channel-type.nibeheatpump.smo40-41980.label = AA23-BE5 Voltage1 10 +channel-type.nibeheatpump.smo40-41981.label = AA23-BE5 Voltage1 9 +channel-type.nibeheatpump.smo40-41982.label = AA23-BE5 Voltage1 8 +channel-type.nibeheatpump.smo40-41983.label = AA23-BE5 Voltage1 7 +channel-type.nibeheatpump.smo40-41984.label = AA23-BE5 Voltage1 6 +channel-type.nibeheatpump.smo40-41985.label = AA23-BE5 Voltage1 5 +channel-type.nibeheatpump.smo40-41986.label = AA23-BE5 Voltage1 4 +channel-type.nibeheatpump.smo40-41987.label = AA23-BE5 Voltage1 3 +channel-type.nibeheatpump.smo40-41988.label = AA23-BE5 Voltage1 2 +channel-type.nibeheatpump.smo40-41989.label = AA23-BE5 Voltage1 1 +channel-type.nibeheatpump.smo40-41990.label = AA23-BE5 Voltage2 10 +channel-type.nibeheatpump.smo40-41991.label = AA23-BE5 Voltage2 9 +channel-type.nibeheatpump.smo40-41992.label = AA23-BE5 Voltage2 8 +channel-type.nibeheatpump.smo40-41993.label = AA23-BE5 Voltage2 7 +channel-type.nibeheatpump.smo40-41994.label = AA23-BE5 Voltage2 6 +channel-type.nibeheatpump.smo40-41995.label = AA23-BE5 Voltage2 5 +channel-type.nibeheatpump.smo40-41996.label = AA23-BE5 Voltage2 4 +channel-type.nibeheatpump.smo40-41997.label = AA23-BE5 Voltage2 3 +channel-type.nibeheatpump.smo40-41998.label = AA23-BE5 Voltage2 2 +channel-type.nibeheatpump.smo40-41999.label = AA23-BE5 Voltage2 1 +channel-type.nibeheatpump.smo40-42000.label = AA23-BE5 Temperature 10 +channel-type.nibeheatpump.smo40-42001.label = AA23-BE5 Temperature 9 +channel-type.nibeheatpump.smo40-42002.label = AA23-BE5 Temperature 8 +channel-type.nibeheatpump.smo40-42003.label = AA23-BE5 Temperature 7 +channel-type.nibeheatpump.smo40-42004.label = AA23-BE5 Temperature 6 +channel-type.nibeheatpump.smo40-42005.label = AA23-BE5 Temperature 5 +channel-type.nibeheatpump.smo40-42006.label = AA23-BE5 Temperature 4 +channel-type.nibeheatpump.smo40-42007.label = AA23-BE5 Temperature 3 +channel-type.nibeheatpump.smo40-42008.label = AA23-BE5 Temperature 2 +channel-type.nibeheatpump.smo40-42009.label = AA23-BE5 Temperature 1 +channel-type.nibeheatpump.smo40-42010.label = AA23-BE5 Energy 10 +channel-type.nibeheatpump.smo40-42012.label = AA23-BE5 Energy 9 +channel-type.nibeheatpump.smo40-42014.label = AA23-BE5 Energy 8 +channel-type.nibeheatpump.smo40-42016.label = AA23-BE5 Energy 7 +channel-type.nibeheatpump.smo40-42018.label = AA23-BE5 Energy 6 +channel-type.nibeheatpump.smo40-42020.label = AA23-BE5 Energy 5 +channel-type.nibeheatpump.smo40-42022.label = AA23-BE5 Energy 4 +channel-type.nibeheatpump.smo40-42024.label = AA23-BE5 Energy 3 +channel-type.nibeheatpump.smo40-42026.label = AA23-BE5 Energy 2 +channel-type.nibeheatpump.smo40-42028.label = AA23-BE5 Energy 1 +channel-type.nibeheatpump.smo40-42030.label = AA23-BE5 EME20 Version +channel-type.nibeheatpump.smo40-42033.label = PV Panel Heat Offset +channel-type.nibeheatpump.smo40-42034.label = PV Panel Pool Offset +channel-type.nibeheatpump.smo40-42035.label = AA23-BE5 EME20 Total Power +channel-type.nibeheatpump.smo40-42037.label = AA23-BE5 EME20 Total Average Power +channel-type.nibeheatpump.smo40-42075.label = AA23-BE5 EME20 Total Energy +channel-type.nibeheatpump.smo40-42080.label = AA23-BE5 Alarm 504 +channel-type.nibeheatpump.smo40-42081.label = AA23-BE5 Alarm 505 +channel-type.nibeheatpump.smo40-42082.label = AA23-BE5 Alarm 506 +channel-type.nibeheatpump.smo40-42083.label = AA23-BE5 Alarm 507 +channel-type.nibeheatpump.smo40-42084.label = AA23-BE5 Alarm 508 +channel-type.nibeheatpump.smo40-42085.label = AA23-BE5 Alarm 509 +channel-type.nibeheatpump.smo40-42086.label = AA23-BE5 Alarm 510 +channel-type.nibeheatpump.smo40-42087.label = AA23-BE5 Alarm 511 +channel-type.nibeheatpump.smo40-42100.label = BT1 Average, 24h +channel-type.nibeheatpump.smo40-42100.description = EB100-BT1 Outdoor temperature average, 24h +channel-type.nibeheatpump.smo40-42101.label = Used heating power average, 24h +channel-type.nibeheatpump.smo40-42101.description = Used heating power average, 24h +channel-type.nibeheatpump.smo40-42136.label = BT22 Supply air temp. +channel-type.nibeheatpump.smo40-42137.label = BT22 Supply air temp. +channel-type.nibeheatpump.smo40-42138.label = BT22 Supply air temp. +channel-type.nibeheatpump.smo40-42139.label = AZ30-BT23 Outdoor temp. ERS 4 +channel-type.nibeheatpump.smo40-42140.label = AZ30-BT23 Outdoor temp. ERS 3 +channel-type.nibeheatpump.smo40-42141.label = AZ30-BT23 Outdoor temp. ERS 2 +channel-type.nibeheatpump.smo40-42150.label = External ERS 4 accessory relays +channel-type.nibeheatpump.smo40-42150.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.smo40-42151.label = External ERS 3 accessory relays +channel-type.nibeheatpump.smo40-42151.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.smo40-42152.label = External ERS 2 accessory relays +channel-type.nibeheatpump.smo40-42152.description = Indicates the status of the relays on the ERS accessory. The information is binary encoded. b0: K1, b1: K2, b2: K3, b3: K4 +channel-type.nibeheatpump.smo40-42153.label = External ERS 4 accessory GQ2 speed +channel-type.nibeheatpump.smo40-42153.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42154.label = External ERS 3 accessory GQ2 speed +channel-type.nibeheatpump.smo40-42154.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42155.label = External ERS 2 accessory GQ2 speed +channel-type.nibeheatpump.smo40-42155.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42156.label = External ERS 4 accessory GQ3 speed +channel-type.nibeheatpump.smo40-42156.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42157.label = External ERS 3 accessory GQ3 speed +channel-type.nibeheatpump.smo40-42157.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42158.label = External ERS 2 accessory GQ3 speed +channel-type.nibeheatpump.smo40-42158.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-type.nibeheatpump.smo40-42159.label = External ERS 4 accessory block status +channel-type.nibeheatpump.smo40-42159.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.smo40-42160.label = External ERS 3 accessory block status +channel-type.nibeheatpump.smo40-42160.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.smo40-42161.label = External ERS 2 accessory block status +channel-type.nibeheatpump.smo40-42161.description = Indicates if the ERS accessory is externaly blocked. +channel-type.nibeheatpump.smo40-42162.label = External ERS 4 accessory EB17 +channel-type.nibeheatpump.smo40-42162.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.smo40-42162.state.option.0 = open. +channel-type.nibeheatpump.smo40-42163.label = External ERS 3 accessory EB17 +channel-type.nibeheatpump.smo40-42163.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.smo40-42163.state.option.0 = open. +channel-type.nibeheatpump.smo40-42164.label = External ERS 2 accessory EB17 +channel-type.nibeheatpump.smo40-42164.description = Indicates if the status of ERS accessory EB17. I = closed, 0 = open. +channel-type.nibeheatpump.smo40-42164.state.option.0 = open. +channel-type.nibeheatpump.smo40-42464.label = External ERS 4 fire place guard +channel-type.nibeheatpump.smo40-42465.label = External ERS 3 fire place guard +channel-type.nibeheatpump.smo40-42466.label = External ERS 2 fire place guard +channel-type.nibeheatpump.smo40-42467.label = External ERS 1 fire place guard +channel-type.nibeheatpump.smo40-42468.label = EB108 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42470.label = EB108 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42472.label = EB107 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42474.label = EB107 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42476.label = EB106 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42478.label = EB106 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42480.label = EB105 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42482.label = EB105 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42484.label = EB104 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42486.label = EB104 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42488.label = EB103 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42490.label = EB103 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42492.label = EB102 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42494.label = EB102 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42496.label = EB101 External Energy Meter 2 Accumulated Energy +channel-type.nibeheatpump.smo40-42498.label = EB101 External Energy Meter 1 Accumulated Energy +channel-type.nibeheatpump.smo40-42504.label = External Energy Meter Accumulated System +channel-type.nibeheatpump.smo40-43001.label = Software version +channel-type.nibeheatpump.smo40-43005.label = Degree Minutes (16 bit) +channel-type.nibeheatpump.smo40-43005.description = Degree minutes, 16bit value (-32768 < x < 32767). Values outside valid values are rounded to the closest valid value. +channel-type.nibeheatpump.smo40-43006.label = Calc. Supply S4 +channel-type.nibeheatpump.smo40-43006.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-43007.label = Calc. Supply S3 +channel-type.nibeheatpump.smo40-43007.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-43008.label = Calc. Supply S2 +channel-type.nibeheatpump.smo40-43008.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-43009.label = Calc. Supply S1 +channel-type.nibeheatpump.smo40-43009.description = Calculated supply temperature for the climate system +channel-type.nibeheatpump.smo40-43013.label = Freeze Protection Status +channel-type.nibeheatpump.smo40-43013.description = 1 = Freeze protection active +channel-type.nibeheatpump.smo40-43013.state.option.1 = Freeze protection active +channel-type.nibeheatpump.smo40-43024.label = Status Cooling +channel-type.nibeheatpump.smo40-43024.description = 0=Off 1=On +channel-type.nibeheatpump.smo40-43024.state.option.0 = Off +channel-type.nibeheatpump.smo40-43024.state.option.1 = On +channel-type.nibeheatpump.smo40-43065.label = Heat Medium Flow dT Actual +channel-type.nibeheatpump.smo40-43065.description = Current value of the delta T for the heat medium flow +channel-type.nibeheatpump.smo40-43081.label = Tot. op.time add. +channel-type.nibeheatpump.smo40-43081.description = Total electric additive operation time +channel-type.nibeheatpump.smo40-43084.label = Int. el.add. Power +channel-type.nibeheatpump.smo40-43084.description = Current power from the internal electrical addition +channel-type.nibeheatpump.smo40-43086.label = Prio +channel-type.nibeheatpump.smo40-43086.description = Indicates what heating action (HW/heat/pool) currently prioritised 10=Off 20=Hot Water 30=Heat 40=Pool 41=Pool 2 50=Transfer 60=Cooling +channel-type.nibeheatpump.smo40-43086.state.option.10 = Off +channel-type.nibeheatpump.smo40-43086.state.option.20 = Hot Water +channel-type.nibeheatpump.smo40-43086.state.option.30 = Heat +channel-type.nibeheatpump.smo40-43086.state.option.40 = Pool +channel-type.nibeheatpump.smo40-43086.state.option.41 = Pool 2 +channel-type.nibeheatpump.smo40-43086.state.option.50 = Transfer +channel-type.nibeheatpump.smo40-43086.state.option.60 = Cooling +channel-type.nibeheatpump.smo40-43091.label = Int. el.add. State +channel-type.nibeheatpump.smo40-43091.description = Number of steps active for internal step-controlled addition +channel-type.nibeheatpump.smo40-43093.label = Mixing Valve State S4 +channel-type.nibeheatpump.smo40-43093.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-43094.label = Mixing Valve State S3 +channel-type.nibeheatpump.smo40-43094.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-43095.label = Mixing Valve State S2 +channel-type.nibeheatpump.smo40-43095.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-43096.label = Mixing Valve State S1 +channel-type.nibeheatpump.smo40-43096.description = State of the mixing valve for the climate system +channel-type.nibeheatpump.smo40-43097.label = Status of the shunt controlled additional heat accessory +channel-type.nibeheatpump.smo40-43097.description = 10 = Off, 20 = Running, 30 = Passive +channel-type.nibeheatpump.smo40-43097.state.option.10 = Off +channel-type.nibeheatpump.smo40-43097.state.option.20 = Running +channel-type.nibeheatpump.smo40-43097.state.option.30 = Passive +channel-type.nibeheatpump.smo40-43158.label = External adjustment activated via input S4 +channel-type.nibeheatpump.smo40-43159.label = External adjustment activated via input S3 +channel-type.nibeheatpump.smo40-43160.label = External adjustment activated via input S2 +channel-type.nibeheatpump.smo40-43161.label = External adjustment activated via input S1 +channel-type.nibeheatpump.smo40-43163.label = Blocking status of the shunt controlled add heat acc +channel-type.nibeheatpump.smo40-43163.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.smo40-43163.state.option.0 = Unblocked +channel-type.nibeheatpump.smo40-43163.state.option.1 = Blocked +channel-type.nibeheatpump.smo40-43171.label = Blocking status of the step controlled add heat acc +channel-type.nibeheatpump.smo40-43171.description = 0 = Unblocked, 1 = Blocked +channel-type.nibeheatpump.smo40-43171.state.option.0 = Unblocked +channel-type.nibeheatpump.smo40-43171.state.option.1 = Blocked +channel-type.nibeheatpump.smo40-43189.label = GP10 Ext. Supply Pump Status +channel-type.nibeheatpump.smo40-43189.description = External supply pump status. 1=on,0=off +channel-type.nibeheatpump.smo40-43189.state.option.1 = on +channel-type.nibeheatpump.smo40-43189.state.option.0 = off +channel-type.nibeheatpump.smo40-43230.label = Heat Meter (OBSOLETE) +channel-type.nibeheatpump.smo40-43230.description = Obsolete since v4798 of the controller software +channel-type.nibeheatpump.smo40-43239.label = Tot. HW op.time add. +channel-type.nibeheatpump.smo40-43239.description = Total electric additive operation time in hot water mode +channel-type.nibeheatpump.smo40-43473.label = Docked Heat Compressors +channel-type.nibeheatpump.smo40-43473.description = Number of compressors docked to heating +channel-type.nibeheatpump.smo40-43474.label = Docked Hot Water Compressors +channel-type.nibeheatpump.smo40-43474.description = Number of compressors docked to hot water +channel-type.nibeheatpump.smo40-43475.label = Docked Pool 1 Compressors +channel-type.nibeheatpump.smo40-43475.description = Number of compressors docked to pool 1 +channel-type.nibeheatpump.smo40-43514.label = EB100-EP14 PCA Base Relays +channel-type.nibeheatpump.smo40-43514.description = Indicates active relays on the PCA Base card. Please refer to the wiring diagram for relay description. Binary encoded. 1=on, 0=off. Bit0=K4,Bit1=K3,Bit2=K2,Bit3=K1 +channel-type.nibeheatpump.smo40-43514.state.option.1 = on +channel-type.nibeheatpump.smo40-43514.state.option.0 = off. Bit0 K4 Bit1 K3 Bit2 K2 Bit3 K1 +channel-type.nibeheatpump.smo40-43516.label = PCA-Power Relays EP14 +channel-type.nibeheatpump.smo40-43516.description = Indicates the active relays on the PCA-Power card. The information is binary encoded +channel-type.nibeheatpump.smo40-43555.label = HW Comfort Shunt State +channel-type.nibeheatpump.smo40-43555.description = 10=shunt off,20=shunt open,30=shunt closed +channel-type.nibeheatpump.smo40-43555.state.option.10 = shunt off +channel-type.nibeheatpump.smo40-43555.state.option.20 = shunt open +channel-type.nibeheatpump.smo40-43555.state.option.30 = shunt closed +channel-type.nibeheatpump.smo40-43556.label = HW Comfort Add Status +channel-type.nibeheatpump.smo40-43556.description = 1=on,0=off +channel-type.nibeheatpump.smo40-43556.state.option.1 = on +channel-type.nibeheatpump.smo40-43556.state.option.0 = off +channel-type.nibeheatpump.smo40-43560.label = Pool 2 blocked +channel-type.nibeheatpump.smo40-43561.label = Pool 1 blocked +channel-type.nibeheatpump.smo40-43563.label = GP9 Pool 2 Valve +channel-type.nibeheatpump.smo40-43564.label = GP9 Pool 1 Valve +channel-type.nibeheatpump.smo40-43577.label = Docked Pool 2 Compressors +channel-type.nibeheatpump.smo40-43577.description = Number of compressors docked to pool 2 +channel-type.nibeheatpump.smo40-43580.label = EB108 Version +channel-type.nibeheatpump.smo40-43598.label = EB108 Slave Type +channel-type.nibeheatpump.smo40-43599.label = EB108 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43621.label = EB108-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43621.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43624.label = EB108-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43624.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43625.label = EB108-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43625.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43626.label = EB108-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43626.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43627.label = EB108-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43627.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43631.label = EB108-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43635.label = EB108-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43637.label = EB108-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43639.label = EB108-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43641.label = EB108-EP14 Alarm number +channel-type.nibeheatpump.smo40-43641.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43642.label = EB107 Version +channel-type.nibeheatpump.smo40-43660.label = EB107 Slave Type +channel-type.nibeheatpump.smo40-43661.label = EB107 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43683.label = EB107-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43683.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43686.label = EB107-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43686.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43687.label = EB107-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43687.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43688.label = EB107-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43688.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43689.label = EB107-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43689.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43692.label = EB107-EP14 Compressor State +channel-type.nibeheatpump.smo40-43693.label = EB107-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43697.label = EB107-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43699.label = EB107-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43701.label = EB107-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43703.label = EB107-EP14 Alarm number +channel-type.nibeheatpump.smo40-43703.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43704.label = EB106 Version +channel-type.nibeheatpump.smo40-43722.label = EB106 Slave Type +channel-type.nibeheatpump.smo40-43723.label = EB106 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43745.label = EB106-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43745.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43748.label = EB106-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43748.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43749.label = EB106-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43749.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43750.label = EB106-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43750.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43751.label = EB106-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43751.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43755.label = EB106-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43759.label = EB106-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43761.label = EB106-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43763.label = EB106-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43765.label = EB106-EP14 Alarm number +channel-type.nibeheatpump.smo40-43765.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43766.label = EB105 Version +channel-type.nibeheatpump.smo40-43784.label = EB105 Slave Type +channel-type.nibeheatpump.smo40-43785.label = EB105 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43807.label = EB105-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43807.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43810.label = EB105-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43810.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43811.label = EB105-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43811.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43812.label = EB105-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43812.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43813.label = EB105-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43813.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43817.label = EB105-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43821.label = EB105-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43823.label = EB105-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43825.label = EB105-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43827.label = EB105-EP14 Alarm number +channel-type.nibeheatpump.smo40-43827.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43828.label = EB104 Version +channel-type.nibeheatpump.smo40-43846.label = EB104 Slave Type +channel-type.nibeheatpump.smo40-43847.label = EB104 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43869.label = EB104-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43869.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43872.label = EB104-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43872.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43873.label = EB104-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43873.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43874.label = EB104-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43874.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43875.label = EB104-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43875.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43879.label = EB104-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43883.label = EB104-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43885.label = EB104-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43887.label = EB104-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43889.label = EB104-EP14 Alarm number +channel-type.nibeheatpump.smo40-43889.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43890.label = EB103 Version +channel-type.nibeheatpump.smo40-43908.label = EB103 Slave Type +channel-type.nibeheatpump.smo40-43909.label = EB103 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43931.label = EB103-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43931.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43934.label = EB103-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43934.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43935.label = EB103-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43935.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43936.label = EB103-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43936.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43937.label = EB103-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43937.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-43941.label = EB103-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-43945.label = EB103-EP14 Compressor starts +channel-type.nibeheatpump.smo40-43947.label = EB103-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-43949.label = EB103-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-43951.label = EB103-EP14 Alarm number +channel-type.nibeheatpump.smo40-43951.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-43952.label = EB102 Version +channel-type.nibeheatpump.smo40-43970.label = EB102 Slave Type +channel-type.nibeheatpump.smo40-43971.label = EB102 Compressor EP14 Size +channel-type.nibeheatpump.smo40-43993.label = EB102-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-43993.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-43996.label = EB102-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-43996.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-43997.label = EB102-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-43997.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-43998.label = EB102-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-43998.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-43999.label = EB102-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-43999.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-44003.label = EB102-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-44007.label = EB102-EP14 Compressor starts +channel-type.nibeheatpump.smo40-44009.label = EB102-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-44011.label = EB102-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-44013.label = EB102-EP14 Alarm number +channel-type.nibeheatpump.smo40-44013.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-44014.label = EB101 Version +channel-type.nibeheatpump.smo40-44032.label = EB101 Slave Type +channel-type.nibeheatpump.smo40-44033.label = EB101 Compressor EP14 Size +channel-type.nibeheatpump.smo40-44055.label = EB101-EP14-BT3 Return Temp. +channel-type.nibeheatpump.smo40-44055.description = Return temperature, BT3 +channel-type.nibeheatpump.smo40-44058.label = EB101-EP14-BT12 Condensor Out +channel-type.nibeheatpump.smo40-44058.description = Condensor temperature, BT12 +channel-type.nibeheatpump.smo40-44059.label = EB101-EP14-BT14 Hot Gas Temp +channel-type.nibeheatpump.smo40-44059.description = Hot gas temperature, BT14 +channel-type.nibeheatpump.smo40-44060.label = EB101-EP14-BT15 Liquid Line +channel-type.nibeheatpump.smo40-44060.description = Liquid line temperature, BT15 +channel-type.nibeheatpump.smo40-44061.label = EB101-EP14-BT17 Suction +channel-type.nibeheatpump.smo40-44061.description = Suction temperature, BT17 +channel-type.nibeheatpump.smo40-44065.label = EB101-EP14 Compr. time to start +channel-type.nibeheatpump.smo40-44069.label = EB101-EP14 Compressor starts +channel-type.nibeheatpump.smo40-44071.label = EB101-EP14 Tot. op.time compr +channel-type.nibeheatpump.smo40-44073.label = EB101-EP14 Tot. HW op.time compr +channel-type.nibeheatpump.smo40-44075.label = EB101-EP14 Alarm number +channel-type.nibeheatpump.smo40-44075.description = The value indicates the most severe current alarm +channel-type.nibeheatpump.smo40-44139.label = EB108-EP14 Prio +channel-type.nibeheatpump.smo40-44139.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44139.state.option.0 = Off +channel-type.nibeheatpump.smo40-44139.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44139.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44139.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44139.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44139.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44152.label = EB107-EP14 Prio +channel-type.nibeheatpump.smo40-44152.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44152.state.option.0 = Off +channel-type.nibeheatpump.smo40-44152.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44152.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44152.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44152.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44152.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44165.label = EB106-EP14 Prio +channel-type.nibeheatpump.smo40-44165.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44165.state.option.0 = Off +channel-type.nibeheatpump.smo40-44165.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44165.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44165.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44165.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44165.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44178.label = EB105-EP14 Prio +channel-type.nibeheatpump.smo40-44178.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44178.state.option.0 = Off +channel-type.nibeheatpump.smo40-44178.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44178.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44178.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44178.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44178.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44191.label = EB104-EP14 Prio +channel-type.nibeheatpump.smo40-44191.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44191.state.option.0 = Off +channel-type.nibeheatpump.smo40-44191.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44191.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44191.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44191.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44191.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44204.label = EB103-EP14 Prio +channel-type.nibeheatpump.smo40-44204.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44204.state.option.0 = Off +channel-type.nibeheatpump.smo40-44204.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44204.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44204.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44204.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44204.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44217.label = EB102-EP14 Prio +channel-type.nibeheatpump.smo40-44217.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44217.state.option.0 = Off +channel-type.nibeheatpump.smo40-44217.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44217.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44217.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44217.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44217.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44230.label = EB101-EP14 Prio +channel-type.nibeheatpump.smo40-44230.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44230.state.option.0 = Off +channel-type.nibeheatpump.smo40-44230.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44230.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44230.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44230.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44230.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44243.label = EB100-EP14 Prio +channel-type.nibeheatpump.smo40-44243.description = Indicates what need is assigned to the compressor module, 0 = Off, 1 = Heat, 2 = Hot water, 3 = Pool 1, 4 = Pool2, 5=External Request +channel-type.nibeheatpump.smo40-44243.state.option.0 = Off +channel-type.nibeheatpump.smo40-44243.state.option.1 = Heat +channel-type.nibeheatpump.smo40-44243.state.option.2 = Hot water +channel-type.nibeheatpump.smo40-44243.state.option.3 = Pool 1 +channel-type.nibeheatpump.smo40-44243.state.option.4 = Pool2 +channel-type.nibeheatpump.smo40-44243.state.option.5 = External Request +channel-type.nibeheatpump.smo40-44256.label = Ext. Cooling Blocked +channel-type.nibeheatpump.smo40-44266.label = Cool Degree Minutes +channel-type.nibeheatpump.smo40-44267.label = Calc. Cooling Supply S4 +channel-type.nibeheatpump.smo40-44267.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-44268.label = Calc. Cooling Supply S3 +channel-type.nibeheatpump.smo40-44268.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-44269.label = Calc. Cooling Supply S2 +channel-type.nibeheatpump.smo40-44269.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-44270.label = Calc. Cooling Supply S1 +channel-type.nibeheatpump.smo40-44270.description = Calculated supply temperature in cooling mode for the climate system +channel-type.nibeheatpump.smo40-44282.label = Used cprs. HW +channel-type.nibeheatpump.smo40-44282.description = The number of compressors that's currently producing hot water +channel-type.nibeheatpump.smo40-44283.label = Used cprs. heat +channel-type.nibeheatpump.smo40-44283.description = The number of compressors that's currently producing heating +channel-type.nibeheatpump.smo40-44284.label = Used cprs. pool 1 +channel-type.nibeheatpump.smo40-44284.description = The number of compressors that's currently producing poolheating for pool 1 +channel-type.nibeheatpump.smo40-44285.label = Used cprs. pool 2 +channel-type.nibeheatpump.smo40-44285.description = The number of compressors that's currently producing poolheating for pool 2 +channel-type.nibeheatpump.smo40-44320.label = Used cprs. cool +channel-type.nibeheatpump.smo40-44320.description = The number of compressors that's currently producing active cooling +channel-type.nibeheatpump.smo40-44331.label = Software release +channel-type.nibeheatpump.smo40-44334.label = EB108-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44334.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44335.label = EB108-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44335.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44338.label = EB107-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44338.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44339.label = EB107-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44339.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44342.label = EB106-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44342.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44343.label = EB106-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44343.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44346.label = EB105-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44346.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44347.label = EB105-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44347.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44350.label = EB104-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44350.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44351.label = EB104-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44351.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44354.label = EB103-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44354.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44355.label = EB103-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44355.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44358.label = EB102-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44358.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44359.label = EB102-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44359.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44362.label = EB101-EP14-BT28 Outdoor Temp +channel-type.nibeheatpump.smo40-44362.description = Current outdoor temperature, BT28 +channel-type.nibeheatpump.smo40-44363.label = EB101-EP14-BT16 Evaporator +channel-type.nibeheatpump.smo40-44363.description = Evaporator temperature, BT16 +channel-type.nibeheatpump.smo40-44389.label = EB108 Speed charge pump +channel-type.nibeheatpump.smo40-44390.label = EB107 Speed charge pump +channel-type.nibeheatpump.smo40-44391.label = EB106 Speed charge pump +channel-type.nibeheatpump.smo40-44392.label = EB105 Speed charge pump +channel-type.nibeheatpump.smo40-44393.label = EB104 Speed charge pump +channel-type.nibeheatpump.smo40-44394.label = EB103 Speed charge pump +channel-type.nibeheatpump.smo40-44395.label = EB102 Speed charge pump +channel-type.nibeheatpump.smo40-44396.label = EB101 Speed charge pump +channel-type.nibeheatpump.smo40-44415.label = EB108-EP14 Compressor State +channel-type.nibeheatpump.smo40-44415.description = On/Off +channel-type.nibeheatpump.smo40-44421.label = EB107-EP14 Compressor State +channel-type.nibeheatpump.smo40-44421.description = On/Off +channel-type.nibeheatpump.smo40-44427.label = EB106-EP14 Compressor State +channel-type.nibeheatpump.smo40-44427.description = On/Off +channel-type.nibeheatpump.smo40-44433.label = EB105-EP14 Compressor State +channel-type.nibeheatpump.smo40-44433.description = On/Off +channel-type.nibeheatpump.smo40-44439.label = EB104-EP14 Compressor State +channel-type.nibeheatpump.smo40-44439.description = On/Off +channel-type.nibeheatpump.smo40-44445.label = EB103-EP14 Compressor State +channel-type.nibeheatpump.smo40-44445.description = On/Off +channel-type.nibeheatpump.smo40-44451.label = EB102-EP14 Compressor State +channel-type.nibeheatpump.smo40-44451.description = On/Off +channel-type.nibeheatpump.smo40-44457.label = EB101-EP14 Compressor State +channel-type.nibeheatpump.smo40-44457.description = On/Off +channel-type.nibeheatpump.smo40-44483.label = State of the extra additional heat in series +channel-type.nibeheatpump.smo40-44483.description = 0 = Off, 1 = On +channel-type.nibeheatpump.smo40-44483.state.option.0 = Off +channel-type.nibeheatpump.smo40-44483.state.option.1 = On +channel-type.nibeheatpump.smo40-44487.label = Docked Cool Compressors +channel-type.nibeheatpump.smo40-44487.description = Number of compressors docked to cooling +channel-type.nibeheatpump.smo40-44503.label = EB108-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44504.label = EB108-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44505.label = EB108-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44506.label = EB108-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44507.label = EB108-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44507.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44507.state.option.0 = No +channel-type.nibeheatpump.smo40-44507.state.option.1 = Active +channel-type.nibeheatpump.smo40-44507.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44510.label = EB108-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44531.label = EB107-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44532.label = EB107-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44533.label = EB107-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44534.label = EB107-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44535.label = EB107-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44535.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44535.state.option.0 = No +channel-type.nibeheatpump.smo40-44535.state.option.1 = Active +channel-type.nibeheatpump.smo40-44535.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44538.label = EB107-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44559.label = EB106-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44560.label = EB106-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44561.label = EB106-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44562.label = EB106-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44563.label = EB106-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44563.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44563.state.option.0 = No +channel-type.nibeheatpump.smo40-44563.state.option.1 = Active +channel-type.nibeheatpump.smo40-44563.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44566.label = EB106-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44587.label = EB105-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44588.label = EB105-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44589.label = EB105-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44590.label = EB105-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44591.label = EB105-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44591.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44591.state.option.0 = No +channel-type.nibeheatpump.smo40-44591.state.option.1 = Active +channel-type.nibeheatpump.smo40-44591.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44594.label = EB105-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44615.label = EB104-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44616.label = EB104-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44617.label = EB104-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44618.label = EB104-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44619.label = EB104-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44619.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44619.state.option.0 = No +channel-type.nibeheatpump.smo40-44619.state.option.1 = Active +channel-type.nibeheatpump.smo40-44619.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44622.label = EB104-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44643.label = EB103-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44644.label = EB103-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44645.label = EB103-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44646.label = EB103-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44647.label = EB103-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44647.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44647.state.option.0 = No +channel-type.nibeheatpump.smo40-44647.state.option.1 = Active +channel-type.nibeheatpump.smo40-44647.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44650.label = EB103-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44671.label = EB102-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44672.label = EB102-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44673.label = EB102-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44674.label = EB102-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44675.label = EB102-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44675.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44675.state.option.0 = No +channel-type.nibeheatpump.smo40-44675.state.option.1 = Active +channel-type.nibeheatpump.smo40-44675.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44678.label = EB102-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44699.label = EB101-EP14 High Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44700.label = EB101-EP14 Low Pressure Sensor Outdoor Unit +channel-type.nibeheatpump.smo40-44701.label = EB101-EP14 Actual Cpr Frequency Outdoor Unit +channel-type.nibeheatpump.smo40-44702.label = EB101-EP14 Protection Status Register Outdoor Unit +channel-type.nibeheatpump.smo40-44703.label = EB101-EP14 Defrosting Outdoor Unit +channel-type.nibeheatpump.smo40-44703.description = 0=No, 1=Active, 2 = Passive +channel-type.nibeheatpump.smo40-44703.state.option.0 = No +channel-type.nibeheatpump.smo40-44703.state.option.1 = Active +channel-type.nibeheatpump.smo40-44703.state.option.2 = Passive +channel-type.nibeheatpump.smo40-44706.label = EB101-EP14 Calculated Power Outdoor Unit +channel-type.nibeheatpump.smo40-44744.label = Extra heating system pump S4 +channel-type.nibeheatpump.smo40-44745.label = Extra heating system pump S3 +channel-type.nibeheatpump.smo40-44746.label = Extra heating system pump S2 +channel-type.nibeheatpump.smo40-44748.label = Pool 2 Pump Status +channel-type.nibeheatpump.smo40-44748.description = 1=on,0=off +channel-type.nibeheatpump.smo40-44748.state.option.1 = on +channel-type.nibeheatpump.smo40-44748.state.option.0 = off +channel-type.nibeheatpump.smo40-44749.label = Pool 1 Pump Status +channel-type.nibeheatpump.smo40-44749.description = 1=on,0=off +channel-type.nibeheatpump.smo40-44749.state.option.1 = on +channel-type.nibeheatpump.smo40-44749.state.option.0 = off +channel-type.nibeheatpump.smo40-44761.label = EB108-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44761.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44763.label = EB107-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44763.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44765.label = EB106-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44765.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44767.label = EB105-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44767.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44769.label = EB104-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44769.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44771.label = EB103-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44771.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44773.label = EB102-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44773.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44775.label = EB101-EP14 calc. ou compressor freq +channel-type.nibeheatpump.smo40-44775.description = Calculated compressor frequency +channel-type.nibeheatpump.smo40-44824.label = EB108-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44825.label = EB108-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44825.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44825.state.option.0 = No +channel-type.nibeheatpump.smo40-44825.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44830.label = EB107-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44831.label = EB107-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44831.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44831.state.option.0 = No +channel-type.nibeheatpump.smo40-44831.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44836.label = EB106-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44837.label = EB106-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44837.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44837.state.option.0 = No +channel-type.nibeheatpump.smo40-44837.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44842.label = EB105-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44843.label = EB105-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44843.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44843.state.option.0 = No +channel-type.nibeheatpump.smo40-44843.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44848.label = EB104-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44849.label = EB104-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44849.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44849.state.option.0 = No +channel-type.nibeheatpump.smo40-44849.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44854.label = EB103-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44855.label = EB103-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44855.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44855.state.option.0 = No +channel-type.nibeheatpump.smo40-44855.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44860.label = EB102-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44861.label = EB102-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44861.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44861.state.option.0 = No +channel-type.nibeheatpump.smo40-44861.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44866.label = EB101-EP14 Current Sensor +channel-type.nibeheatpump.smo40-44867.label = EB101-EP14 Hz Down Mode Outdoor Unit +channel-type.nibeheatpump.smo40-44867.description = 0=No, 1=Yes +channel-type.nibeheatpump.smo40-44867.state.option.0 = No +channel-type.nibeheatpump.smo40-44867.state.option.1 = Yes +channel-type.nibeheatpump.smo40-44874.label = State SG Ready +channel-type.nibeheatpump.smo40-44878.label = SG Ready input A +channel-type.nibeheatpump.smo40-44879.label = SG Ready input B +channel-type.nibeheatpump.smo40-44896.label = Smart Price Adaption Heating Offset +channel-type.nibeheatpump.smo40-44897.label = Smart Price Adaption HW Comfort Mode +channel-type.nibeheatpump.smo40-44897.description = 0=Eco,1=Normal,2=Luxury,10=Normal+,20=Mini +channel-type.nibeheatpump.smo40-44897.state.option.0 = Eco +channel-type.nibeheatpump.smo40-44897.state.option.1 = Normal +channel-type.nibeheatpump.smo40-44897.state.option.2 = Luxury +channel-type.nibeheatpump.smo40-44897.state.option.10 = Normal+ +channel-type.nibeheatpump.smo40-44897.state.option.20 = Mini +channel-type.nibeheatpump.smo40-44898.label = Smart Price Adaption Pool Offset +channel-type.nibeheatpump.smo40-44899.label = Smart Price Adaption Cool Offset +channel-type.nibeheatpump.smo40-44908.label = State smart price adaption +channel-type.nibeheatpump.smo40-44935.label = EB108-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44935.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44936.label = EB108-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44936.description = Inverter temperature +channel-type.nibeheatpump.smo40-44937.label = EB108-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44941.label = EB107-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44941.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44942.label = EB107-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44942.description = Inverter temperature +channel-type.nibeheatpump.smo40-44943.label = EB107-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44947.label = EB106-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44947.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44948.label = EB106-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44948.description = Inverter temperature +channel-type.nibeheatpump.smo40-44949.label = EB106-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44953.label = EB105-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44953.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44954.label = EB105-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44954.description = Inverter temperature +channel-type.nibeheatpump.smo40-44955.label = EB105-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44959.label = EB104-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44959.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44960.label = EB104-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44960.description = Inverter temperature +channel-type.nibeheatpump.smo40-44961.label = EB104-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44965.label = EB103-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44965.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44966.label = EB103-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44966.description = Inverter temperature +channel-type.nibeheatpump.smo40-44967.label = EB103-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44971.label = EB102-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44971.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44972.label = EB102-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44972.description = Inverter temperature +channel-type.nibeheatpump.smo40-44973.label = EB102-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-44977.label = EB101-EP14-BT16 Evaporator 2 +channel-type.nibeheatpump.smo40-44977.description = Evaporator 2 temperature, BT16 +channel-type.nibeheatpump.smo40-44978.label = EB101-EP14 Inverter Temperature +channel-type.nibeheatpump.smo40-44978.description = Inverter temperature +channel-type.nibeheatpump.smo40-44979.label = EB101-EP14-Fan Speed Step +channel-type.nibeheatpump.smo40-45001.label = Alarm +channel-type.nibeheatpump.smo40-45001.description = Indicates the alarm number of the most severe current alarm +channel-type.nibeheatpump.smo40-45171.label = Alarm Reset +channel-type.nibeheatpump.smo40-45171.description = Reset alarm by setting value 1 +channel-type.nibeheatpump.smo40-45780.label = Silent Mode Frequency 1 +channel-type.nibeheatpump.smo40-45780.description = Silent Mode Frequency 1 +channel-type.nibeheatpump.smo40-47004.label = Heat Curve S4 +channel-type.nibeheatpump.smo40-47004.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47005.label = Heat Curve S3 +channel-type.nibeheatpump.smo40-47005.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47006.label = Heat Curve S2 +channel-type.nibeheatpump.smo40-47006.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47007.label = Heat Curve S1 +channel-type.nibeheatpump.smo40-47007.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47008.label = Heat Offset S4 +channel-type.nibeheatpump.smo40-47008.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47009.label = Heat Offset S3 +channel-type.nibeheatpump.smo40-47009.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47010.label = Heat Offset S2 +channel-type.nibeheatpump.smo40-47010.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47011.label = Heat Offset S1 +channel-type.nibeheatpump.smo40-47011.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47012.label = Min Supply System 4 +channel-type.nibeheatpump.smo40-47013.label = Min Supply System 3 +channel-type.nibeheatpump.smo40-47014.label = Min Supply System 2 +channel-type.nibeheatpump.smo40-47015.label = Min Supply System 1 +channel-type.nibeheatpump.smo40-47016.label = Max Supply System 4 +channel-type.nibeheatpump.smo40-47017.label = Max Supply System 3 +channel-type.nibeheatpump.smo40-47018.label = Max Supply System 2 +channel-type.nibeheatpump.smo40-47019.label = Max Supply System 1 +channel-type.nibeheatpump.smo40-47020.label = Own Heating Curve P7 +channel-type.nibeheatpump.smo40-47020.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47021.label = Own Heating Curve P6 +channel-type.nibeheatpump.smo40-47021.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47022.label = Own Heating Curve P5 +channel-type.nibeheatpump.smo40-47022.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47023.label = Own Heating Curve P4 +channel-type.nibeheatpump.smo40-47023.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47024.label = Own Heating Curve P3 +channel-type.nibeheatpump.smo40-47024.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47025.label = Own Heating Curve P2 +channel-type.nibeheatpump.smo40-47025.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47026.label = Own Heating Curve P1 +channel-type.nibeheatpump.smo40-47026.description = User defined heating curve point +channel-type.nibeheatpump.smo40-47027.label = Point offset outdoor temp. +channel-type.nibeheatpump.smo40-47027.description = Outdoor temperature point where the heat curve is offset +channel-type.nibeheatpump.smo40-47028.label = Point offset +channel-type.nibeheatpump.smo40-47028.description = Amount of offset at the point offset temperature +channel-type.nibeheatpump.smo40-47029.label = External adjustment S4 +channel-type.nibeheatpump.smo40-47029.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-47030.label = External adjustment S3 +channel-type.nibeheatpump.smo40-47030.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-47031.label = External adjustment S2 +channel-type.nibeheatpump.smo40-47031.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-47032.label = External adjustment S1 +channel-type.nibeheatpump.smo40-47032.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-47033.label = External adjustment with room sensor S4 +channel-type.nibeheatpump.smo40-47033.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-47034.label = External adjustment with room sensor S3 +channel-type.nibeheatpump.smo40-47034.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-47035.label = External adjustment with room sensor S2 +channel-type.nibeheatpump.smo40-47035.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-47036.label = External adjustment with room sensor S1 +channel-type.nibeheatpump.smo40-47036.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-47041.label = Hot water comfort mode +channel-type.nibeheatpump.smo40-47041.description = Setting in menu 2.2. 0=Economy,1=Normal,2=Luxury,4=Smart Control 0=Economy 1=Normal 2=Luxury +channel-type.nibeheatpump.smo40-47041.state.option.0 = Economy +channel-type.nibeheatpump.smo40-47041.state.option.1 = Normal +channel-type.nibeheatpump.smo40-47041.state.option.2 = Luxury +channel-type.nibeheatpump.smo40-47041.state.option.4 = Smart Control +channel-type.nibeheatpump.smo40-47041.state.option.0 = Economy +channel-type.nibeheatpump.smo40-47041.state.option.1 = Normal +channel-type.nibeheatpump.smo40-47041.state.option.2 = Luxury +channel-type.nibeheatpump.smo40-47043.label = Start temperature HW Luxury +channel-type.nibeheatpump.smo40-47043.description = Start temperature for heating water +channel-type.nibeheatpump.smo40-47044.label = Start temperature HW Normal +channel-type.nibeheatpump.smo40-47044.description = Start temperature for heating water +channel-type.nibeheatpump.smo40-47045.label = Start temperature HW Economy +channel-type.nibeheatpump.smo40-47045.description = Start temperature for heating water +channel-type.nibeheatpump.smo40-47046.label = Stop temperature Periodic HW +channel-type.nibeheatpump.smo40-47046.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.smo40-47047.label = Stop temperature HW Luxury +channel-type.nibeheatpump.smo40-47047.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.smo40-47048.label = Stop temperature HW Normal +channel-type.nibeheatpump.smo40-47048.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.smo40-47049.label = Stop temperature HW Economy +channel-type.nibeheatpump.smo40-47049.description = Temperature where hot water generation will stop +channel-type.nibeheatpump.smo40-47050.label = Periodic HW +channel-type.nibeheatpump.smo40-47050.description = Activates the periodic hot water generation +channel-type.nibeheatpump.smo40-47051.label = Periodic HW Interval +channel-type.nibeheatpump.smo40-47051.description = Interval between Periodic hot water sessions +channel-type.nibeheatpump.smo40-47054.label = Run time HWC +channel-type.nibeheatpump.smo40-47054.description = Run time for the hot water circulation system +channel-type.nibeheatpump.smo40-47055.label = Still time HWC +channel-type.nibeheatpump.smo40-47055.description = Still time for the hot water circulation system +channel-type.nibeheatpump.smo40-47131.label = Language +channel-type.nibeheatpump.smo40-47131.description = Display language in the heat pump 0=English 1=Svenska 2=Deutsch 3=Francais 4=Espanol 5=Suomi 6=Lietuviu 7=Cesky 8=Polski 9=Nederlands 10=Norsk 11=Dansk 12=Eesti 13=Latviesu 16=Magyar +channel-type.nibeheatpump.smo40-47131.state.option.0 = English +channel-type.nibeheatpump.smo40-47131.state.option.1 = Svenska +channel-type.nibeheatpump.smo40-47131.state.option.2 = Deutsch +channel-type.nibeheatpump.smo40-47131.state.option.3 = Francais +channel-type.nibeheatpump.smo40-47131.state.option.4 = Espanol +channel-type.nibeheatpump.smo40-47131.state.option.5 = Suomi +channel-type.nibeheatpump.smo40-47131.state.option.6 = Lietuviu +channel-type.nibeheatpump.smo40-47131.state.option.7 = Cesky +channel-type.nibeheatpump.smo40-47131.state.option.8 = Polski +channel-type.nibeheatpump.smo40-47131.state.option.9 = Nederlands +channel-type.nibeheatpump.smo40-47131.state.option.10 = Norsk +channel-type.nibeheatpump.smo40-47131.state.option.11 = Dansk +channel-type.nibeheatpump.smo40-47131.state.option.12 = Eesti +channel-type.nibeheatpump.smo40-47131.state.option.13 = Latviesu +channel-type.nibeheatpump.smo40-47131.state.option.16 = Magyar +channel-type.nibeheatpump.smo40-47134.label = Period HW +channel-type.nibeheatpump.smo40-47135.label = Period Heat +channel-type.nibeheatpump.smo40-47136.label = Period Pool +channel-type.nibeheatpump.smo40-47137.label = Operational mode +channel-type.nibeheatpump.smo40-47137.description = The operational mode of the heat pump 0=Auto 1=Manual 2=Add. heat only +channel-type.nibeheatpump.smo40-47137.state.option.0 = Auto +channel-type.nibeheatpump.smo40-47137.state.option.1 = Manual +channel-type.nibeheatpump.smo40-47137.state.option.2 = Add. heat only +channel-type.nibeheatpump.smo40-47138.label = Operational mode heat medium pump +channel-type.nibeheatpump.smo40-47138.description = 10=Intermittent 20=Continous 30=Economy 40=Auto +channel-type.nibeheatpump.smo40-47138.state.option.10 = Intermittent +channel-type.nibeheatpump.smo40-47138.state.option.20 = Continous +channel-type.nibeheatpump.smo40-47138.state.option.30 = Economy +channel-type.nibeheatpump.smo40-47138.state.option.40 = Auto +channel-type.nibeheatpump.smo40-47206.label = DM start heating +channel-type.nibeheatpump.smo40-47206.description = The value the degree minutes needed to be reached for the pump to start heating +channel-type.nibeheatpump.smo40-47209.label = DM between add. steps +channel-type.nibeheatpump.smo40-47209.description = The number of degree minutes between start of each electric addition step +channel-type.nibeheatpump.smo40-47210.label = DM start add. with shunt +channel-type.nibeheatpump.smo40-47214.label = Fuse +channel-type.nibeheatpump.smo40-47214.description = Size of the fuse that the HP is connected to +channel-type.nibeheatpump.smo40-47271.label = Fan return time 4 +channel-type.nibeheatpump.smo40-47271.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.smo40-47272.label = Fan return time 3 +channel-type.nibeheatpump.smo40-47272.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.smo40-47273.label = Fan return time 2 +channel-type.nibeheatpump.smo40-47273.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.smo40-47274.label = Fan return time 1 +channel-type.nibeheatpump.smo40-47274.description = Time from a changed fan speed until it returns to normal speed +channel-type.nibeheatpump.smo40-47275.label = Filter Reminder period +channel-type.nibeheatpump.smo40-47275.description = Time between the reminder of filter replacement/cleaning. +channel-type.nibeheatpump.smo40-47276.label = Floor drying +channel-type.nibeheatpump.smo40-47276.description = 0=Off 1=On +channel-type.nibeheatpump.smo40-47277.label = Floor drying period 7 +channel-type.nibeheatpump.smo40-47277.description = Days each period is active +channel-type.nibeheatpump.smo40-47278.label = Floor drying period 6 +channel-type.nibeheatpump.smo40-47278.description = Days each period is active +channel-type.nibeheatpump.smo40-47279.label = Floor drying period 5 +channel-type.nibeheatpump.smo40-47279.description = Days each period is active +channel-type.nibeheatpump.smo40-47280.label = Floor drying period 4 +channel-type.nibeheatpump.smo40-47280.description = Days each period is active +channel-type.nibeheatpump.smo40-47281.label = Floor drying period 3 +channel-type.nibeheatpump.smo40-47281.description = Days each period is active +channel-type.nibeheatpump.smo40-47282.label = Floor drying period 2 +channel-type.nibeheatpump.smo40-47282.description = Days each period is active +channel-type.nibeheatpump.smo40-47283.label = Floor drying period 1 +channel-type.nibeheatpump.smo40-47283.description = Days each period is active +channel-type.nibeheatpump.smo40-47284.label = Floor drying temp. 7 +channel-type.nibeheatpump.smo40-47284.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47285.label = Floor drying temp. 6 +channel-type.nibeheatpump.smo40-47285.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47286.label = Floor drying temp. 5 +channel-type.nibeheatpump.smo40-47286.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47287.label = Floor drying temp. 4 +channel-type.nibeheatpump.smo40-47287.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47288.label = Floor drying temp. 3 +channel-type.nibeheatpump.smo40-47288.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47289.label = Floor drying temp. 2 +channel-type.nibeheatpump.smo40-47289.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47290.label = Floor drying temp. 1 +channel-type.nibeheatpump.smo40-47290.description = Supply temperature each period +channel-type.nibeheatpump.smo40-47291.label = Floor drying timer +channel-type.nibeheatpump.smo40-47300.label = DOT +channel-type.nibeheatpump.smo40-47300.description = Dimensioning outdoor temperature +channel-type.nibeheatpump.smo40-47301.label = delta T at DOT +channel-type.nibeheatpump.smo40-47301.description = Delta T (BT12-BT3)at dimensioning outdoor temperature +channel-type.nibeheatpump.smo40-47302.label = Climate system 2 accessory +channel-type.nibeheatpump.smo40-47302.description = Activates the climate system 2 accessory 0=Off 1=On +channel-type.nibeheatpump.smo40-47303.label = Climate system 3 accessory +channel-type.nibeheatpump.smo40-47303.description = Activates the climate system 3 accessory 0=Off 1=On +channel-type.nibeheatpump.smo40-47304.label = Climate system 4 accessory +channel-type.nibeheatpump.smo40-47304.description = Activates the climate system 4 accessory 0=Off 1=On +channel-type.nibeheatpump.smo40-47305.label = Climate system 4 mixing valve amp. +channel-type.nibeheatpump.smo40-47305.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-47306.label = Climate system 3 mixing valve amp. +channel-type.nibeheatpump.smo40-47306.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-47307.label = Climate system 2 mixing valve amp. +channel-type.nibeheatpump.smo40-47307.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-47308.label = Climate system 4 shunt wait +channel-type.nibeheatpump.smo40-47308.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-47309.label = Climate system 3 shunt wait +channel-type.nibeheatpump.smo40-47309.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-47310.label = Climate system 2 shunt wait +channel-type.nibeheatpump.smo40-47310.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-47317.label = Shunt controlled add. accessory +channel-type.nibeheatpump.smo40-47317.description = Activates the shunt controlled addition accessory. 1=on,0=off 0=Off 1=On +channel-type.nibeheatpump.smo40-47318.label = Shunt controlled add. min. temp. +channel-type.nibeheatpump.smo40-47319.label = Shunt controlled add. min. runtime +channel-type.nibeheatpump.smo40-47320.label = Shunt controlled add. mixing valve amp. +channel-type.nibeheatpump.smo40-47320.description = Mixing valve amplification for shunt controlled add. +channel-type.nibeheatpump.smo40-47321.label = Shunt controlled add. mixing valve wait +channel-type.nibeheatpump.smo40-47321.description = Wait time between changes of the shunt in shunt controlled add. +channel-type.nibeheatpump.smo40-47322.label = Step controlled add. accessory +channel-type.nibeheatpump.smo40-47322.description = Activates the step controlled addition accessory 0=Off 1=On +channel-type.nibeheatpump.smo40-47324.label = Step controlled add. diff. DM +channel-type.nibeheatpump.smo40-47324.description = Difference in DM of each step in the step controlled add. +channel-type.nibeheatpump.smo40-47325.label = Step controlled add. max. step +channel-type.nibeheatpump.smo40-47325.description = Maximum number of steps allowed in step controlled add. +channel-type.nibeheatpump.smo40-47326.label = Step controlled add. mode +channel-type.nibeheatpump.smo40-47326.description = Binary or linear stepping method. 0=Linear 1=Binary +channel-type.nibeheatpump.smo40-47335.label = Time betw. switch heat/cool +channel-type.nibeheatpump.smo40-47335.description = Time between switching from heating to cooling or vice versa. +channel-type.nibeheatpump.smo40-47336.label = Heat at room under temp. +channel-type.nibeheatpump.smo40-47336.description = This value indicates how many degrees under set room temp heating will be allowed +channel-type.nibeheatpump.smo40-47337.label = Cool at room over temp. +channel-type.nibeheatpump.smo40-47337.description = This value indicates how many degrees over set room temp cooling will be allowed +channel-type.nibeheatpump.smo40-47339.label = Cooling mix. valve step delay +channel-type.nibeheatpump.smo40-47340.label = Cooling with room sensor +channel-type.nibeheatpump.smo40-47340.description = Enables use of room sensor together with cooling 0=Off 1=On +channel-type.nibeheatpump.smo40-47340.state.option.0 = Off +channel-type.nibeheatpump.smo40-47340.state.option.1 = On +channel-type.nibeheatpump.smo40-47343.label = Start Active Cooling DM +channel-type.nibeheatpump.smo40-47343.description = Value the degree minutes have to reach to start active cooling +channel-type.nibeheatpump.smo40-47352.label = SMS40 accessory +channel-type.nibeheatpump.smo40-47352.description = Activates the SMS40 accessory +channel-type.nibeheatpump.smo40-47365.label = RMU System 1 +channel-type.nibeheatpump.smo40-47365.description = Activates the RMU accessory for system 1 +channel-type.nibeheatpump.smo40-47366.label = RMU System 2 +channel-type.nibeheatpump.smo40-47366.description = Activates the RMU accessory for system 2 +channel-type.nibeheatpump.smo40-47367.label = RMU System 3 +channel-type.nibeheatpump.smo40-47367.description = Activates the RMU accessory for system 3 +channel-type.nibeheatpump.smo40-47368.label = RMU System 4 +channel-type.nibeheatpump.smo40-47368.description = Activates the RMU accessory for system 4 +channel-type.nibeheatpump.smo40-47370.label = Allow Additive Heating +channel-type.nibeheatpump.smo40-47370.description = Whether to allow additive heating (only valid for operational mode Manual) +channel-type.nibeheatpump.smo40-47371.label = Allow Heating +channel-type.nibeheatpump.smo40-47371.description = Whether to allow heating (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.smo40-47372.label = Allow Cooling +channel-type.nibeheatpump.smo40-47372.description = Whether to allow cooling (only valid for operational mode Manual or Add. heat only) +channel-type.nibeheatpump.smo40-47374.label = Start Temperature Cooling +channel-type.nibeheatpump.smo40-47374.description = Start temperature for cooling, as set in menu 4.9.2 0=Off 1=On +channel-type.nibeheatpump.smo40-47374.state.option.0 = Off +channel-type.nibeheatpump.smo40-47374.state.option.1 = On +channel-type.nibeheatpump.smo40-47375.label = Stop Temperature Heating +channel-type.nibeheatpump.smo40-47375.description = Stop temperature for heating, as set in menu 4.9.2 +channel-type.nibeheatpump.smo40-47376.label = Stop Temperature Additive +channel-type.nibeheatpump.smo40-47376.description = Stop temperature for additive, as set in menu 4.9.2 +channel-type.nibeheatpump.smo40-47377.label = Outdoor Filter Time +channel-type.nibeheatpump.smo40-47377.description = 12=12 Hours 24=24 Hours +channel-type.nibeheatpump.smo40-47377.state.option.12 = Hours 24 +channel-type.nibeheatpump.smo40-47377.state.option.24 = Hours +channel-type.nibeheatpump.smo40-47378.label = Max diff. comp. +channel-type.nibeheatpump.smo40-47379.label = Max diff. add. +channel-type.nibeheatpump.smo40-47384.label = Date format +channel-type.nibeheatpump.smo40-47384.description = 1=DD-MM-YY 2=YY-MM-DD +channel-type.nibeheatpump.smo40-47384.state.option.1 = DD-MM-YY +channel-type.nibeheatpump.smo40-47384.state.option.2 = YY-MM-DD +channel-type.nibeheatpump.smo40-47385.label = Time format +channel-type.nibeheatpump.smo40-47385.description = 12=12 hours 24=24 Hours +channel-type.nibeheatpump.smo40-47385.state.option.12 = hours 24 +channel-type.nibeheatpump.smo40-47385.state.option.24 = Hours +channel-type.nibeheatpump.smo40-47387.label = HW production +channel-type.nibeheatpump.smo40-47387.description = Activates hot water production where applicable 0=Off 1=On +channel-type.nibeheatpump.smo40-47388.label = Alarm lower room temp. +channel-type.nibeheatpump.smo40-47388.description = Lowers the room temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.smo40-47389.label = Alarm lower HW temp. +channel-type.nibeheatpump.smo40-47389.description = Lowers the hot water temperature during red light alarms to notify the occupants of the building that something is the matter 0=Off 1=On +channel-type.nibeheatpump.smo40-47391.label = Use room sensor S4 +channel-type.nibeheatpump.smo40-47391.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.smo40-47392.label = Use room sensor S3 +channel-type.nibeheatpump.smo40-47392.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.smo40-47393.label = Use room sensor S2 +channel-type.nibeheatpump.smo40-47393.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.smo40-47394.label = Use room sensor S1 +channel-type.nibeheatpump.smo40-47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-type.nibeheatpump.smo40-47395.label = Room sensor setpoint S4 +channel-type.nibeheatpump.smo40-47395.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-47396.label = Room sensor setpoint S3 +channel-type.nibeheatpump.smo40-47396.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-47397.label = Room sensor setpoint S2 +channel-type.nibeheatpump.smo40-47397.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-47398.label = Room sensor setpoint S1 +channel-type.nibeheatpump.smo40-47398.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-47399.label = Room sensor factor S4 +channel-type.nibeheatpump.smo40-47399.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-47400.label = Room sensor factor S3 +channel-type.nibeheatpump.smo40-47400.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-47401.label = Room sensor factor S2 +channel-type.nibeheatpump.smo40-47401.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-47402.label = Room sensor factor S1 +channel-type.nibeheatpump.smo40-47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-47442.label = preset flow clim. sys. +channel-type.nibeheatpump.smo40-47442.description = Preset flow setting for climate system. 0 = manual setting, 1 = radiator, 2 = floor heating, 3 = radiator + floor heating. +channel-type.nibeheatpump.smo40-47442.state.option.0 = manual setting +channel-type.nibeheatpump.smo40-47442.state.option.1 = radiator +channel-type.nibeheatpump.smo40-47442.state.option.2 = floor heating +channel-type.nibeheatpump.smo40-47442.state.option.3 = radiator + floor heating. +channel-type.nibeheatpump.smo40-47525.label = Heat Curve S8 +channel-type.nibeheatpump.smo40-47525.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47537.label = Night cooling +channel-type.nibeheatpump.smo40-47537.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. 0=Off 1=On +channel-type.nibeheatpump.smo40-47538.label = Start room temp. night cooling +channel-type.nibeheatpump.smo40-47539.label = Night Cooling Min. diff. +channel-type.nibeheatpump.smo40-47539.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.smo40-47540.label = Heat DM diff +channel-type.nibeheatpump.smo40-47540.description = Difference in DM between compressor starts in heating mode +channel-type.nibeheatpump.smo40-47543.label = Cooling DM diff +channel-type.nibeheatpump.smo40-47543.description = Difference in DM between compressor starts in cooling mode +channel-type.nibeheatpump.smo40-47567.label = Heat Curve S7 +channel-type.nibeheatpump.smo40-47567.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-47613.label = Max Internal Add +channel-type.nibeheatpump.smo40-47613.description = Maximum allowed steps for the internally connected addition. +channel-type.nibeheatpump.smo40-47614.label = Int. connected add. mode +channel-type.nibeheatpump.smo40-47614.description = Binary or linear stepping method for the internally connected external addition. 0=Linear 1=Binary +channel-type.nibeheatpump.smo40-48043.label = Holiday - Activated +channel-type.nibeheatpump.smo40-48043.description = 0=inactive, 10=active +channel-type.nibeheatpump.smo40-48043.state.option.0 = inactive +channel-type.nibeheatpump.smo40-48043.state.option.10 = active +channel-type.nibeheatpump.smo40-48072.label = DM diff start add. +channel-type.nibeheatpump.smo40-48072.description = The value below the last compressor step the degree minutes needed to be reached for the pump to start electric addition +channel-type.nibeheatpump.smo40-48074.label = Cool/Heat Sensor Set Point +channel-type.nibeheatpump.smo40-48074.description = Set point for change between cooling and heating when using the cool/heat sensor +channel-type.nibeheatpump.smo40-48085.label = Heat medium pump manual speed +channel-type.nibeheatpump.smo40-48085.description = Heat medium pump speed if manual +channel-type.nibeheatpump.smo40-48087.label = Pool 2 accessory +channel-type.nibeheatpump.smo40-48087.description = Activate the pool 2 accessory +channel-type.nibeheatpump.smo40-48088.label = Pool 1 accessory +channel-type.nibeheatpump.smo40-48088.description = Activates the pool 1 accessory +channel-type.nibeheatpump.smo40-48089.label = Pool 2 start temp. +channel-type.nibeheatpump.smo40-48089.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.smo40-48090.label = Pool 1 start temp. +channel-type.nibeheatpump.smo40-48090.description = The Temperature below which the pool heating should start +channel-type.nibeheatpump.smo40-48091.label = Pool 2 stop temp. +channel-type.nibeheatpump.smo40-48091.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.smo40-48092.label = Pool 1 stop temp. +channel-type.nibeheatpump.smo40-48092.description = The Temperature at which the pool heating will stop +channel-type.nibeheatpump.smo40-48093.label = Pool 2 Activated +channel-type.nibeheatpump.smo40-48093.description = Activates pool heating +channel-type.nibeheatpump.smo40-48094.label = Pool 1 Activated +channel-type.nibeheatpump.smo40-48094.description = Activates pool heating +channel-type.nibeheatpump.smo40-48130.label = Manual heat medium pump speed +channel-type.nibeheatpump.smo40-48130.description = Manual heat medium pump speed? +channel-type.nibeheatpump.smo40-48132.label = Temporary Lux +channel-type.nibeheatpump.smo40-48132.description = 0=Off, 1=3h, 2=6h, 3=12h, 4=One time increase +channel-type.nibeheatpump.smo40-48132.state.option.0 = Off +channel-type.nibeheatpump.smo40-48132.state.option.1 = 3h +channel-type.nibeheatpump.smo40-48132.state.option.2 = 6h +channel-type.nibeheatpump.smo40-48132.state.option.3 = 12h +channel-type.nibeheatpump.smo40-48132.state.option.4 = One time increase +channel-type.nibeheatpump.smo40-48133.label = Period Pool 2 +channel-type.nibeheatpump.smo40-48139.label = DM startdiff add. with shunt +channel-type.nibeheatpump.smo40-48140.label = Max pool 2 compr. +channel-type.nibeheatpump.smo40-48140.description = Maximum number of compressors that are simultaneously charging the pool +channel-type.nibeheatpump.smo40-48141.label = Max pool 1 compr. +channel-type.nibeheatpump.smo40-48141.description = Maximum number of compressors that are simultaneously charging the pool +channel-type.nibeheatpump.smo40-48142.label = Step controlled add. start diff DM +channel-type.nibeheatpump.smo40-48142.description = DM diff from last compressor step where the first step of step controlled add. starts +channel-type.nibeheatpump.smo40-48156.label = External cooling accessory +channel-type.nibeheatpump.smo40-48156.description = Activates the external cooling accessory +channel-type.nibeheatpump.smo40-48174.label = Min cooling supply temp S4 +channel-type.nibeheatpump.smo40-48174.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48175.label = Min cooling supply temp S3 +channel-type.nibeheatpump.smo40-48175.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48176.label = Min cooling supply temp S2 +channel-type.nibeheatpump.smo40-48176.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48177.label = Min cooling supply temp S1 +channel-type.nibeheatpump.smo40-48177.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48181.label = Own Cooling Curve P3 +channel-type.nibeheatpump.smo40-48181.description = User defined cooling curve point +channel-type.nibeheatpump.smo40-48185.label = Own Cooling Curve P5 +channel-type.nibeheatpump.smo40-48185.description = User defined cooling curve point +channel-type.nibeheatpump.smo40-48186.label = Cooling use mix. valve S4 +channel-type.nibeheatpump.smo40-48186.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48187.label = Cooling use mix. valve S3 +channel-type.nibeheatpump.smo40-48187.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48188.label = Cooling use mix. valve S2 +channel-type.nibeheatpump.smo40-48188.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48189.label = Cooling use mix. valve S1 +channel-type.nibeheatpump.smo40-48189.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48206.label = Silent Mode Status +channel-type.nibeheatpump.smo40-48206.description = 1 = active, 0 = inactive +channel-type.nibeheatpump.smo40-48206.state.option.1 = active +channel-type.nibeheatpump.smo40-48206.state.option.0 = inactive +channel-type.nibeheatpump.smo40-48207.label = Period Cool +channel-type.nibeheatpump.smo40-48214.label = Cooling delta temp. at 20°C +channel-type.nibeheatpump.smo40-48214.description = Delta Temperature at 20°C. Used to control charge pump speed +channel-type.nibeheatpump.smo40-48215.label = Cooling delta temp. at 40°C +channel-type.nibeheatpump.smo40-48215.description = Delta Temperature at 40°C. Used to control charge pump speed +channel-type.nibeheatpump.smo40-48228.label = Operational mode charge pump S8 +channel-type.nibeheatpump.smo40-48229.label = Operational mode charge pump S7 +channel-type.nibeheatpump.smo40-48230.label = Operational mode charge pump S6 +channel-type.nibeheatpump.smo40-48231.label = Operational mode charge pump S5 +channel-type.nibeheatpump.smo40-48232.label = Operational mode charge pump S4 +channel-type.nibeheatpump.smo40-48233.label = Operational mode charge pump S3 +channel-type.nibeheatpump.smo40-48234.label = Operational mode charge pump S2 +channel-type.nibeheatpump.smo40-48235.label = Operational mode charge pump S1 +channel-type.nibeheatpump.smo40-48274.label = Hot Water Stepdiff Compressor +channel-type.nibeheatpump.smo40-48279.label = Position of Addition +channel-type.nibeheatpump.smo40-48279.description = Addition before QN10:0, Addition after QN10:1 +channel-type.nibeheatpump.smo40-48280.label = Internal HW add in tank +channel-type.nibeheatpump.smo40-48280.description = Internal HW add in tank +channel-type.nibeheatpump.smo40-48281.label = Charge method HW +channel-type.nibeheatpump.smo40-48281.description = Heating medium pump control when hot water is charged +channel-type.nibeheatpump.smo40-48282.label = SG Ready heating +channel-type.nibeheatpump.smo40-48282.description = Sets whether or not SG Ready should affect heating +channel-type.nibeheatpump.smo40-48283.label = SG Ready cooling +channel-type.nibeheatpump.smo40-48283.description = Sets whether or not SG Ready should affect cooling +channel-type.nibeheatpump.smo40-48284.label = SG Ready hot water +channel-type.nibeheatpump.smo40-48284.description = Sets whether or not SG Ready should affect hot water +channel-type.nibeheatpump.smo40-48285.label = SG Ready pool +channel-type.nibeheatpump.smo40-48285.description = Sets whether or not SG Ready should affect pool +channel-type.nibeheatpump.smo40-48367.label = Speed circ.pump Heat Slave 8 +channel-type.nibeheatpump.smo40-48368.label = Speed circ.pump Heat Slave 7 +channel-type.nibeheatpump.smo40-48369.label = Speed circ.pump Heat Slave 6 +channel-type.nibeheatpump.smo40-48370.label = Speed circ.pump Heat Slave 5 +channel-type.nibeheatpump.smo40-48371.label = Speed circ.pump Heat Slave 4 +channel-type.nibeheatpump.smo40-48372.label = Speed circ.pump Heat Slave 3 +channel-type.nibeheatpump.smo40-48373.label = Speed circ.pump Heat Slave 2 +channel-type.nibeheatpump.smo40-48374.label = Speed circ.pump Heat Slave 1 +channel-type.nibeheatpump.smo40-48375.label = Op mode circ.pump Heat Slave 8 +channel-type.nibeheatpump.smo40-48376.label = Op mode circ.pump Heat Slave 7 +channel-type.nibeheatpump.smo40-48377.label = Op mode circ.pump Heat Slave 6 +channel-type.nibeheatpump.smo40-48378.label = Op mode circ.pump Heat Slave 5 +channel-type.nibeheatpump.smo40-48379.label = Op mode circ.pump Heat Slave 4 +channel-type.nibeheatpump.smo40-48380.label = Op mode circ.pump Heat Slave 3 +channel-type.nibeheatpump.smo40-48381.label = Op mode circ.pump Heat Slave 2 +channel-type.nibeheatpump.smo40-48382.label = Op mode circ.pump Heat Slave 1 +channel-type.nibeheatpump.smo40-48390.label = Speed circ.pump HW Slave 1 +channel-type.nibeheatpump.smo40-48391.label = Op mode circ.pump HW Slave 8 +channel-type.nibeheatpump.smo40-48392.label = Op mode circ.pump HW Slave 7 +channel-type.nibeheatpump.smo40-48393.label = Op mode circ.pump HW Slave 6 +channel-type.nibeheatpump.smo40-48394.label = Op mode circ.pump HW Slave 5 +channel-type.nibeheatpump.smo40-48395.label = Op mode circ.pump HW Slave 4 +channel-type.nibeheatpump.smo40-48396.label = Op mode circ.pump HW Slave 3 +channel-type.nibeheatpump.smo40-48397.label = Op mode circ.pump HW Slave 2 +channel-type.nibeheatpump.smo40-48398.label = Op mode circ.pump HW Slave 1 +channel-type.nibeheatpump.smo40-48399.label = Speed circ.pump Pool Slave 8 +channel-type.nibeheatpump.smo40-48400.label = Speed circ.pump Pool Slave 7 +channel-type.nibeheatpump.smo40-48401.label = Speed circ.pump Pool Slave 6 +channel-type.nibeheatpump.smo40-48402.label = Speed circ.pump Pool Slave 5 +channel-type.nibeheatpump.smo40-48403.label = Speed circ.pump Pool Slave 4 +channel-type.nibeheatpump.smo40-48404.label = Speed circ.pump Pool Slave 3 +channel-type.nibeheatpump.smo40-48405.label = Speed circ.pump Pool Slave 2 +channel-type.nibeheatpump.smo40-48406.label = Speed circ.pump Pool Slave 1 +channel-type.nibeheatpump.smo40-48407.label = Op mode circ.pump Pool Slave 8 +channel-type.nibeheatpump.smo40-48408.label = Op mode circ.pump Pool Slave 7 +channel-type.nibeheatpump.smo40-48409.label = Op mode circ.pump Pool Slave 6 +channel-type.nibeheatpump.smo40-48410.label = Op mode circ.pump Pool Slave 5 +channel-type.nibeheatpump.smo40-48411.label = Op mode circ.pump Pool Slave 4 +channel-type.nibeheatpump.smo40-48412.label = Op mode circ.pump Pool Slave 3 +channel-type.nibeheatpump.smo40-48413.label = Op mode circ.pump Pool Slave 2 +channel-type.nibeheatpump.smo40-48414.label = Op mode circ.pump Pool Slave 1 +channel-type.nibeheatpump.smo40-48415.label = Speed circ.pump Cooling Slave 8 +channel-type.nibeheatpump.smo40-48416.label = Speed circ.pump Cooling Slave 7 +channel-type.nibeheatpump.smo40-48417.label = Speed circ.pump Cooling Slave 6 +channel-type.nibeheatpump.smo40-48418.label = Speed circ.pump Cooling Slave 5 +channel-type.nibeheatpump.smo40-48419.label = Speed circ.pump Cooling Slave 4 +channel-type.nibeheatpump.smo40-48420.label = Speed circ.pump Cooling Slave 3 +channel-type.nibeheatpump.smo40-48421.label = Speed circ.pump Cooling Slave 2 +channel-type.nibeheatpump.smo40-48422.label = Speed circ.pump Cooling Slave 1 +channel-type.nibeheatpump.smo40-48424.label = Op mode circ.pump Cooling Slave 8 +channel-type.nibeheatpump.smo40-48425.label = Op mode circ.pump Cooling Slave 7 +channel-type.nibeheatpump.smo40-48426.label = Op mode circ.pump Cooling Slave 6 +channel-type.nibeheatpump.smo40-48427.label = Op mode circ.pump Cooling Slave 5 +channel-type.nibeheatpump.smo40-48428.label = Op mode circ.pump Cooling Slave 4 +channel-type.nibeheatpump.smo40-48429.label = Op mode circ.pump Cooling Slave 3 +channel-type.nibeheatpump.smo40-48430.label = Op mode circ.pump Cooling Slave 2 +channel-type.nibeheatpump.smo40-48431.label = Op mode circ.pump Cooling Slave 1 +channel-type.nibeheatpump.smo40-48433.label = Speed circ.pump Waiting Slave 8 +channel-type.nibeheatpump.smo40-48434.label = Speed circ.pump Waiting Slave 7 +channel-type.nibeheatpump.smo40-48435.label = Speed circ.pump Waiting Slave 6 +channel-type.nibeheatpump.smo40-48436.label = Speed circ.pump Waiting Slave 5 +channel-type.nibeheatpump.smo40-48437.label = Speed circ.pump Waiting Slave 4 +channel-type.nibeheatpump.smo40-48438.label = Speed circ.pump Waiting Slave 3 +channel-type.nibeheatpump.smo40-48439.label = Speed circ.pump Waiting Slave 2 +channel-type.nibeheatpump.smo40-48440.label = Speed circ.pump Waiting Slave 1 +channel-type.nibeheatpump.smo40-48457.label = Int shunt controlled add. +channel-type.nibeheatpump.smo40-48460.label = EB108 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48460.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48461.label = EB107 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48461.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48462.label = EB106 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48462.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48463.label = EB105 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48463.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48464.label = EB104 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48464.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48465.label = EB103 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48465.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48466.label = EB102 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48466.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48467.label = EB101 Max charge pump reg speed +channel-type.nibeheatpump.smo40-48467.description = Max charge pump reg speed +channel-type.nibeheatpump.smo40-48468.label = Operational mode charge pump in cooling mode S8 +channel-type.nibeheatpump.smo40-48469.label = Operational mode charge pump in cooling mode S7 +channel-type.nibeheatpump.smo40-48470.label = Operational mode charge pump in cooling mode S6 +channel-type.nibeheatpump.smo40-48471.label = Operational mode charge pump in cooling mode S5 +channel-type.nibeheatpump.smo40-48472.label = Operational mode charge pump in cooling mode S4 +channel-type.nibeheatpump.smo40-48473.label = Operational mode charge pump in cooling mode S3 +channel-type.nibeheatpump.smo40-48474.label = Operational mode charge pump in cooling mode S2 +channel-type.nibeheatpump.smo40-48475.label = Operational mode charge pump in cooling mode S1 +channel-type.nibeheatpump.smo40-48488.label = Heat Curve S6 +channel-type.nibeheatpump.smo40-48488.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48489.label = Heat Curve S5 +channel-type.nibeheatpump.smo40-48489.description = Heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48491.label = Heat Offset S8 +channel-type.nibeheatpump.smo40-48491.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48492.label = Heat Offset S7 +channel-type.nibeheatpump.smo40-48492.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48493.label = Heat Offset S6 +channel-type.nibeheatpump.smo40-48493.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48494.label = Heat Offset S5 +channel-type.nibeheatpump.smo40-48494.description = Offset of the heat curve, see manual for more information +channel-type.nibeheatpump.smo40-48495.label = Min Supply System 8 +channel-type.nibeheatpump.smo40-48496.label = Min Supply System 7 +channel-type.nibeheatpump.smo40-48497.label = Min Supply System 6 +channel-type.nibeheatpump.smo40-48498.label = Min Supply System 5 +channel-type.nibeheatpump.smo40-48499.label = Max Supply System 8 +channel-type.nibeheatpump.smo40-48500.label = Max Supply System 7 +channel-type.nibeheatpump.smo40-48501.label = Max Supply System 6 +channel-type.nibeheatpump.smo40-48502.label = Max Supply System 5 +channel-type.nibeheatpump.smo40-48503.label = External adjustment S8 +channel-type.nibeheatpump.smo40-48503.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-48504.label = External adjustment S7 +channel-type.nibeheatpump.smo40-48504.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-48505.label = External adjustment S6 +channel-type.nibeheatpump.smo40-48505.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-48506.label = External adjustment S5 +channel-type.nibeheatpump.smo40-48506.description = Change of the offset of the heat curve when closing the external adjustment input +channel-type.nibeheatpump.smo40-48507.label = External adjustment with room sensor S8 +channel-type.nibeheatpump.smo40-48507.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-48508.label = External adjustment with room sensor S7 +channel-type.nibeheatpump.smo40-48508.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-48509.label = External adjustment with room sensor S6 +channel-type.nibeheatpump.smo40-48509.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-48510.label = External adjustment with room sensor S5 +channel-type.nibeheatpump.smo40-48510.description = Room temperature setting when closing the external adjustment input +channel-type.nibeheatpump.smo40-48569.label = Climate system 5 accessory +channel-type.nibeheatpump.smo40-48569.description = Activates the climate system 5 accessory +channel-type.nibeheatpump.smo40-48570.label = Climate system 6 accessory +channel-type.nibeheatpump.smo40-48570.description = Activates the climate system 6 accessory +channel-type.nibeheatpump.smo40-48571.label = Climate system 7 accessory +channel-type.nibeheatpump.smo40-48571.description = Activates the climate system 7 accessory +channel-type.nibeheatpump.smo40-48572.label = Climate system 8 accessory +channel-type.nibeheatpump.smo40-48572.description = Activates the climate system 8 accessory +channel-type.nibeheatpump.smo40-48573.label = Climate system 8 mixing valve amp. +channel-type.nibeheatpump.smo40-48573.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-48574.label = Climate system 7 mixing valve amp. +channel-type.nibeheatpump.smo40-48574.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-48575.label = Climate system 6 mixing valve amp. +channel-type.nibeheatpump.smo40-48575.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-48576.label = Climate system 5 mixing valve amp. +channel-type.nibeheatpump.smo40-48576.description = Mixing valve amplification for extra climate systems +channel-type.nibeheatpump.smo40-48577.label = Climate system 8 shunt wait +channel-type.nibeheatpump.smo40-48577.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-48578.label = Climate system 7 shunt wait +channel-type.nibeheatpump.smo40-48578.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-48579.label = Climate system 6 shunt wait +channel-type.nibeheatpump.smo40-48579.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-48580.label = Climate system 5 shunt wait +channel-type.nibeheatpump.smo40-48580.description = Wait time between changes of the shunt in extra climate systems +channel-type.nibeheatpump.smo40-48581.label = Min cooling supply temp S8 +channel-type.nibeheatpump.smo40-48581.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48582.label = Min cooling supply temp S7 +channel-type.nibeheatpump.smo40-48582.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48583.label = Min cooling supply temp S6 +channel-type.nibeheatpump.smo40-48583.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48584.label = Min cooling supply temp S5 +channel-type.nibeheatpump.smo40-48584.description = Minimum allowed supply temperature during cooling +channel-type.nibeheatpump.smo40-48593.label = Cooling use mix. valve S8 +channel-type.nibeheatpump.smo40-48593.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48594.label = Cooling use mix. valve S7 +channel-type.nibeheatpump.smo40-48594.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48595.label = Cooling use mix. valve S6 +channel-type.nibeheatpump.smo40-48595.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48596.label = Cooling use mix. valve S5 +channel-type.nibeheatpump.smo40-48596.description = Sets if the valve should be used or not in cooling mode. Only applies if cooling is available in the system +channel-type.nibeheatpump.smo40-48597.label = Heating use mix. valve S8 +channel-type.nibeheatpump.smo40-48597.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48598.label = Heating use mix. valve S7 +channel-type.nibeheatpump.smo40-48598.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48599.label = Heating use mix. valve S6 +channel-type.nibeheatpump.smo40-48599.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48600.label = Heating use mix. valve S5 +channel-type.nibeheatpump.smo40-48600.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48601.label = Heating use mix. valve S4 +channel-type.nibeheatpump.smo40-48601.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48602.label = Heating use mix. valve S3 +channel-type.nibeheatpump.smo40-48602.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48603.label = Heating use mix. valve S2 +channel-type.nibeheatpump.smo40-48603.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48604.label = Heating use mix. valve S1 +channel-type.nibeheatpump.smo40-48604.description = Sets if the valve should be used or not in heating mode. Only applies if cooling is available in the system. Otherwise the valve is always used in heating mode. +channel-type.nibeheatpump.smo40-48607.label = ERS 1 accessory +channel-type.nibeheatpump.smo40-48607.description = Activates the ERS accessory +channel-type.nibeheatpump.smo40-48647.label = EB103/104-GP12 +channel-type.nibeheatpump.smo40-48647.description = Activates the EB103/104-GP12 Accessory. +channel-type.nibeheatpump.smo40-48648.label = EB105/106-GP12 +channel-type.nibeheatpump.smo40-48648.description = Activates the EB105/106-GP12 Accessory. +channel-type.nibeheatpump.smo40-48649.label = EB107/108-GP12 +channel-type.nibeheatpump.smo40-48649.description = Activates the EB107/108-GP12 Accessory. +channel-type.nibeheatpump.smo40-48675.label = Use room sensor S8 +channel-type.nibeheatpump.smo40-48675.description = When activated the system uses the room sensor +channel-type.nibeheatpump.smo40-48676.label = Use room sensor S7 +channel-type.nibeheatpump.smo40-48676.description = When activated the system uses the room sensor +channel-type.nibeheatpump.smo40-48677.label = Use room sensor S6 +channel-type.nibeheatpump.smo40-48677.description = When activated the system uses the room sensor +channel-type.nibeheatpump.smo40-48678.label = Use room sensor S5 +channel-type.nibeheatpump.smo40-48678.description = When activated the system uses the room sensor +channel-type.nibeheatpump.smo40-48680.label = Room sensor setpoint S8 +channel-type.nibeheatpump.smo40-48680.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-48681.label = Room sensor setpoint S7 +channel-type.nibeheatpump.smo40-48681.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-48682.label = Room sensor setpoint S6 +channel-type.nibeheatpump.smo40-48682.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-48683.label = Room sensor setpoint S5 +channel-type.nibeheatpump.smo40-48683.description = Sets the room temperature setpoint for the system +channel-type.nibeheatpump.smo40-48685.label = Room sensor factor S8 +channel-type.nibeheatpump.smo40-48685.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-48686.label = Room sensor factor S7 +channel-type.nibeheatpump.smo40-48686.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-48687.label = Room sensor factor S6 +channel-type.nibeheatpump.smo40-48687.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-48688.label = Room sensor factor S5 +channel-type.nibeheatpump.smo40-48688.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-type.nibeheatpump.smo40-48724.label = Cool curve S8 +channel-type.nibeheatpump.smo40-48724.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48725.label = Cool curve S7 +channel-type.nibeheatpump.smo40-48725.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48726.label = Cool curve S6 +channel-type.nibeheatpump.smo40-48726.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48727.label = Cool curve S5 +channel-type.nibeheatpump.smo40-48727.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48728.label = Cool curve S4 +channel-type.nibeheatpump.smo40-48728.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48729.label = Cool curve S3 +channel-type.nibeheatpump.smo40-48729.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48730.label = Cool curve S2 +channel-type.nibeheatpump.smo40-48730.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48731.label = Cool curve S1 +channel-type.nibeheatpump.smo40-48731.description = Cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48732.label = Cool offset S8 +channel-type.nibeheatpump.smo40-48732.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48733.label = Cool offset S7 +channel-type.nibeheatpump.smo40-48733.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48734.label = Cool offset S6 +channel-type.nibeheatpump.smo40-48734.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48735.label = Cool offset S5 +channel-type.nibeheatpump.smo40-48735.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48736.label = Cool offset S4 +channel-type.nibeheatpump.smo40-48736.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48737.label = Cool offset S3 +channel-type.nibeheatpump.smo40-48737.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48738.label = Cool offset S2 +channel-type.nibeheatpump.smo40-48738.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48739.label = Cool offset S1 +channel-type.nibeheatpump.smo40-48739.description = Offset of the cool curve, see manual for more information +channel-type.nibeheatpump.smo40-48740.label = Own Cooling Curve P4 +channel-type.nibeheatpump.smo40-48740.description = User defined cooling curve point +channel-type.nibeheatpump.smo40-48741.label = Own Cooling Curve P2 +channel-type.nibeheatpump.smo40-48741.description = User defined cooling curve point +channel-type.nibeheatpump.smo40-48742.label = Own Cooling Curve P1 +channel-type.nibeheatpump.smo40-48742.description = User defined cooling curve point +channel-type.nibeheatpump.smo40-48743.label = Hot water high power mode +channel-type.nibeheatpump.smo40-48755.label = Transformer ratio +channel-type.nibeheatpump.smo40-48755.description = Ratio of the current measurement transformers +channel-type.nibeheatpump.smo40-48778.label = Room sensor cool setpoint S8 +channel-type.nibeheatpump.smo40-48778.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48779.label = Room sensor cool setpoint S7 +channel-type.nibeheatpump.smo40-48779.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48780.label = Room sensor cool setpoint S6 +channel-type.nibeheatpump.smo40-48780.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48781.label = Room sensor cool setpoint S5 +channel-type.nibeheatpump.smo40-48781.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48782.label = Room sensor cool setpoint S4 +channel-type.nibeheatpump.smo40-48782.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48783.label = Room sensor cool setpoint S3 +channel-type.nibeheatpump.smo40-48783.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48784.label = Room sensor cool setpoint S2 +channel-type.nibeheatpump.smo40-48784.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48785.label = Room sensor cool setpoint S1 +channel-type.nibeheatpump.smo40-48785.description = Sets the room temperature setpoint for the system in cooling mode +channel-type.nibeheatpump.smo40-48786.label = Room sensor cool factor S8 +channel-type.nibeheatpump.smo40-48786.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48787.label = Room sensor cool factor S7 +channel-type.nibeheatpump.smo40-48787.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48788.label = Room sensor cool factor S6 +channel-type.nibeheatpump.smo40-48788.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48789.label = Room sensor cool factor S5 +channel-type.nibeheatpump.smo40-48789.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48790.label = Room sensor cool factor S4 +channel-type.nibeheatpump.smo40-48790.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48791.label = Room sensor cool factor S3 +channel-type.nibeheatpump.smo40-48791.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48792.label = Room sensor cool factor S2 +channel-type.nibeheatpump.smo40-48792.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48793.label = Room sensor cool factor S1 +channel-type.nibeheatpump.smo40-48793.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48794.label = RH set value +channel-type.nibeheatpump.smo40-48794.description = RH set value +channel-type.nibeheatpump.smo40-48808.label = HTS accessory +channel-type.nibeheatpump.smo40-48808.description = HTS accessory +channel-type.nibeheatpump.smo40-48810.label = Prevent humidity S8 +channel-type.nibeheatpump.smo40-48811.label = Prevent humidity S7 +channel-type.nibeheatpump.smo40-48812.label = Prevent humidity S6 +channel-type.nibeheatpump.smo40-48813.label = Prevent humidity S5 +channel-type.nibeheatpump.smo40-48814.label = Prevent humidity S4 +channel-type.nibeheatpump.smo40-48815.label = Prevent humidity S3 +channel-type.nibeheatpump.smo40-48816.label = Prevent humidity S2 +channel-type.nibeheatpump.smo40-48817.label = Prevent humidity S1 +channel-type.nibeheatpump.smo40-48819.label = Limit humidity in room, heating S8 +channel-type.nibeheatpump.smo40-48819.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48820.label = Limit humidity in room, heating S7 +channel-type.nibeheatpump.smo40-48820.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48821.label = Limit humidity in room, heating S6 +channel-type.nibeheatpump.smo40-48821.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48822.label = Limit humidity in room, heating S5 +channel-type.nibeheatpump.smo40-48822.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48823.label = Limit humidity in room, heating S4 +channel-type.nibeheatpump.smo40-48823.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48824.label = Limit humidity in room, heating S3 +channel-type.nibeheatpump.smo40-48824.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48825.label = Limit humidity in room, heating S2 +channel-type.nibeheatpump.smo40-48825.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48826.label = Limit humidity in room, heating S1 +channel-type.nibeheatpump.smo40-48826.description = Limit humidity in room, heating +channel-type.nibeheatpump.smo40-48828.label = OPT +channel-type.nibeheatpump.smo40-48828.description = Activates the OPT Accessory. +channel-type.nibeheatpump.smo40-48829.label = OPT DM startdiff +channel-type.nibeheatpump.smo40-48829.description = The number of degree minutes below the last compressor the OPT is allowed to start +channel-type.nibeheatpump.smo40-48852.label = Modbus40 Word Swap +channel-type.nibeheatpump.smo40-48852.description = If set: swapping the words in 32-bit variables when value requested via ''read holding register'' commando. +channel-type.nibeheatpump.smo40-48853.label = ERS 1 Exhaust Fan speed 4 +channel-type.nibeheatpump.smo40-48854.label = ERS 1 Exhaust Fan speed 3 +channel-type.nibeheatpump.smo40-48855.label = ERS 1 Exhaust Fan speed 2 +channel-type.nibeheatpump.smo40-48856.label = ERS 1 Exhaust Fan speed 1 +channel-type.nibeheatpump.smo40-48857.label = ERS 1 Exhaust Fan speed normal +channel-type.nibeheatpump.smo40-48889.label = MODBUS40 Disable LOG.SET +channel-type.nibeheatpump.smo40-48889.description = If set, the system will ignore the existing LOG.SET on the USB stick.1=ignore LOG.SET,0=use LOG.SET +channel-type.nibeheatpump.smo40-48893.label = F135 Heat pump +channel-type.nibeheatpump.smo40-48893.description = 0=not activated, 1=activated +channel-type.nibeheatpump.smo40-48894.label = F135 Pump Speed +channel-type.nibeheatpump.smo40-48895.label = F135 HW-Cool +channel-type.nibeheatpump.smo40-48895.description = If activated, F135 will take care of all the hot water need when cooling is running +channel-type.nibeheatpump.smo40-48896.label = ERS 1 Supply Fan speed 4 +channel-type.nibeheatpump.smo40-48897.label = ERS 1 Supply Fan speed 3 +channel-type.nibeheatpump.smo40-48898.label = ERS 1 Supply Fan speed 2 +channel-type.nibeheatpump.smo40-48899.label = ERS 1 Supply Fan speed 1 +channel-type.nibeheatpump.smo40-48900.label = ERS 1 Supply Fan speed normal +channel-type.nibeheatpump.smo40-48901.label = External ERS 1 accessory min exhaust temp. +channel-type.nibeheatpump.smo40-48902.label = External ERS 1 accessory bypass temp. +channel-type.nibeheatpump.smo40-48905.label = External cooling accessory Pump Type +channel-type.nibeheatpump.smo40-48908.label = Energy Meter Factor X23 +channel-type.nibeheatpump.smo40-48908.description = Energy meter factor X23, energy per pulse +channel-type.nibeheatpump.smo40-48909.label = Energy Meter Factor X22 +channel-type.nibeheatpump.smo40-48909.description = Energy meter factor X22, energy per pulse +channel-type.nibeheatpump.smo40-48910.label = Energy Meter X23 +channel-type.nibeheatpump.smo40-48910.description = Activates the external energy meter +channel-type.nibeheatpump.smo40-48911.label = Energy Meter X22 +channel-type.nibeheatpump.smo40-48911.description = Activates the external energy meter +channel-type.nibeheatpump.smo40-48918.label = Limit humidity in room, cooling S8 +channel-type.nibeheatpump.smo40-48918.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48919.label = Limit humidity in room, cooling S7 +channel-type.nibeheatpump.smo40-48919.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48920.label = Limit humidity in room, cooling S6 +channel-type.nibeheatpump.smo40-48920.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48921.label = Limit humidity in room, cooling S5 +channel-type.nibeheatpump.smo40-48921.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48922.label = Limit humidity in room, cooling S4 +channel-type.nibeheatpump.smo40-48922.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48923.label = Limit humidity in room, cooling S3 +channel-type.nibeheatpump.smo40-48923.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48924.label = Limit humidity in room, cooling S2 +channel-type.nibeheatpump.smo40-48924.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48925.label = Limit humidity in room, cooling S1 +channel-type.nibeheatpump.smo40-48925.description = Limit humidity in room, cooling +channel-type.nibeheatpump.smo40-48926.label = Humidity factor +channel-type.nibeheatpump.smo40-48926.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature. +channel-type.nibeheatpump.smo40-48927.label = Humidity cool factor +channel-type.nibeheatpump.smo40-48927.description = Setting of how much the difference between set and actual room humidity should affect the supply temperature in cooling mode. +channel-type.nibeheatpump.smo40-48928.label = OPT Hystereses +channel-type.nibeheatpump.smo40-48928.description = The hystereses in OPT system +channel-type.nibeheatpump.smo40-48931.label = EME PV Panel Affect Heating +channel-type.nibeheatpump.smo40-48931.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.smo40-48932.label = EME PV Panel Affect Hot Water +channel-type.nibeheatpump.smo40-48932.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.smo40-48968.label = FLM 1 set point, cooling +channel-type.nibeheatpump.smo40-48968.description = Set point, cooling, when using FLM cooling +channel-type.nibeheatpump.smo40-48969.label = AUX block OPT +channel-type.nibeheatpump.smo40-48969.description = AUX block OPT +channel-type.nibeheatpump.smo40-48970.label = Outdoor Air Mixing function +channel-type.nibeheatpump.smo40-48970.description = Activates the Outdoor Air Mixing function. +channel-type.nibeheatpump.smo40-48976.label = Smart home room control +channel-type.nibeheatpump.smo40-48979.label = Smart energy source +channel-type.nibeheatpump.smo40-48979.description = Smart energy source activated. +channel-type.nibeheatpump.smo40-48980.label = Smart energy source, ctrl method +channel-type.nibeheatpump.smo40-48980.description = Smart energy source, ctrl method. 0 = price. 1 = primary factor. +channel-type.nibeheatpump.smo40-48981.label = Smart energy source, electricity price source +channel-type.nibeheatpump.smo40-48981.description = Smart energy source, electricity price source. 0 = fixed price. 1 = tariff. 2= spot price. +channel-type.nibeheatpump.smo40-48981.state.option.0 = fixed price. +channel-type.nibeheatpump.smo40-48981.state.option.1 = tariff. +channel-type.nibeheatpump.smo40-48981.state.option.2 = spot price. +channel-type.nibeheatpump.smo40-48982.label = Smart energy source, electricity price +channel-type.nibeheatpump.smo40-48982.description = Smart energy source, electricity fixed price. +channel-type.nibeheatpump.smo40-48983.label = Smart energy source, fixed elec. price from +channel-type.nibeheatpump.smo40-48983.description = Smart energy source, fixed electricity price part source, if spot electricity price are used. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.smo40-48984.label = Smart energy source, fixed part electricity price +channel-type.nibeheatpump.smo40-48984.description = Smart energy source, fixed part (if spot price are used) electricity price +channel-type.nibeheatpump.smo40-48985.label = Smart energy source, shunt add price source +channel-type.nibeheatpump.smo40-48985.description = Smart energy source, shunted addition price part source. From tariff or fixed price. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.smo40-48986.label = Smart energy source, shunt add price +channel-type.nibeheatpump.smo40-48986.description = Smart energy source, shunted add price +channel-type.nibeheatpump.smo40-48987.label = Smart energy source, ext step add price from +channel-type.nibeheatpump.smo40-48987.description = Smart energy source, external step add source. From tariff or fixed price. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.smo40-48988.label = Smart energy source, ext step add price +channel-type.nibeheatpump.smo40-48988.description = Smart energy source, ext step add price +channel-type.nibeheatpump.smo40-48989.label = Smart energy source, OPT10 price source +channel-type.nibeheatpump.smo40-48989.description = Smart energy source, OPT10 addition price source. 0 = fixed price. 1 = tariff. +channel-type.nibeheatpump.smo40-48990.label = Smart energy source, OPT10 price +channel-type.nibeheatpump.smo40-48990.description = Smart energy source, OPT10 addition price. +channel-type.nibeheatpump.smo40-48991.label = Smart energy source, primary factor elec. +channel-type.nibeheatpump.smo40-48991.description = Smart energy source, primary factor electricity +channel-type.nibeheatpump.smo40-48992.label = Smart energy source, primary factor shunted add. +channel-type.nibeheatpump.smo40-48992.description = Smart energy source, primary factor shunted addition +channel-type.nibeheatpump.smo40-48993.label = Smart energy source, primary factor ext step add +channel-type.nibeheatpump.smo40-48993.description = Smart energy source, primary factor external step addition +channel-type.nibeheatpump.smo40-48994.label = Smart energy source, primary factor OPT10 add. +channel-type.nibeheatpump.smo40-48994.description = Smart energy source, primary factor OPT10 addition +channel-type.nibeheatpump.smo40-48995.label = Smart energy source, OPT10 high tariff price +channel-type.nibeheatpump.smo40-48995.description = Smart energy source, OPT10 addition high tariff price +channel-type.nibeheatpump.smo40-48996.label = Smart energy source, OPT10 low tariff price +channel-type.nibeheatpump.smo40-48996.description = Smart energy source, OPT10 addition low tariff price +channel-type.nibeheatpump.smo40-48997.label = Smart energy source, ext step add high tariff price +channel-type.nibeheatpump.smo40-48997.description = Smart energy source, external step addition high tariff price +channel-type.nibeheatpump.smo40-48998.label = Smart energy source, ext step add low tariff price +channel-type.nibeheatpump.smo40-48998.description = Smart energy source, external step addition low tariff price +channel-type.nibeheatpump.smo40-48999.label = Smart energy source, shunt add high tariff price +channel-type.nibeheatpump.smo40-48999.description = Smart energy source, shunt addition high tariff price +channel-type.nibeheatpump.smo40-49000.label = Smart energy source, shunt add low tariff price +channel-type.nibeheatpump.smo40-49000.description = Smart energy source, shunt addition low tariff price +channel-type.nibeheatpump.smo40-49001.label = Smart energy source, fixed elec. high tariff price +channel-type.nibeheatpump.smo40-49001.description = Smart energy source, fixed electricity part high tariff price +channel-type.nibeheatpump.smo40-49002.label = Smart energy source, fixed elec. low tariff price +channel-type.nibeheatpump.smo40-49002.description = Smart energy source, fixed electricity part low tariff price +channel-type.nibeheatpump.smo40-49003.label = Smart energy source, electricity high tariff price +channel-type.nibeheatpump.smo40-49003.description = Smart energy source, electricity high tariff price +channel-type.nibeheatpump.smo40-49004.label = Smart energy source, electricity high low price +channel-type.nibeheatpump.smo40-49004.description = Smart energy source, electricity low tariff price +channel-type.nibeheatpump.smo40-49005.label = Smart energy source, DM diff source prio 5 +channel-type.nibeheatpump.smo40-49005.description = Smart energy source, DM diff source with prio 5 +channel-type.nibeheatpump.smo40-49006.label = Smart energy source, DM diff source prio 4 +channel-type.nibeheatpump.smo40-49006.description = Smart energy source, DM diff source with prio 4 +channel-type.nibeheatpump.smo40-49007.label = Smart energy source, DM diff source prio 3 +channel-type.nibeheatpump.smo40-49007.description = Smart energy source, DM diff source with prio 3 +channel-type.nibeheatpump.smo40-49008.label = Smart energy source, DM diff source prio 2 +channel-type.nibeheatpump.smo40-49008.description = Smart energy source, DM diff source with prio 2 +channel-type.nibeheatpump.smo40-49009.label = Smart energy source, DM start source prio 1 +channel-type.nibeheatpump.smo40-49009.description = Smart energy source, DM start source with prio 1 +channel-type.nibeheatpump.smo40-49230.label = Internal HW add in tank, use in heat +channel-type.nibeheatpump.smo40-49230.description = Internal HW add in tank, use in heat +channel-type.nibeheatpump.smo40-49232.label = EB108 Installed +channel-type.nibeheatpump.smo40-49233.label = EB107 Installed +channel-type.nibeheatpump.smo40-49234.label = EB106 Installed +channel-type.nibeheatpump.smo40-49235.label = EB105 Installed +channel-type.nibeheatpump.smo40-49236.label = EB104 Installed +channel-type.nibeheatpump.smo40-49237.label = EB103 Installed +channel-type.nibeheatpump.smo40-49238.label = EB102 Installed +channel-type.nibeheatpump.smo40-49239.label = EB101 Installed +channel-type.nibeheatpump.smo40-49241.label = External ERS 1 accessory bypass set temp. +channel-type.nibeheatpump.smo40-49242.label = External ERS 1 accessory bypass at heat +channel-type.nibeheatpump.smo40-49285.label = Energy Meter pulses per kWh X23 +channel-type.nibeheatpump.smo40-49285.description = Energy meter factor X23, pulses per kWh +channel-type.nibeheatpump.smo40-49286.label = Energy Meter pulses per kWh X22 +channel-type.nibeheatpump.smo40-49286.description = Energy meter factor X22, pulses per kWh +channel-type.nibeheatpump.smo40-49287.label = Energy Meter mode X23 +channel-type.nibeheatpump.smo40-49287.description = Energy meter X23 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.smo40-49288.label = Energy Meter mode X22 +channel-type.nibeheatpump.smo40-49288.description = Energy meter X22 in mode Wh/pulse = 0 or pulses/kWh = 1 +channel-type.nibeheatpump.smo40-49289.label = Ground water pump speed control +channel-type.nibeheatpump.smo40-49297.label = EME20 Activated +channel-type.nibeheatpump.smo40-49297.description = 0=not activated, 1=activated +channel-type.nibeheatpump.smo40-49298.label = EME PV Panel Affect Pool +channel-type.nibeheatpump.smo40-49298.description = 0=not affecting, 1=affecting +channel-type.nibeheatpump.smo40-49298.state.option.0 = not affecting +channel-type.nibeheatpump.smo40-49298.state.option.1 = affecting +channel-type.nibeheatpump.smo40-49328.label = ERS 4 Exhaust Fan speed 4 +channel-type.nibeheatpump.smo40-49329.label = ERS 3 Exhaust Fan speed 4 +channel-type.nibeheatpump.smo40-49330.label = ERS 2 Exhaust Fan speed 4 +channel-type.nibeheatpump.smo40-49331.label = ERS 4 Exhaust Fan speed 3 +channel-type.nibeheatpump.smo40-49332.label = ERS 3 Exhaust Fan speed 3 +channel-type.nibeheatpump.smo40-49333.label = ERS 2 Exhaust Fan speed 3 +channel-type.nibeheatpump.smo40-49334.label = ERS 4 Exhaust Fan speed 2 +channel-type.nibeheatpump.smo40-49335.label = ERS 3 Exhaust Fan speed 2 +channel-type.nibeheatpump.smo40-49336.label = ERS 2 Exhaust Fan speed 2 +channel-type.nibeheatpump.smo40-49337.label = ERS 4 Exhaust Fan speed 1 +channel-type.nibeheatpump.smo40-49338.label = ERS 3 Exhaust Fan speed 1 +channel-type.nibeheatpump.smo40-49339.label = ERS 2 Exhaust Fan speed 1 +channel-type.nibeheatpump.smo40-49340.label = ERS 4 Exhaust Fan speed normal +channel-type.nibeheatpump.smo40-49341.label = ERS 3 Exhaust Fan speed normal +channel-type.nibeheatpump.smo40-49342.label = ERS 2 Exhaust Fan speed normal +channel-type.nibeheatpump.smo40-49343.label = ERS 4 Supply Fan speed 4 +channel-type.nibeheatpump.smo40-49344.label = ERS 3 Supply Fan speed 4 +channel-type.nibeheatpump.smo40-49345.label = ERS 2 Supply Fan speed 4 +channel-type.nibeheatpump.smo40-49346.label = ERS 4 Supply Fan speed 3 +channel-type.nibeheatpump.smo40-49347.label = ERS 3 Supply Fan speed 3 +channel-type.nibeheatpump.smo40-49348.label = ERS 2 Supply Fan speed 3 +channel-type.nibeheatpump.smo40-49349.label = ERS 4 Supply Fan speed 2 +channel-type.nibeheatpump.smo40-49350.label = ERS 3 Supply Fan speed 2 +channel-type.nibeheatpump.smo40-49351.label = ERS 2 Supply Fan speed 2 +channel-type.nibeheatpump.smo40-49352.label = ERS 4 Supply Fan speed 1 +channel-type.nibeheatpump.smo40-49353.label = ERS 3 Supply Fan speed 1 +channel-type.nibeheatpump.smo40-49354.label = ERS 2 Supply Fan speed 1 +channel-type.nibeheatpump.smo40-49355.label = ERS 4 Supply Fan speed normal +channel-type.nibeheatpump.smo40-49356.label = ERS 3 Supply Fan speed normal +channel-type.nibeheatpump.smo40-49357.label = ERS 2 Supply Fan speed normal +channel-type.nibeheatpump.smo40-49358.label = Night cooling +channel-type.nibeheatpump.smo40-49358.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.smo40-49359.label = Night cooling +channel-type.nibeheatpump.smo40-49359.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.smo40-49360.label = Night cooling +channel-type.nibeheatpump.smo40-49360.description = If the fan should have a higher speed when there is a high room temp and a low outdoor temp. +channel-type.nibeheatpump.smo40-49361.label = Start room temp. night cooling +channel-type.nibeheatpump.smo40-49362.label = Start room temp. night cooling +channel-type.nibeheatpump.smo40-49363.label = Start room temp. night cooling +channel-type.nibeheatpump.smo40-49364.label = Night Cooling Min. diff. +channel-type.nibeheatpump.smo40-49364.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.smo40-49365.label = Night Cooling Min. diff. +channel-type.nibeheatpump.smo40-49365.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.smo40-49366.label = Night Cooling Min. diff. +channel-type.nibeheatpump.smo40-49366.description = Minimum difference between room temp and outdoor temp to start night cooling +channel-type.nibeheatpump.smo40-49367.label = ERS 4 accessory +channel-type.nibeheatpump.smo40-49367.description = Activates the ERS accessory +channel-type.nibeheatpump.smo40-49368.label = ERS 3 accessory +channel-type.nibeheatpump.smo40-49368.description = Activates the ERS accessory +channel-type.nibeheatpump.smo40-49369.label = ERS 2 accessory +channel-type.nibeheatpump.smo40-49369.description = Activates the ERS accessory +channel-type.nibeheatpump.smo40-49370.label = External ERS 4 accessory min exhaust temp. +channel-type.nibeheatpump.smo40-49371.label = External ERS 3 accessory min exhaust temp. +channel-type.nibeheatpump.smo40-49372.label = External ERS 2 accessory min exhaust temp. +channel-type.nibeheatpump.smo40-49373.label = External ERS 4 accessory bypass temp. +channel-type.nibeheatpump.smo40-49374.label = External ERS 3 accessory bypass temp. +channel-type.nibeheatpump.smo40-49375.label = External ERS 2 accessory bypass temp. +channel-type.nibeheatpump.smo40-49376.label = External ERS 4 accessory bypass set temp. +channel-type.nibeheatpump.smo40-49377.label = External ERS 3 accessory bypass set temp. +channel-type.nibeheatpump.smo40-49378.label = External ERS 2 accessory bypass set temp. +channel-type.nibeheatpump.smo40-49379.label = External ERS 4 accessory bypass at heat +channel-type.nibeheatpump.smo40-49380.label = External ERS 3 accessory bypass at heat +channel-type.nibeheatpump.smo40-49381.label = External ERS 2 accessory bypass at heat +channel-type.nibeheatpump.smo40-49430.label = AUX ERS Fire Place Guard +channel-type.nibeheatpump.smo40-49430.description = Activates ERS Fire Place Guard +channel-type.nibeheatpump.smo40-49806.label = Silent Mode Frequency 2 +channel-type.nibeheatpump.smo40-49806.description = Silent Mode Frequency 2 diff --git a/bundles/org.openhab.binding.nibeuplink/src/main/resources/OH-INF/i18n/nibeuplink.properties b/bundles/org.openhab.binding.nibeuplink/src/main/resources/OH-INF/i18n/nibeuplink.properties new file mode 100644 index 0000000000000..76265aa64e119 --- /dev/null +++ b/bundles/org.openhab.binding.nibeuplink/src/main/resources/OH-INF/i18n/nibeuplink.properties @@ -0,0 +1,469 @@ +# binding + +binding.nibeuplink.name = NibeUplink Binding +binding.nibeuplink.description = This is the binding for NibeUplink. + +# thing types + +thing-type.nibeuplink.f1145.label = Nibe F1145 +thing-type.nibeuplink.f1145.description = Nibe F1145 heat pump connected through Nibe UpLink +thing-type.nibeuplink.f1155.label = Nibe F1155 +thing-type.nibeuplink.f1155.description = Nibe F1155 heat pump connected through Nibe UpLink +thing-type.nibeuplink.f730.label = Nibe F730 +thing-type.nibeuplink.f730.description = Nibe F730 heat pump connected through Nibe UpLink +thing-type.nibeuplink.f750.label = Nibe F750 +thing-type.nibeuplink.f750.description = Nibe F750 heat pump connected through Nibe UpLink +thing-type.nibeuplink.vvm310.label = Nibe VVM310 / VVM500 +thing-type.nibeuplink.vvm310.description = Nibe VVM310 / VVM500 heat pump connected through Nibe UpLink +thing-type.nibeuplink.vvm320.label = Nibe VVM320 / VVM325 +thing-type.nibeuplink.vvm320.description = Nibe VVM320 / VVM325 heat pump connected through Nibe UpLink + +# thing types config + +thing-type.config.nibeuplink.web.group.authentication.label = Authentication +thing-type.config.nibeuplink.web.group.authentication.description = Authentication settings. +thing-type.config.nibeuplink.web.group.connection.label = Connection +thing-type.config.nibeuplink.web.group.connection.description = Connection settings. +thing-type.config.nibeuplink.web.group.customChannels.label = Custom Channels +thing-type.config.nibeuplink.web.group.customChannels.description = Custom Channel configuration +thing-type.config.nibeuplink.web.group.general.label = General +thing-type.config.nibeuplink.web.group.general.description = General settings. +thing-type.config.nibeuplink.web.nibeId.label = Nibe ID +thing-type.config.nibeuplink.web.nibeId.description = The ID to identify the heat pump at NibeIplink. +thing-type.config.nibeuplink.web.password.label = Password +thing-type.config.nibeuplink.web.password.description = The Password to login at NibeIplink. +thing-type.config.nibeuplink.web.pollingInterval.label = Polling Interval +thing-type.config.nibeuplink.web.pollingInterval.description = Interval in which data is polled from Nibe Uplink (in seconds). +thing-type.config.nibeuplink.web.user.label = Username +thing-type.config.nibeuplink.web.user.description = The Username to login at NibeIplink. + +# channel group types + +channel-group-type.nibeuplink.base-base.label = Base Channels +channel-group-type.nibeuplink.base-base.channel.10012.label = Compressor Blocked +channel-group-type.nibeuplink.base-base.channel.10012.description = states if the compressor is blocked +channel-group-type.nibeuplink.base-base.channel.10033.label = Int. El.add. Blocked +channel-group-type.nibeuplink.base-base.channel.10033.description = states if internal electric additional heater is blocked +channel-group-type.nibeuplink.base-base.channel.40004.label = BT1 Outdoor Temperature +channel-group-type.nibeuplink.base-base.channel.40004.description = Current outdoor temperature +channel-group-type.nibeuplink.base-base.channel.40008.label = BT2 Supply Temp S1 +channel-group-type.nibeuplink.base-base.channel.40008.description = Supply temperature for system 1 +channel-group-type.nibeuplink.base-base.channel.40012.label = EB100-EP14-BT3 Return Temp +channel-group-type.nibeuplink.base-base.channel.40012.description = Return temperature +channel-group-type.nibeuplink.base-base.channel.40033.label = BT50 Room Temp S1 +channel-group-type.nibeuplink.base-base.channel.40033.description = Room Temperature S1 (BT50) +channel-group-type.nibeuplink.base-base.channel.40067.label = BT1 Average +channel-group-type.nibeuplink.base-base.channel.40067.description = EB100-BT1 Outdoor temperature average +channel-group-type.nibeuplink.base-base.channel.40071.label = BT25 Ext. Supply +channel-group-type.nibeuplink.base-base.channel.40071.description = External supply temperature, BT25 +channel-group-type.nibeuplink.base-base.channel.40072.label = BF1 EP14 Flow +channel-group-type.nibeuplink.base-base.channel.40072.description = Current flow EP14|Current flow EP15 +channel-group-type.nibeuplink.base-base.channel.40079.label = EB100-BE3 Current +channel-group-type.nibeuplink.base-base.channel.40079.description = BE3 Current +channel-group-type.nibeuplink.base-base.channel.40081.label = EB100-BE2 Current +channel-group-type.nibeuplink.base-base.channel.40081.description = BE2 Current +channel-group-type.nibeuplink.base-base.channel.40083.label = EB100-BE1 Current +channel-group-type.nibeuplink.base-base.channel.40083.description = BE1 Current +channel-group-type.nibeuplink.base-base.channel.43005.label = Degree Minutes (16 Bit) +channel-group-type.nibeuplink.base-base.channel.43005.description = Degree minutes, 16bit value (-32768 < x < 32767). Values outside valid values are rounded to the closest valid value. +channel-group-type.nibeuplink.base-base.channel.43009.label = Calc. Supply S1 +channel-group-type.nibeuplink.base-base.channel.43009.description = Calculated supply temperature for the climate system +channel-group-type.nibeuplink.base-base.channel.43081.label = Tot. Op.time Add. +channel-group-type.nibeuplink.base-base.channel.43081.description = Total electric additive operation time +channel-group-type.nibeuplink.base-base.channel.43084.label = Int. El.add. Power +channel-group-type.nibeuplink.base-base.channel.43084.description = Current power from the internal electrical addition +channel-group-type.nibeuplink.base-base.channel.43161.label = External Adjustment Activated Via Input S1 +channel-group-type.nibeuplink.base-base.channel.43161.description = External Adjustment Activated Via Input S1 +channel-group-type.nibeuplink.base-base.channel.43437.label = Supply Pump Speed EP14 +channel-group-type.nibeuplink.base-base.channel.43437.description = Supply Pump Speed, EP14 (GP6) +channel-group-type.nibeuplink.base-base.channel.44300.label = Heat Meter - Heat Cpr and Add EP14 +channel-group-type.nibeuplink.base-base.channel.44300.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.base-base.channel.44304.label = Heat Meter - Pool Cpr EP14 +channel-group-type.nibeuplink.base-base.channel.44304.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.base-base.channel.44308.label = Heat Meter - Heat Cpr EP14 +channel-group-type.nibeuplink.base-base.channel.44308.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.base-base.channel.47212.label = Max Int Add. Power +channel-group-type.nibeuplink.base-base.channel.47212.description = Maximum power from the internal electrical addition +channel-group-type.nibeuplink.base-base.channel.48043.label = Holiday +channel-group-type.nibeuplink.base-base.channel.48043.description = states if Holiday mode is activated +channel-group-type.nibeuplink.base-base.channel.48914.label = Max Int Add. Power, SG Ready +channel-group-type.nibeuplink.base-base.channel.48914.description = Maximum power from the internal electrical addition in SG-Ready Mode +channel-group-type.nibeuplink.base-hotwater.label = Hot Water Channels +channel-group-type.nibeuplink.base-hotwater.channel.40013.label = BT7 HW Top +channel-group-type.nibeuplink.base-hotwater.channel.40013.description = Hot water top temperature, BT7 +channel-group-type.nibeuplink.base-hotwater.channel.40014.label = BT6 HW Load +channel-group-type.nibeuplink.base-hotwater.channel.40014.description = Hot water load temperature, BT6 +channel-group-type.nibeuplink.base-hotwater.channel.44298.label = Heat Meter - HW Cpr and Add EP14 +channel-group-type.nibeuplink.base-hotwater.channel.44298.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.base-hotwater.channel.44306.label = Heat Meter - HW Cpr EP14 +channel-group-type.nibeuplink.base-hotwater.channel.44306.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.base-hotwater.channel.47041.label = Hot Water Mode +channel-group-type.nibeuplink.base-hotwater.channel.47041.description = The currently active hotwater mode +channel-group-type.nibeuplink.base-hotwater.channel.47043.label = Start Temperature HW Luxury +channel-group-type.nibeuplink.base-hotwater.channel.47043.description = Start temperature for heating water in Luxury mode +channel-group-type.nibeuplink.base-hotwater.channel.47044.label = Start Temperature HW Normal +channel-group-type.nibeuplink.base-hotwater.channel.47044.description = Start temperature for heating water in Normal mode +channel-group-type.nibeuplink.base-hotwater.channel.47045.label = Start Temperature HW Economy +channel-group-type.nibeuplink.base-hotwater.channel.47045.description = Start temperature for heating water in Economy mode +channel-group-type.nibeuplink.base-hotwater.channel.47046.label = Stop Temperature Periodic HW +channel-group-type.nibeuplink.base-hotwater.channel.47046.description = Stop temperature for heating water in periodic heating +channel-group-type.nibeuplink.base-hotwater.channel.47047.label = Stop Temperature HW Luxury +channel-group-type.nibeuplink.base-hotwater.channel.47047.description = Stop temperature for heating water in Luxory mode +channel-group-type.nibeuplink.base-hotwater.channel.47048.label = Stop Temperature HW Normal +channel-group-type.nibeuplink.base-hotwater.channel.47048.description = Stop temperature for heating water in Normal mode +channel-group-type.nibeuplink.base-hotwater.channel.47049.label = Stop Temperature HW Economy +channel-group-type.nibeuplink.base-hotwater.channel.47049.description = Stop temperature for heating water in Economy mode +channel-group-type.nibeuplink.base-hotwater.channel.48132.label = Temporary Lux +channel-group-type.nibeuplink.base-hotwater.channel.48132.description = Temporary hot water lux mode +channel-group-type.nibeuplink.f1145-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.f1145-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.f1145-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.f1145-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.f1145-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.f1145-compressor.label = Compressor Channels +channel-group-type.nibeuplink.f1145-compressor.channel.40015.label = EB100-EP14-BT10 Brine in Temperature +channel-group-type.nibeuplink.f1145-compressor.channel.40015.description = Brine in temperature, BT10 +channel-group-type.nibeuplink.f1145-compressor.channel.40016.label = EB100-EP14-BT11 Brine out Temperature +channel-group-type.nibeuplink.f1145-compressor.channel.40016.description = Brine out temperature, BT11 +channel-group-type.nibeuplink.f1145-compressor.channel.40017.label = EB100-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.f1145-compressor.channel.40017.description = Condensor out temperature, BT12 +channel-group-type.nibeuplink.f1145-compressor.channel.40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.f1145-compressor.channel.40018.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.f1145-compressor.channel.40019.label = EB100-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.f1145-compressor.channel.40019.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.f1145-compressor.channel.40022.label = EB100-EP14-BT17 Suction +channel-group-type.nibeuplink.f1145-compressor.channel.40022.description = Suction temperature, BT17 +channel-group-type.nibeuplink.f1145-compressor.channel.43416.label = Compressor Starts EB100-EP14 +channel-group-type.nibeuplink.f1145-compressor.channel.43416.description = Number of compressor starts +channel-group-type.nibeuplink.f1145-compressor.channel.43420.label = Tot. Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f1145-compressor.channel.43420.description = Total compressor operation time +channel-group-type.nibeuplink.f1145-compressor.channel.43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f1145-compressor.channel.43424.description = Total compressor operation time in hot water mode +channel-group-type.nibeuplink.f1145-compressor.channel.43439.label = EP14-GP2 Brine Pump Speed +channel-group-type.nibeuplink.f1145-compressor.channel.43439.description = Brine pump speed EP14 (GP2) +channel-group-type.nibeuplink.f1145-general.label = General Channels +channel-group-type.nibeuplink.f1145-general.channel.43103.label = HPAC State +channel-group-type.nibeuplink.f1145-general.channel.43103.description = State of the HPAC accessory +channel-group-type.nibeuplink.f1145-general.channel.44270.label = Calculated Cooling Supply Temperature S1 +channel-group-type.nibeuplink.f1145-general.channel.44270.description = Calculated supply temperature in cooling mode for the climate system +channel-group-type.nibeuplink.f1145-general.channel.44302.label = Heat Meter - Cooling Cpr EP14 +channel-group-type.nibeuplink.f1145-general.channel.44302.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.f1155-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.f1155-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.f1155-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.f1155-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.f1155-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.f1155-compressor.label = Compressor Channels +channel-group-type.nibeuplink.f1155-compressor.channel.40015.label = EB100-EP14-BT10 Brine in Temperature +channel-group-type.nibeuplink.f1155-compressor.channel.40015.description = Brine in temperature, BT10 +channel-group-type.nibeuplink.f1155-compressor.channel.40016.label = EB100-EP14-BT11 Brine out Temperature +channel-group-type.nibeuplink.f1155-compressor.channel.40016.description = Brine out temperature, BT11 +channel-group-type.nibeuplink.f1155-compressor.channel.40017.label = EB100-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.f1155-compressor.channel.40017.description = Condensor out temperature, BT12 +channel-group-type.nibeuplink.f1155-compressor.channel.40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.f1155-compressor.channel.40018.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.f1155-compressor.channel.40019.label = EB100-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.f1155-compressor.channel.40019.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.f1155-compressor.channel.40022.label = EB100-EP14-BT17 Suction +channel-group-type.nibeuplink.f1155-compressor.channel.40022.description = Suction temperature, BT17 +channel-group-type.nibeuplink.f1155-compressor.channel.43122.label = Compr. Current Min.freq. +channel-group-type.nibeuplink.f1155-compressor.channel.43122.description = The current minimum frequency of the compressor +channel-group-type.nibeuplink.f1155-compressor.channel.43123.label = Compr. Current Max.freq. +channel-group-type.nibeuplink.f1155-compressor.channel.43123.description = The current maximum frequency of the compressor +channel-group-type.nibeuplink.f1155-compressor.channel.43136.label = Compressor Frequency, Actual +channel-group-type.nibeuplink.f1155-compressor.channel.43136.description = The compressor frequency the compressor is currently running at +channel-group-type.nibeuplink.f1155-compressor.channel.43416.label = Compressor Starts EB100-EP14 +channel-group-type.nibeuplink.f1155-compressor.channel.43416.description = Number of compressor starts +channel-group-type.nibeuplink.f1155-compressor.channel.43420.label = Tot. Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f1155-compressor.channel.43420.description = Total compressor operation time +channel-group-type.nibeuplink.f1155-compressor.channel.43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f1155-compressor.channel.43424.description = Total compressor operation time in hot water mode +channel-group-type.nibeuplink.f1155-compressor.channel.43439.label = EP14-GP2 Brine Pump Speed +channel-group-type.nibeuplink.f1155-compressor.channel.43439.description = Brine pump speed EP14 (GP2) +channel-group-type.nibeuplink.f1155-general.label = General Channels +channel-group-type.nibeuplink.f1155-general.channel.44302.label = Heat Meter - Cooling Cpr EP14 +channel-group-type.nibeuplink.f1155-general.channel.44302.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.f730-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.f730-airsupply.channel.10001.label = Fan Speed Current +channel-group-type.nibeuplink.f730-airsupply.channel.10001.description = The current fan speed +channel-group-type.nibeuplink.f730-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.f730-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.f730-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.f730-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.f730-airsupply.channel.40101.label = BT28 Airmix Temp +channel-group-type.nibeuplink.f730-airsupply.channel.40101.description = External airmix temperature BT28 +channel-group-type.nibeuplink.f730-airsupply.channel.40919.label = Air Mix +channel-group-type.nibeuplink.f730-airsupply.channel.40919.description = Air Mix +channel-group-type.nibeuplink.f730-airsupply.channel.41026.label = EB100-Adjusted BS1 Air Flow +channel-group-type.nibeuplink.f730-airsupply.channel.41026.description = Adjusted BS1 Air Flow (BT100) +channel-group-type.nibeuplink.f730-airsupply.channel.43124.label = Airflow Ref. +channel-group-type.nibeuplink.f730-airsupply.channel.43124.description = Reference value for the airflow. +channel-group-type.nibeuplink.f730-airsupply.channel.43125.label = Airflow Reduction +channel-group-type.nibeuplink.f730-airsupply.channel.43125.description = Airflow Reduction +channel-group-type.nibeuplink.f730-compressor.label = Compressor Channels +channel-group-type.nibeuplink.f730-compressor.channel.40017.label = EB100-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.f730-compressor.channel.40017.description = Condensor out temperature, BT12 +channel-group-type.nibeuplink.f730-compressor.channel.40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.f730-compressor.channel.40018.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.f730-compressor.channel.40019.label = EB100-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.f730-compressor.channel.40019.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.f730-compressor.channel.40020.label = EB100-BT16 Evaporator Temp +channel-group-type.nibeuplink.f730-compressor.channel.40020.description = Evaporator Temp (BT16) +channel-group-type.nibeuplink.f730-compressor.channel.40022.label = EB100-EP14-BT17 Suction +channel-group-type.nibeuplink.f730-compressor.channel.40022.description = Suction temperature, BT17 +channel-group-type.nibeuplink.f730-compressor.channel.43066.label = Defrosting Time +channel-group-type.nibeuplink.f730-compressor.channel.43066.description = Defrosting time, no defrosting heater in the product +channel-group-type.nibeuplink.f730-compressor.channel.43122.label = Compr. Current Min.freq. +channel-group-type.nibeuplink.f730-compressor.channel.43122.description = The current minimum frequency of the compressor +channel-group-type.nibeuplink.f730-compressor.channel.43123.label = Compr. Current Max.freq. +channel-group-type.nibeuplink.f730-compressor.channel.43123.description = The current maximum frequency of the compressor +channel-group-type.nibeuplink.f730-compressor.channel.43136.label = Compressor Frequency, Actual +channel-group-type.nibeuplink.f730-compressor.channel.43136.description = The compressor frequency the compressor is currently running at +channel-group-type.nibeuplink.f730-compressor.channel.43181.label = Chargepump Speed +channel-group-type.nibeuplink.f730-compressor.channel.43181.description = Chargepump Speed +channel-group-type.nibeuplink.f730-compressor.channel.43416.label = Compressor Starts EB100-EP14 +channel-group-type.nibeuplink.f730-compressor.channel.43416.description = Number of compressor starts +channel-group-type.nibeuplink.f730-compressor.channel.43420.label = Tot. Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f730-compressor.channel.43420.description = Total compressor operation time +channel-group-type.nibeuplink.f730-compressor.channel.43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f730-compressor.channel.43424.description = Total compressor operation time in hot water mode +channel-group-type.nibeuplink.f750-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.f750-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.f750-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.f750-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.f750-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.f750-airsupply.channel.41026.label = EB100-Adjusted BS1 Air Flow +channel-group-type.nibeuplink.f750-airsupply.channel.41026.description = Adjusted BS1 Air Flow (BT100) +channel-group-type.nibeuplink.f750-airsupply.channel.43124.label = Airflow Ref. +channel-group-type.nibeuplink.f750-airsupply.channel.43124.description = Reference value for the airflow. +channel-group-type.nibeuplink.f750-airsupply.channel.47260.label = Selected Fan Speed +channel-group-type.nibeuplink.f750-airsupply.channel.47260.description = Currently selected fan speed +channel-group-type.nibeuplink.f750-compressor.label = Compressor Channels +channel-group-type.nibeuplink.f750-compressor.channel.40017.label = EB100-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.f750-compressor.channel.40017.description = Condensor out temperature, BT12 +channel-group-type.nibeuplink.f750-compressor.channel.40018.label = EB100-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.f750-compressor.channel.40018.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.f750-compressor.channel.40019.label = EB100-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.f750-compressor.channel.40019.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.f750-compressor.channel.40020.label = EB100-BT16 Evaporator Temp +channel-group-type.nibeuplink.f750-compressor.channel.40020.description = Evaporator Temp (BT16) +channel-group-type.nibeuplink.f750-compressor.channel.40022.label = EB100-EP14-BT17 Suction +channel-group-type.nibeuplink.f750-compressor.channel.40022.description = Suction temperature, BT17 +channel-group-type.nibeuplink.f750-compressor.channel.43122.label = Compr. Current Min.freq. +channel-group-type.nibeuplink.f750-compressor.channel.43122.description = The current minimum frequency of the compressor +channel-group-type.nibeuplink.f750-compressor.channel.43123.label = Compr. Current Max.freq. +channel-group-type.nibeuplink.f750-compressor.channel.43123.description = The current maximum frequency of the compressor +channel-group-type.nibeuplink.f750-compressor.channel.43136.label = Compressor Frequency, Actual +channel-group-type.nibeuplink.f750-compressor.channel.43136.description = The compressor frequency the compressor is currently running at +channel-group-type.nibeuplink.f750-compressor.channel.43181.label = Chargepump Speed +channel-group-type.nibeuplink.f750-compressor.channel.43181.description = Chargepump Speed +channel-group-type.nibeuplink.f750-compressor.channel.43416.label = Compressor Starts EB100-EP14 +channel-group-type.nibeuplink.f750-compressor.channel.43416.description = Number of compressor starts +channel-group-type.nibeuplink.f750-compressor.channel.43420.label = Tot. Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f750-compressor.channel.43420.description = Total compressor operation time +channel-group-type.nibeuplink.f750-compressor.channel.43424.label = Tot. HW Op.time Compr. EB100-EP14 +channel-group-type.nibeuplink.f750-compressor.channel.43424.description = Total compressor operation time in hot water mode +channel-group-type.nibeuplink.vvm310-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.vvm310-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.vvm310-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.vvm310-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.vvm310-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.vvm310-airsupply.channel.40075.label = BT22 Supply Air Temp. +channel-group-type.nibeuplink.vvm310-airsupply.channel.40075.description = Supply Air Temperature (BT22) +channel-group-type.nibeuplink.vvm310-airsupply.channel.40183.label = AZ30-BT23 Outdoor Temp. ERS +channel-group-type.nibeuplink.vvm310-airsupply.channel.40183.description = Outdoor Temperature (BT23) +channel-group-type.nibeuplink.vvm310-airsupply.channel.40311.label = External ERS Accessory GQ2 Speed +channel-group-type.nibeuplink.vvm310-airsupply.channel.40311.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-group-type.nibeuplink.vvm310-airsupply.channel.40312.label = External ERS Accessory GQ3 Speed +channel-group-type.nibeuplink.vvm310-airsupply.channel.40312.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-group-type.nibeuplink.vvm310-airsupply.channel.40942.label = External ERS Accessory Block Status +channel-group-type.nibeuplink.vvm310-airsupply.channel.40942.description = Indicates if the ERS accessory is externaly blocked. +channel-group-type.nibeuplink.vvm310-airsupply.channel.47260.label = Selected Fan Speed +channel-group-type.nibeuplink.vvm310-airsupply.channel.47260.description = Currently selected fan speed +channel-group-type.nibeuplink.vvm310-compressor.label = Compressor Channels +channel-group-type.nibeuplink.vvm310-compressor.channel.40737.label = EB101-EP14 Tot. Cooling Op.time Compr +channel-group-type.nibeuplink.vvm310-compressor.channel.40737.description = Total operation time of compressor in cooling mode +channel-group-type.nibeuplink.vvm310-compressor.channel.40782.label = EB101 Cpr Frequency Desired F2040 +channel-group-type.nibeuplink.vvm310-compressor.channel.40782.description = The desired frequency as shown in service info +channel-group-type.nibeuplink.vvm310-compressor.channel.44055.label = EB101-EP14-BT3 Return Temp. +channel-group-type.nibeuplink.vvm310-compressor.channel.44055.description = Return temperature, BT3 +channel-group-type.nibeuplink.vvm310-compressor.channel.44058.label = EB101-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.vvm310-compressor.channel.44058.description = Condensor temperature, BT12 +channel-group-type.nibeuplink.vvm310-compressor.channel.44059.label = EB101-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.vvm310-compressor.channel.44059.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.vvm310-compressor.channel.44060.label = EB101-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.vvm310-compressor.channel.44060.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.vvm310-compressor.channel.44061.label = EB101-EP14-BT17 Suction +channel-group-type.nibeuplink.vvm310-compressor.channel.44061.description = Suction temperature, BT17 +channel-group-type.nibeuplink.vvm310-compressor.channel.44069.label = EB101-EP14 Compressor Starts +channel-group-type.nibeuplink.vvm310-compressor.channel.44069.description = Total compressor starts +channel-group-type.nibeuplink.vvm310-compressor.channel.44071.label = EB101-EP14 Tot. Op.time Compr +channel-group-type.nibeuplink.vvm310-compressor.channel.44071.description = Total operation time of compressor +channel-group-type.nibeuplink.vvm310-compressor.channel.44073.label = EB101-EP14 Tot. HW Op.time Compr +channel-group-type.nibeuplink.vvm310-compressor.channel.44073.description = Total operation time of compressor in hotwater mode +channel-group-type.nibeuplink.vvm310-compressor.channel.44362.label = EB101-EP14-BT28 Outdoor Temp +channel-group-type.nibeuplink.vvm310-compressor.channel.44362.description = Current outdoor temperature, BT28 +channel-group-type.nibeuplink.vvm310-compressor.channel.44363.label = EB101-EP14-BT16 Evaporator +channel-group-type.nibeuplink.vvm310-compressor.channel.44363.description = Evaporator temperature, BT16 +channel-group-type.nibeuplink.vvm310-compressor.channel.44396.label = EB101 Speed Charge Pump +channel-group-type.nibeuplink.vvm310-compressor.channel.44396.description = Speed Charge Pump +channel-group-type.nibeuplink.vvm310-compressor.channel.44457.label = EB101-EP14 Compressor State +channel-group-type.nibeuplink.vvm310-compressor.channel.44457.description = Compressor state +channel-group-type.nibeuplink.vvm310-compressor.channel.44699.label = EB101-EP14-BT4 Pressure Sensor +channel-group-type.nibeuplink.vvm310-compressor.channel.44699.description = Pressure Sensor (BT4) +channel-group-type.nibeuplink.vvm310-compressor.channel.44700.label = EB101-EP14 Low Pressure Sensor Outdoor Unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44700.description = Low pressure sensor outdoor unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44701.label = EB101-EP14 Actual Cpr Frequency Outdoor Unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44701.description = Actual compressor frequency of the outdoor unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44702.label = EB101-EP14 Protection Status Register Outdoor Unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44702.description = rotection status register of the outdoor unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44703.label = EB101-EP14 Defrosting Outdoor Unit +channel-group-type.nibeuplink.vvm310-compressor.channel.44703.description = Defrosting state of the outdoor unit +channel-group-type.nibeuplink.vvm310-general.label = General Channels +channel-group-type.nibeuplink.vvm310-general.channel.40121.label = BT63 Add Supply Temp +channel-group-type.nibeuplink.vvm310-general.channel.40121.description = Supply Temp at internal additional heater (BT63) +channel-group-type.nibeuplink.vvm310-general.channel.44270.label = Calc. Cooling Supply S1 +channel-group-type.nibeuplink.vvm310-general.channel.44270.description = Calculated supply temperature in cooling mode for the climate system +channel-group-type.nibeuplink.vvm310-general.channel.44302.label = Heat Meter - Cooling Cpr EP14 +channel-group-type.nibeuplink.vvm310-general.channel.44302.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.vvm310-general.channel.47011.label = Heat Offset S1 +channel-group-type.nibeuplink.vvm310-general.channel.47011.description = Offset of the heat curve, see manual for more information +channel-group-type.nibeuplink.vvm310-general.channel.47394.label = Use Room Sensor S1 +channel-group-type.nibeuplink.vvm310-general.channel.47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-group-type.nibeuplink.vvm310-general.channel.47402.label = Room Sensor Factor S1 +channel-group-type.nibeuplink.vvm310-general.channel.47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-group-type.nibeuplink.vvm310-general.channel.48793.label = Room Sensor Cool Factor S1 +channel-group-type.nibeuplink.vvm310-general.channel.48793.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. +channel-group-type.nibeuplink.vvm320-airsupply.label = Air Supply/Exhaust Channels +channel-group-type.nibeuplink.vvm320-airsupply.channel.40025.label = BT20 Exhaust Air Temp. 1 +channel-group-type.nibeuplink.vvm320-airsupply.channel.40025.description = Exhaust Air Temperature (BT20) +channel-group-type.nibeuplink.vvm320-airsupply.channel.40026.label = BT21 Vented Air Temp. 1 +channel-group-type.nibeuplink.vvm320-airsupply.channel.40026.description = Vented Air Temperature (BT21) +channel-group-type.nibeuplink.vvm320-airsupply.channel.40075.label = BT22 Supply Air Temp. +channel-group-type.nibeuplink.vvm320-airsupply.channel.40075.description = Supply Air Temperature (BT22) +channel-group-type.nibeuplink.vvm320-airsupply.channel.40183.label = AZ30-BT23 Outdoor Temp. ERS +channel-group-type.nibeuplink.vvm320-airsupply.channel.40183.description = Outdoor Temperature (BT23) +channel-group-type.nibeuplink.vvm320-airsupply.channel.40311.label = External ERS Accessory GQ2 Speed +channel-group-type.nibeuplink.vvm320-airsupply.channel.40311.description = Indicates the speed of the GQ2 fan speed on the ERS accessory. +channel-group-type.nibeuplink.vvm320-airsupply.channel.40312.label = External ERS Accessory GQ3 Speed +channel-group-type.nibeuplink.vvm320-airsupply.channel.40312.description = Indicates the speed of the GQ3 fan speed on the ERS accessory. +channel-group-type.nibeuplink.vvm320-airsupply.channel.40942.label = External ERS Accessory Block Status +channel-group-type.nibeuplink.vvm320-airsupply.channel.40942.description = Indicates if the ERS accessory is externaly blocked. +channel-group-type.nibeuplink.vvm320-airsupply.channel.47260.label = Selected Fan Speed +channel-group-type.nibeuplink.vvm320-airsupply.channel.47260.description = Currently selected fan speed +channel-group-type.nibeuplink.vvm320-compressor.label = Compressor Channels +channel-group-type.nibeuplink.vvm320-compressor.channel.40737.label = EB101-EP14 Tot. Cooling Op.time Compr +channel-group-type.nibeuplink.vvm320-compressor.channel.40737.description = Total operation time of compressor in cooling mode +channel-group-type.nibeuplink.vvm320-compressor.channel.40782.label = EB101 Cpr Frequency Desired F2040 +channel-group-type.nibeuplink.vvm320-compressor.channel.40782.description = The desired frequency as shown in service info +channel-group-type.nibeuplink.vvm320-compressor.channel.44055.label = EB101-EP14-BT3 Return Temp. +channel-group-type.nibeuplink.vvm320-compressor.channel.44055.description = Return temperature, BT3 +channel-group-type.nibeuplink.vvm320-compressor.channel.44058.label = EB101-EP14-BT12 Condensor Out +channel-group-type.nibeuplink.vvm320-compressor.channel.44058.description = Condensor temperature, BT12 +channel-group-type.nibeuplink.vvm320-compressor.channel.44059.label = EB101-EP14-BT14 Hot Gas Temp +channel-group-type.nibeuplink.vvm320-compressor.channel.44059.description = Hot gas temperature, BT14 +channel-group-type.nibeuplink.vvm320-compressor.channel.44060.label = EB101-EP14-BT15 Liquid Line +channel-group-type.nibeuplink.vvm320-compressor.channel.44060.description = Liquid line temperature, BT15 +channel-group-type.nibeuplink.vvm320-compressor.channel.44061.label = EB101-EP14-BT17 Suction +channel-group-type.nibeuplink.vvm320-compressor.channel.44061.description = Suction temperature, BT17 +channel-group-type.nibeuplink.vvm320-compressor.channel.44069.label = EB101-EP14 Compressor Starts +channel-group-type.nibeuplink.vvm320-compressor.channel.44069.description = Total compressor starts +channel-group-type.nibeuplink.vvm320-compressor.channel.44071.label = EB101-EP14 Tot. Op.time Compr +channel-group-type.nibeuplink.vvm320-compressor.channel.44071.description = Total operation time of compressor +channel-group-type.nibeuplink.vvm320-compressor.channel.44073.label = EB101-EP14 Tot. HW Op.time Compr +channel-group-type.nibeuplink.vvm320-compressor.channel.44073.description = Total operation time of compressor in hotwater mode +channel-group-type.nibeuplink.vvm320-compressor.channel.44362.label = EB101-EP14-BT28 Outdoor Temp +channel-group-type.nibeuplink.vvm320-compressor.channel.44362.description = Current outdoor temperature, BT28 +channel-group-type.nibeuplink.vvm320-compressor.channel.44363.label = EB101-EP14-BT16 Evaporator +channel-group-type.nibeuplink.vvm320-compressor.channel.44363.description = Evaporator temperature, BT16 +channel-group-type.nibeuplink.vvm320-compressor.channel.44396.label = EB101 Speed Charge Pump +channel-group-type.nibeuplink.vvm320-compressor.channel.44396.description = Speed Charge Pump +channel-group-type.nibeuplink.vvm320-compressor.channel.44457.label = EB101-EP14 Compressor State +channel-group-type.nibeuplink.vvm320-compressor.channel.44457.description = Compressor state +channel-group-type.nibeuplink.vvm320-compressor.channel.44699.label = EB101-EP14-BT4 Pressure Sensor +channel-group-type.nibeuplink.vvm320-compressor.channel.44699.description = Pressure Sensor (BT4) +channel-group-type.nibeuplink.vvm320-compressor.channel.44700.label = EB101-EP14 Low Pressure Sensor Outdoor Unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44700.description = Low pressure sensor outdoor unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44701.label = EB101-EP14 Actual Cpr Frequency Outdoor Unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44701.description = Actual compressor frequency of the outdoor unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44702.label = EB101-EP14 Protection Status Register Outdoor Unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44702.description = rotection status register of the outdoor unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44703.label = EB101-EP14 Defrosting Outdoor Unit +channel-group-type.nibeuplink.vvm320-compressor.channel.44703.description = Defrosting state of the outdoor unit +channel-group-type.nibeuplink.vvm320-general.label = General Channels +channel-group-type.nibeuplink.vvm320-general.channel.40121.label = BT63 Add Supply Temp +channel-group-type.nibeuplink.vvm320-general.channel.40121.description = Supply Temp at internal additional heater (BT63) +channel-group-type.nibeuplink.vvm320-general.channel.44270.label = Calc. Cooling Supply S1 +channel-group-type.nibeuplink.vvm320-general.channel.44270.description = Calculated supply temperature in cooling mode for the climate system +channel-group-type.nibeuplink.vvm320-general.channel.44302.label = Heat Meter - Cooling Cpr EP14 +channel-group-type.nibeuplink.vvm320-general.channel.44302.description = Accumulated energy production as calculated by the heat meter +channel-group-type.nibeuplink.vvm320-general.channel.47011.label = Heat Offset S1 +channel-group-type.nibeuplink.vvm320-general.channel.47011.description = Offset of the heat curve, see manual for more information +channel-group-type.nibeuplink.vvm320-general.channel.47374.label = Start Temperature Cooling +channel-group-type.nibeuplink.vvm320-general.channel.47374.description = Start Temperature Cooling in Auto mode +channel-group-type.nibeuplink.vvm320-general.channel.47375.label = Stop Temperature Heating +channel-group-type.nibeuplink.vvm320-general.channel.47375.description = Stop Temperature Heating in Auto mode +channel-group-type.nibeuplink.vvm320-general.channel.47376.label = Stop Temperature Additive +channel-group-type.nibeuplink.vvm320-general.channel.47376.description = Stop Temperature Additive heater in Auto mode +channel-group-type.nibeuplink.vvm320-general.channel.47377.label = Outdoor Filter Time +channel-group-type.nibeuplink.vvm320-general.channel.47377.description = Outdoor Filter Time in Auto mode +channel-group-type.nibeuplink.vvm320-general.channel.47394.label = Use Room Sensor S1 +channel-group-type.nibeuplink.vvm320-general.channel.47394.description = When activated the system uses the room sensor 0=Off 1=On +channel-group-type.nibeuplink.vvm320-general.channel.47402.label = Room Sensor Factor S1 +channel-group-type.nibeuplink.vvm320-general.channel.47402.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature. +channel-group-type.nibeuplink.vvm320-general.channel.48793.label = Room Sensor Cool Factor S1 +channel-group-type.nibeuplink.vvm320-general.channel.48793.description = Setting of how much the difference between set and actual room temperature should affect the supply temperature in cooling mode. + +# channel types + +channel-type.nibeuplink.rwtype-degree-minutes.label = Unnamed Degree Minutes +channel-type.nibeuplink.rwtype-fan-speed.label = Selected Fan Speed +channel-type.nibeuplink.rwtype-fan-speed.state.option.0 = normal +channel-type.nibeuplink.rwtype-fan-speed.state.option.1 = speed 1 +channel-type.nibeuplink.rwtype-fan-speed.state.option.2 = speed 2 +channel-type.nibeuplink.rwtype-fan-speed.state.option.3 = speed 3 +channel-type.nibeuplink.rwtype-fan-speed.state.option.4 = speed 4 +channel-type.nibeuplink.rwtype-filter-time.label = Outdoor Filter Time +channel-type.nibeuplink.rwtype-heat-offset.label = Heat Offset +channel-type.nibeuplink.rwtype-hw-lux.label = Temporary Lux +channel-type.nibeuplink.rwtype-hw-lux.state.option.0 = Off +channel-type.nibeuplink.rwtype-hw-lux.state.option.1 = 3h +channel-type.nibeuplink.rwtype-hw-lux.state.option.2 = 6h +channel-type.nibeuplink.rwtype-hw-lux.state.option.3 = 12h +channel-type.nibeuplink.rwtype-hw-lux.state.option.4 = One time +channel-type.nibeuplink.rwtype-hw-mode.label = Hot Water Mode +channel-type.nibeuplink.rwtype-hw-mode.state.option.0 = Economy +channel-type.nibeuplink.rwtype-hw-mode.state.option.1 = Normal +channel-type.nibeuplink.rwtype-hw-mode.state.option.2 = Luxury +channel-type.nibeuplink.rwtype-room-sensor-factor.label = Room Sensor Factor +channel-type.nibeuplink.rwtype-start-cooling.label = Start Temperature Cooling +channel-type.nibeuplink.rwtype-stop-add-heating.label = Stop Temperature Additive +channel-type.nibeuplink.rwtype-stop-heating.label = Stop Temperature Heating +channel-type.nibeuplink.rwtype-switch.label = Unnamed Switch +channel-type.nibeuplink.type-defrosting-state.label = Defrosting State +channel-type.nibeuplink.type-defrosting-state.state.option.0 = No +channel-type.nibeuplink.type-defrosting-state.state.option.1 = Active +channel-type.nibeuplink.type-defrosting-state.state.option.2 = Passive +channel-type.nibeuplink.type-electric-current.label = Unnamed Current +channel-type.nibeuplink.type-energy.label = Unnamed Energy +channel-type.nibeuplink.type-flow.label = Unnamed Flow +channel-type.nibeuplink.type-frequency-scale10.label = Unnamed Frequency +channel-type.nibeuplink.type-frequency-unscaled.label = Unnamed Frequency +channel-type.nibeuplink.type-hpac-state.label = HPAC State +channel-type.nibeuplink.type-hpac-state.state.option.10 = Off +channel-type.nibeuplink.type-hpac-state.state.option.20 = Wait +channel-type.nibeuplink.type-hpac-state.state.option.30 = Passive +channel-type.nibeuplink.type-hpac-state.state.option.40 = PassiveWait +channel-type.nibeuplink.type-hpac-state.state.option.50 = Active +channel-type.nibeuplink.type-hpac-state.state.option.60 = ActiveWait +channel-type.nibeuplink.type-hpac-state.state.option.70 = ActiveProtWait +channel-type.nibeuplink.type-number-scale10.label = Unnamed Number (0.1) +channel-type.nibeuplink.type-number-scale100.label = Unnamed Number (0.01) +channel-type.nibeuplink.type-number-unscaled.label = Unnamed Number +channel-type.nibeuplink.type-power.label = Unnamed Power +channel-type.nibeuplink.type-pressure.label = Unnamed Pressure +channel-type.nibeuplink.type-speed-percent.label = Unnamed Speed +channel-type.nibeuplink.type-switch.label = Unnamed Switch +channel-type.nibeuplink.type-temperature.label = Unnamed Temperature +channel-type.nibeuplink.type-time-scale10.label = Unnamed Time +channel-type.nibeuplink.type-time-unscaled.label = Unnamed Time diff --git a/bundles/org.openhab.binding.nikobus/src/main/resources/OH-INF/i18n/nikobus.properties b/bundles/org.openhab.binding.nikobus/src/main/resources/OH-INF/i18n/nikobus.properties new file mode 100644 index 0000000000000..6bff0b760033a --- /dev/null +++ b/bundles/org.openhab.binding.nikobus/src/main/resources/OH-INF/i18n/nikobus.properties @@ -0,0 +1,90 @@ +# binding + +binding.nikobus.name = Nikobus Binding +binding.nikobus.description = This is the binding for Nikobus. + +# thing types + +thing-type.nikobus.dimmer-module.label = Dimmer Module +thing-type.nikobus.dimmer-module.description = Nikobus Dimmer module +thing-type.nikobus.dimmer-module.channel.output-1.label = Output 1 +thing-type.nikobus.dimmer-module.channel.output-10.label = Output 10 +thing-type.nikobus.dimmer-module.channel.output-11.label = Output 11 +thing-type.nikobus.dimmer-module.channel.output-12.label = Output 12 +thing-type.nikobus.dimmer-module.channel.output-2.label = Output 2 +thing-type.nikobus.dimmer-module.channel.output-3.label = Output 3 +thing-type.nikobus.dimmer-module.channel.output-4.label = Output 4 +thing-type.nikobus.dimmer-module.channel.output-5.label = Output 5 +thing-type.nikobus.dimmer-module.channel.output-6.label = Output 6 +thing-type.nikobus.dimmer-module.channel.output-7.label = Output 7 +thing-type.nikobus.dimmer-module.channel.output-8.label = Output 8 +thing-type.nikobus.dimmer-module.channel.output-9.label = Output 9 +thing-type.nikobus.pc-link.label = PC-Link +thing-type.nikobus.pc-link.description = PC-Link via serial connection +thing-type.nikobus.push-button.label = Push Button +thing-type.nikobus.push-button.description = A single push button +thing-type.nikobus.rollershutter-module.label = Rollershutter Module +thing-type.nikobus.rollershutter-module.description = Nikobus Rollershutter module +thing-type.nikobus.rollershutter-module.channel.output-1.label = Output 1 +thing-type.nikobus.rollershutter-module.channel.output-2.label = Output 2 +thing-type.nikobus.rollershutter-module.channel.output-3.label = Output 3 +thing-type.nikobus.rollershutter-module.channel.output-4.label = Output 4 +thing-type.nikobus.rollershutter-module.channel.output-5.label = Output 5 +thing-type.nikobus.rollershutter-module.channel.output-6.label = Output 6 +thing-type.nikobus.switch-module.label = Switch Module +thing-type.nikobus.switch-module.description = Nikobus Switch module +thing-type.nikobus.switch-module.channel.output-1.label = Output 1 +thing-type.nikobus.switch-module.channel.output-10.label = Output 10 +thing-type.nikobus.switch-module.channel.output-11.label = Output 11 +thing-type.nikobus.switch-module.channel.output-12.label = Output 12 +thing-type.nikobus.switch-module.channel.output-2.label = Output 2 +thing-type.nikobus.switch-module.channel.output-3.label = Output 3 +thing-type.nikobus.switch-module.channel.output-4.label = Output 4 +thing-type.nikobus.switch-module.channel.output-5.label = Output 5 +thing-type.nikobus.switch-module.channel.output-6.label = Output 6 +thing-type.nikobus.switch-module.channel.output-7.label = Output 7 +thing-type.nikobus.switch-module.channel.output-8.label = Output 8 +thing-type.nikobus.switch-module.channel.output-9.label = Output 9 + +# thing types config + +thing-type.config.nikobus.module.address.label = Address +thing-type.config.nikobus.module.address.description = The Nikobus address of the module +thing-type.config.nikobus.pc-link.port.label = Port +thing-type.config.nikobus.pc-link.port.description = The serial port used to connect to the Nikobus PC Link. +thing-type.config.nikobus.pc-link.refreshInterval.label = Refresh Interval +thing-type.config.nikobus.pc-link.refreshInterval.description = Refresh interval in seconds. +thing-type.config.nikobus.push-button.address.label = Address +thing-type.config.nikobus.push-button.address.description = The Nikobus address of the push-button. +thing-type.config.nikobus.push-button.impactedModules.label = Impacted Modules +thing-type.config.nikobus.push-button.impactedModules.description = Comma separated list of impacted modules, i.e. switch-module:s1:1 + +# channel types + +channel-type.nikobus.button.label = Button Event +channel-type.nikobus.button.description = Fires when the button is pressed +channel-type.nikobus.dimmer-output.label = Output +channel-type.nikobus.dimmer-output.description = Dimmer Module's Output +channel-type.nikobus.rollershutter-output.label = Output +channel-type.nikobus.rollershutter-output.description = Rollershutter Module's Output +channel-type.nikobus.switch-output.label = Output +channel-type.nikobus.switch-output.description = Switch Module's Output +channel-type.nikobus.trigger-button.label = Trigger Button Channel +channel-type.nikobus.trigger-filter.label = Trigger Filter Channel + +# channel types config + +channel-type.config.nikobus.rollershutter-output.delay.label = Delay +channel-type.config.nikobus.rollershutter-output.delay.description = Delay specifying how many seconds after duration module's output is set to OFF. Defaults to 5 seconds +channel-type.config.nikobus.rollershutter-output.duration.label = Duration +channel-type.config.nikobus.rollershutter-output.duration.description = Duration in seconds required for a rollershutter to get from open to closed +channel-type.config.nikobus.rollershutter-output.reverse.label = Reverse Direction +channel-type.config.nikobus.rollershutter-output.reverse.description = Reverse direction of rollershutters. Defaults to false +channel-type.config.nikobus.trigger-button.threshold.label = Threshold +channel-type.config.nikobus.trigger-button.threshold.description = Long-press threshold in milliseconds +channel-type.config.nikobus.trigger-filter.command.label = Command +channel-type.config.nikobus.trigger-filter.command.description = Command to send +channel-type.config.nikobus.trigger-filter.delay.label = Delay +channel-type.config.nikobus.trigger-filter.delay.description = Delay in milliseconds before triggered +channel-type.config.nikobus.trigger-filter.period.label = Period +channel-type.config.nikobus.trigger-filter.period.description = Time in milliseconds between successive triggers diff --git a/bundles/org.openhab.binding.novafinedust/src/main/resources/OH-INF/i18n/novafinedust.properties b/bundles/org.openhab.binding.novafinedust/src/main/resources/OH-INF/i18n/novafinedust.properties new file mode 100644 index 0000000000000..a6e2b3887a3ed --- /dev/null +++ b/bundles/org.openhab.binding.novafinedust/src/main/resources/OH-INF/i18n/novafinedust.properties @@ -0,0 +1,29 @@ +# binding + +binding.novafinedust.name = NovaFineDust Binding +binding.novafinedust.description = This is the binding for Nova Fitness Fine Dust SDS011 sensor. + +# thing types + +thing-type.novafinedust.SDS011.label = Nova SDS011 Fine Dust Sensor +thing-type.novafinedust.SDS011.description = Nova SDS011 Fine Dust Sensor connected via USB + +# thing types config + +thing-type.config.novafinedust.SDS011.pollingInterval.label = Polling Interval +thing-type.config.novafinedust.SDS011.pollingInterval.description = Device will be polled every x seconds (polling is not recommended) +thing-type.config.novafinedust.SDS011.port.label = USB Port +thing-type.config.novafinedust.SDS011.port.description = USB port the device is connected to i.e. /dev/ttyUSB0 +thing-type.config.novafinedust.SDS011.reporting.label = Mode +thing-type.config.novafinedust.SDS011.reporting.description = Reporting is strongly recommended to increase sensor lifetime +thing-type.config.novafinedust.SDS011.reporting.option.true = Reporting +thing-type.config.novafinedust.SDS011.reporting.option.false = Polling +thing-type.config.novafinedust.SDS011.reportingInterval.label = Reporting Interval +thing-type.config.novafinedust.SDS011.reportingInterval.description = Device will report every x minutes and sleep for x*60 - 30 seconds afterwards, 0 = as fast as possible without sleep + +# channel types + +channel-type.novafinedust.pm10-type.label = PM 10 +channel-type.novafinedust.pm10-type.description = The PM 10 value +channel-type.novafinedust.pm25-type.label = PM 2.5 +channel-type.novafinedust.pm25-type.description = The PM 2.5 value diff --git a/bundles/org.openhab.binding.nuki/src/main/resources/OH-INF/i18n/nuki.properties b/bundles/org.openhab.binding.nuki/src/main/resources/OH-INF/i18n/nuki.properties new file mode 100644 index 0000000000000..bbe646563e2eb --- /dev/null +++ b/bundles/org.openhab.binding.nuki/src/main/resources/OH-INF/i18n/nuki.properties @@ -0,0 +1,92 @@ +# binding + +binding.nuki.name = Nuki Binding +binding.nuki.description = The Nuki Binding allows simple and fast integration of Nuki Smart Locks into openHAB. This binding needs the Nuki Smart Lock(s) to be paired via Bluetooth with a Nuki Bridge to function correctly. + +# thing types + +thing-type.nuki.bridge.label = Nuki Bridge +thing-type.nuki.bridge.description = This bridge represents a Nuki Bridge on your local network. Nuki Smart Locks have to be paired via Bluetooth with it. +thing-type.nuki.opener.label = Nuki Opener +thing-type.nuki.opener.description = Nuki Opener which is paired via Bluetooth to a Nuki Bridge. +thing-type.nuki.smartlock.label = Nuki Smart Lock +thing-type.nuki.smartlock.description = Nuki Smart Lock which is paired via Bluetooth to a Nuki Bridge. + +# thing types config + +thing-type.config.nuki.bridge.apiToken.label = API Token +thing-type.config.nuki.bridge.apiToken.description = The API Token which you configured during Initial Bridge setup (https://nuki.io/en/support/bridge/bridge-setup/initial-bridge-setup/). +thing-type.config.nuki.bridge.ip.label = IP Address +thing-type.config.nuki.bridge.ip.description = The IP address of the Nuki Bridge. Look it up on your router. It is recommended to set a static IP address lease for the Nuki Bridge (and for your openHAB server too) on your router. +thing-type.config.nuki.bridge.manageCallbacks.label = Manage Nuki Bridge Callbacks +thing-type.config.nuki.bridge.manageCallbacks.description = Let the Nuki Binding manage the callback on the Nuki Bridge. Nuki bridge uses HTTP callback to notify openHAB about changes in device properties (e.g. when doors are opened, unlocked, doorbell rings, battery level changes etc.). If callback is not registered, binding will not work properly and channels will not be updated. If this is enabled, binding will automatically register and unregister callback as necessary. If this is disabled, user must register callback manually. It is recommended that this is turned on. +thing-type.config.nuki.bridge.port.label = Port +thing-type.config.nuki.bridge.port.description = The Port which you configured during Initial Bridge setup (https://nuki.io/en/support/bridge/bridge-setup/initial-bridge-setup/). +thing-type.config.nuki.bridge.secureToken.label = Secure Token +thing-type.config.nuki.bridge.secureToken.description = Use hashed token when communicating with bridge. This increases security and prevents sniffing of access token and replay attacks, since communication with bridge is not encrypted. For this feature to work, both device running openHAB and Nuki Bridge must have synchronized time. When disabled, token is sent in plain text with each bridge request. It is recommended that this is turned on unless there are problems with synchronizing time between openHAB and Nuki Bridge. +thing-type.config.nuki.opener.nukiId.label = Nuki ID +thing-type.config.nuki.opener.nukiId.description = The decimal string that identifies the Nuki Opener. +thing-type.config.nuki.smartlock.nukiId.label = Nuki ID +thing-type.config.nuki.smartlock.nukiId.description = The decimal string that identifies the Nuki Smart Lock. +thing-type.config.nuki.smartlock.unlatch.label = Unlatch +thing-type.config.nuki.smartlock.unlatch.description = If switched to On (or set to true) the Nuki Smart Lock will unlock the door but then also automatically pull the latch of the door lock. Usually, if the door hinges are correctly adjusted, the door will then swing open. + +# channel types + +channel-type.nuki.openerMode.label = Opener Mode +channel-type.nuki.openerMode.description = Use this channel to display/set current mode of the opener +channel-type.nuki.openerMode.state.option.2 = Door mode +channel-type.nuki.openerMode.state.option.3 = Continuous mode +channel-type.nuki.openerState.label = Opener State +channel-type.nuki.openerState.description = Use this channel if you want to execute other supported opener actions or to display the current opener state. +channel-type.nuki.openerState.state.option.0 = Untrained +channel-type.nuki.openerState.state.option.1 = Online +channel-type.nuki.openerState.state.option.3 = Ring to open active +channel-type.nuki.openerState.state.option.5 = Open +channel-type.nuki.openerState.state.option.7 = Opening +channel-type.nuki.openerState.state.option.253 = Boot run +channel-type.nuki.openerState.state.option.255 = Undefined +channel-type.nuki.openerState.command.option.1 = Activate ring to open +channel-type.nuki.openerState.command.option.2 = Deactivate ring to open +channel-type.nuki.openerState.command.option.3 = Electric strike actuation +channel-type.nuki.openerState.command.option.4 = Activate continuous mode +channel-type.nuki.openerState.command.option.5 = Deactivate continuous mode +channel-type.nuki.ringActionState.label = Ring Action State +channel-type.nuki.ringActionState.description = Channel is triggered when doorbell is rang, at most once every 30s +channel-type.nuki.ringActionTimestamp.label = Ring Action Timestamp +channel-type.nuki.ringActionTimestamp.description = Time of last ring action +channel-type.nuki.smartLockBatteryCharging.label = Battery Charging +channel-type.nuki.smartLockBatteryCharging.description = Use this channel to display the current state of charging +channel-type.nuki.smartLockBatteryCharging.state.option.OFF = Battery is not charging +channel-type.nuki.smartLockBatteryCharging.state.option.ON = Battery is charging +channel-type.nuki.smartlockDoorState.label = Door State +channel-type.nuki.smartlockDoorState.description = Use this channel to display the current state of the door sensor +channel-type.nuki.smartlockDoorState.state.option.0 = Unavailable +channel-type.nuki.smartlockDoorState.state.option.1 = Deactivated +channel-type.nuki.smartlockDoorState.state.option.2 = Closed +channel-type.nuki.smartlockDoorState.state.option.3 = Open +channel-type.nuki.smartlockDoorState.state.option.4 = Unknown +channel-type.nuki.smartlockDoorState.state.option.5 = Calibrating +channel-type.nuki.smartlockLock.label = Lock +channel-type.nuki.smartlockLock.description = Use this channel with a Switch Item to unlock and lock the door. Configure "Unlatch" to true if your Nuki Smart Lock is mounted on a door lock with a knob on the outside. +channel-type.nuki.smartlockLock.state.option.OFF = Unlocks the door +channel-type.nuki.smartlockLock.state.option.ON = Locks the door +channel-type.nuki.smartlockState.label = Lock State +channel-type.nuki.smartlockState.description = Use this channel if you want to execute other supported lock actions or to display the current lock state. +channel-type.nuki.smartlockState.state.option.0 = Uncalibrated +channel-type.nuki.smartlockState.state.option.1 = Locked +channel-type.nuki.smartlockState.state.option.2 = Unlocking +channel-type.nuki.smartlockState.state.option.3 = Unlocked +channel-type.nuki.smartlockState.state.option.4 = Locking +channel-type.nuki.smartlockState.state.option.5 = Unlatched +channel-type.nuki.smartlockState.state.option.6 = Unlocked (Lock 'n' Go) +channel-type.nuki.smartlockState.state.option.7 = Unlatching +channel-type.nuki.smartlockState.state.option.1002 = Unlocking (Lock 'n' Go) +channel-type.nuki.smartlockState.state.option.1007 = Unlatching (Lock 'n' Go) +channel-type.nuki.smartlockState.state.option.254 = Motor blocked +channel-type.nuki.smartlockState.state.option.255 = UNDEFINED +channel-type.nuki.smartlockState.command.option.1 = Unlock +channel-type.nuki.smartlockState.command.option.2 = Lock +channel-type.nuki.smartlockState.command.option.3 = Unlatch +channel-type.nuki.smartlockState.command.option.4 = Lock'n'go +channel-type.nuki.smartlockState.command.option.5 = Lock'n'go with unlatch diff --git a/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties new file mode 100644 index 0000000000000..20847e1807f96 --- /dev/null +++ b/bundles/org.openhab.binding.nuvo/src/main/resources/OH-INF/i18n/nuvo.properties @@ -0,0 +1,142 @@ +# binding + +binding.nuvo.name = Nuvo Whole House Audio Binding +binding.nuvo.description = Controls the Nuvo Grand Concerto or Essentia G Whole House Amplifier. + +# thing types + +thing-type.nuvo.amplifier.label = Nuvo Whole House Amplifier +thing-type.nuvo.amplifier.description = Grand Concerto or Essentia G Amplifier System +thing-type.nuvo.amplifier.group.source1.label = Source 1 +thing-type.nuvo.amplifier.group.source1.description = The Display Information for Source 1 +thing-type.nuvo.amplifier.group.source2.label = Source 2 +thing-type.nuvo.amplifier.group.source2.description = The Display Information for Source 2 +thing-type.nuvo.amplifier.group.source3.label = Source 3 +thing-type.nuvo.amplifier.group.source3.description = The Display Information for Source 3 +thing-type.nuvo.amplifier.group.source4.label = Source 4 +thing-type.nuvo.amplifier.group.source4.description = The Display Information for Source 4 +thing-type.nuvo.amplifier.group.source5.label = Source 5 +thing-type.nuvo.amplifier.group.source5.description = The Display Information for Source 5 +thing-type.nuvo.amplifier.group.source6.label = Source 6 +thing-type.nuvo.amplifier.group.source6.description = The Display Information for Source 6 +thing-type.nuvo.amplifier.group.system.label = System +thing-type.nuvo.amplifier.group.system.description = System Level Commands +thing-type.nuvo.amplifier.group.zone1.label = Zone 1 +thing-type.nuvo.amplifier.group.zone1.description = The Controls for Zone 1 +thing-type.nuvo.amplifier.group.zone2.label = Zone 2 +thing-type.nuvo.amplifier.group.zone2.description = The Controls for Zone 2 +thing-type.nuvo.amplifier.group.zone3.label = Zone 3 +thing-type.nuvo.amplifier.group.zone3.description = The Controls for Zone 3 +thing-type.nuvo.amplifier.group.zone4.label = Zone 4 +thing-type.nuvo.amplifier.group.zone4.description = The Controls for Zone 4 +thing-type.nuvo.amplifier.group.zone5.label = Zone 5 +thing-type.nuvo.amplifier.group.zone5.description = The Controls for Zone 5 +thing-type.nuvo.amplifier.group.zone6.label = Zone 6 +thing-type.nuvo.amplifier.group.zone6.description = The Controls for Zone 6 +thing-type.nuvo.amplifier.group.zone7.label = Zone 7 +thing-type.nuvo.amplifier.group.zone7.description = The Controls for Zone 7 +thing-type.nuvo.amplifier.group.zone8.label = Zone 8 +thing-type.nuvo.amplifier.group.zone8.description = The Controls for Zone 8 +thing-type.nuvo.amplifier.group.zone9.label = Zone 9 +thing-type.nuvo.amplifier.group.zone9.description = The Controls for Zone 9 +thing-type.nuvo.amplifier.group.zone10.label = Zone 10 +thing-type.nuvo.amplifier.group.zone10.description = The Controls for Zone 10 +thing-type.nuvo.amplifier.group.zone11.label = Zone 11 +thing-type.nuvo.amplifier.group.zone11.description = The Controls for Zone 11 +thing-type.nuvo.amplifier.group.zone12.label = Zone 12 +thing-type.nuvo.amplifier.group.zone12.description = The Controls for Zone 12 +thing-type.nuvo.amplifier.group.zone13.label = Zone 13 +thing-type.nuvo.amplifier.group.zone13.description = The Controls for Zone 13 +thing-type.nuvo.amplifier.group.zone14.label = Zone 14 +thing-type.nuvo.amplifier.group.zone14.description = The Controls for Zone 14 +thing-type.nuvo.amplifier.group.zone15.label = Zone 15 +thing-type.nuvo.amplifier.group.zone15.description = The Controls for Zone 15 +thing-type.nuvo.amplifier.group.zone16.label = Zone 16 +thing-type.nuvo.amplifier.group.zone16.description = The Controls for Zone 16 +thing-type.nuvo.amplifier.group.zone17.label = Zone 17 +thing-type.nuvo.amplifier.group.zone17.description = The Controls for Zone 17 +thing-type.nuvo.amplifier.group.zone18.label = Zone 18 +thing-type.nuvo.amplifier.group.zone18.description = The Controls for Zone 18 +thing-type.nuvo.amplifier.group.zone19.label = Zone 19 +thing-type.nuvo.amplifier.group.zone19.description = The Controls for Zone 19 +thing-type.nuvo.amplifier.group.zone20.label = Zone 20 +thing-type.nuvo.amplifier.group.zone20.description = The Controls for Zone 20 + +# thing types config + +thing-type.config.nuvo.amplifier.clockSync.label = Sync Clock On GConcerto +thing-type.config.nuvo.amplifier.clockSync.description = If set to true, the binding will sync the internal clock on the Grand Concerto to match the openHAB host's system clock. The sync job runs at binding startup and once an hour thereafter. The Essentia G has no RTC, so this setting has no effect on that component. +thing-type.config.nuvo.amplifier.host.label = Address +thing-type.config.nuvo.amplifier.host.description = Host Name or IP Address of the machine connected to the Nuvo amplifier (Serial over IP) +thing-type.config.nuvo.amplifier.numZones.label = Number of Zones +thing-type.config.nuvo.amplifier.numZones.description = Number of Zones on the amplifier to utilize in the binding (Up to 20 zones when using expansion module) +thing-type.config.nuvo.amplifier.port.label = Port +thing-type.config.nuvo.amplifier.port.description = Communication Port (serial over IP). For IP connection to the Nuvo amplifier. Use port 5006 with MPS4 server. +thing-type.config.nuvo.amplifier.serialPort.label = Serial Port +thing-type.config.nuvo.amplifier.serialPort.description = Serial Port to use for connecting to the Nuvo amplifier + +# channel group types + +channel-group-type.nuvo.source_info.label = Source Info +channel-group-type.nuvo.source_info.description = The Display Information for the Source +channel-group-type.nuvo.system.label = System +channel-group-type.nuvo.system.description = System Level Commands +channel-group-type.nuvo.zone.label = Zone Controls +channel-group-type.nuvo.zone.description = The Controls for the Zone + +# channel types + +channel-type.nuvo.alloff.label = All Off +channel-type.nuvo.alloff.description = Turn All Zones Off +channel-type.nuvo.balance.label = Balance Adjustment +channel-type.nuvo.balance.description = Adjust the Balance Setting for the Zone +channel-type.nuvo.bass.label = Bass Adjustment +channel-type.nuvo.bass.description = Adjust the Bass Setting for the Zone +channel-type.nuvo.button_press.label = Button Pressed +channel-type.nuvo.button_press.description = Indicates the Last Button Pressed On the Keypad for a Non NuvoNet Source +channel-type.nuvo.control.label = Control +channel-type.nuvo.control.description = Transport Controls e.g. Play/Pause/Next/Previous for the Current Source +channel-type.nuvo.display_line1.label = Display Line 1 +channel-type.nuvo.display_line1.description = 1st Line of Text Being Displayed on the Keypad +channel-type.nuvo.display_line2.label = Display Line 2 +channel-type.nuvo.display_line2.description = 2nd Line of Text Being Displayed on the Keypad +channel-type.nuvo.display_line3.label = Display Line 3 +channel-type.nuvo.display_line3.description = 3rd Line of Text Being Displayed on the Keypad +channel-type.nuvo.display_line4.label = Display Line 4 +channel-type.nuvo.display_line4.description = 4th Line of Text Being Displayed on the Keypad +channel-type.nuvo.dnd.label = Do Not Disturb +channel-type.nuvo.dnd.description = A Switch That Controls If the Zone Should Ignore an Incoming Audio Page +channel-type.nuvo.favorite.label = Favorite +channel-type.nuvo.favorite.description = Select a Preset Favorite for the Zone +channel-type.nuvo.favorite.state.option.1 = Favorite 1 +channel-type.nuvo.favorite.state.option.2 = Favorite 2 +channel-type.nuvo.favorite.state.option.3 = Favorite 3 +channel-type.nuvo.favorite.state.option.4 = Favorite 4 +channel-type.nuvo.favorite.state.option.5 = Favorite 5 +channel-type.nuvo.favorite.state.option.6 = Favorite 6 +channel-type.nuvo.favorite.state.option.7 = Favorite 7 +channel-type.nuvo.favorite.state.option.8 = Favorite 8 +channel-type.nuvo.favorite.state.option.9 = Favorite 9 +channel-type.nuvo.favorite.state.option.10 = Favorite 10 +channel-type.nuvo.favorite.state.option.11 = Favorite 11 +channel-type.nuvo.favorite.state.option.12 = Favorite 12 +channel-type.nuvo.lock.label = Locked +channel-type.nuvo.lock.description = Indicates If This Zone Is Locked +channel-type.nuvo.lock.state.option.CLOSED = Unlocked +channel-type.nuvo.lock.state.option.OPEN = Locked +channel-type.nuvo.loudness.label = Loudness Compensation +channel-type.nuvo.loudness.description = A Switch That Controls the Loudness Compensation Setting for the Zone +channel-type.nuvo.page.label = Page +channel-type.nuvo.page.description = Activates the Page Mode for All Zones +channel-type.nuvo.party.label = Party Mode +channel-type.nuvo.party.description = Activate Party Mode With This Zone as the Host +channel-type.nuvo.play_mode.label = Play Mode +channel-type.nuvo.play_mode.description = The Current Playback Mode of the Source +channel-type.nuvo.source.label = Source Input +channel-type.nuvo.source.description = Select the Source Input for the Zone +channel-type.nuvo.track_length.label = Track Length +channel-type.nuvo.track_length.description = The Total Running Time of the Current Playing Track +channel-type.nuvo.track_position.label = Track Position +channel-type.nuvo.track_position.description = The Running Time Elapsed of the Current Playing Track +channel-type.nuvo.treble.label = Treble Adjustment +channel-type.nuvo.treble.description = Adjust the Treble Setting for the Zone diff --git a/bundles/org.openhab.binding.nzwateralerts/src/main/resources/OH-INF/i18n/nzwateralerts.properties b/bundles/org.openhab.binding.nzwateralerts/src/main/resources/OH-INF/i18n/nzwateralerts.properties new file mode 100644 index 0000000000000..67c28a236f3e4 --- /dev/null +++ b/bundles/org.openhab.binding.nzwateralerts/src/main/resources/OH-INF/i18n/nzwateralerts.properties @@ -0,0 +1,45 @@ +# binding + +binding.nzwateralerts.name = NZ Water Alerts Binding +binding.nzwateralerts.description = Water Alert Levels for New Zealand water supply. + +# thing types + +thing-type.nzwateralerts.wateralert.label = Alert +thing-type.nzwateralerts.wateralert.description = Water Alert Levels for New Zealand water supply. + +# thing types config + +thing-type.config.nzwateralerts.wateralert.location.label = Location +thing-type.config.nzwateralerts.wateralert.location.description = The location to get the Water Alert level for. +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:whangarei:breambay = Bream Bay +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:kaipara:dargavilleampbaylys = Dargaville & Baylys +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:kaipara:glinksgully = Glinks Gully +thing-type.config.nzwateralerts.wateralert.location.option.smartwater:hamilton:hamilton = Hamilton City +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:kaikohengawha = Kaikohe / Ngawha +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:kaitaia = Kaitaia +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:kerikeriwaipapa = Kerikeri / Waipapa +thing-type.config.nzwateralerts.wateralert.location.option.smartwater:waipa:kihikihi = Kihikihi +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:whangarei:mangapai = Mangapai +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:kaipara:mangawhai = Mangawhai +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:whangarei:maungakaramea = Maungakaramea +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:kaipara:maungaturoto = Maungaturoto +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:moerewakawakawa = Moerewa / Kawakawa +thing-type.config.nzwateralerts.wateralert.location.option.napiercitycouncil:napier:napier = Napier +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:okaihau = Okaihau +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:opononiomapere = Opononi / Omapere +thing-type.config.nzwateralerts.wateralert.location.option.smartwater:waipa:pukerimu = Pukerimu +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:rawene = Rawene +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:kaipara:ruawai = Ruawai +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:russell = Russell +thing-type.config.nzwateralerts.wateralert.location.option.smartwater:waipa:waipa = Waipa District +thing-type.config.nzwateralerts.wateralert.location.option.smartwater:waikato:waikato = Waikato District +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:farnorth:waitangipaihiaopua = Waitangi / Paihia / Opua +thing-type.config.nzwateralerts.wateralert.location.option.bewaterwise:whangarei:whangarei = Whangarei +thing-type.config.nzwateralerts.wateralert.refreshInterval.label = Refresh Interval +thing-type.config.nzwateralerts.wateralert.refreshInterval.description = The interval (in hours) to refresh the data. + +# channel types + +channel-type.nzwateralerts.alertlevel.label = Alert Level +channel-type.nzwateralerts.alertlevel.description = The alert level for the location. diff --git a/bundles/org.openhab.binding.oceanic/src/main/resources/OH-INF/i18n/oceanic.properties b/bundles/org.openhab.binding.oceanic/src/main/resources/OH-INF/i18n/oceanic.properties new file mode 100644 index 0000000000000..a63c0e11ae84c --- /dev/null +++ b/bundles/org.openhab.binding.oceanic/src/main/resources/OH-INF/i18n/oceanic.properties @@ -0,0 +1,60 @@ +# binding + +binding.oceanic.name = openHAB Oceanic Binding +binding.oceanic.description = This is the binding for Oceanic Water Softener. + +# thing types + +thing-type.oceanic.network.label = Oceanic Water Softener +thing-type.oceanic.network.description = Oceanic Water Softener connected through a network proxy +thing-type.oceanic.serial.label = Oceanic Water Softener +thing-type.oceanic.serial.description = Oceanic Water Softener connected through a serial port + +# thing types config + +thing-type.config.oceanic.network.interval.label = Polling Interval +thing-type.config.oceanic.network.interval.description = Interval in seconds to poll the Oceanic Water Softener for status updates +thing-type.config.oceanic.network.ipAddress.label = Network Address +thing-type.config.oceanic.network.ipAddress.description = Network address of the network proxy +thing-type.config.oceanic.network.portNumber.label = Port +thing-type.config.oceanic.network.portNumber.description = Port number of the network proxy +thing-type.config.oceanic.serial.interval.label = Polling Interval +thing-type.config.oceanic.serial.interval.description = Interval in seconds to poll the Oceanic Water Softener for status updates +thing-type.config.oceanic.serial.port.label = Serial Port +thing-type.config.oceanic.serial.port.description = Serial Port the Oceanic Water Softener is connected to + +# channel types + +channel-type.oceanic.alarm.label = Alarm +channel-type.oceanic.alarm.description = Current alarm description, if any +channel-type.oceanic.alert.label = Alert +channel-type.oceanic.alert.description = Current alert description, if any, to notify a shortage of salt +channel-type.oceanic.consumption.label = Water Consumption +channel-type.oceanic.consumption.description = Water consumption, in l +channel-type.oceanic.cycle.label = Cycle +channel-type.oceanic.cycle.description = Indicates the stage of the regeneration cycle +channel-type.oceanic.cylinderstate.label = Cylinder State +channel-type.oceanic.cylinderstate.description = Indicates the state of the regeneration cylinder(s) +channel-type.oceanic.flow.label = Flow +channel-type.oceanic.flow.description = Flow in l/min +channel-type.oceanic.hardness.label = Water Hardness +channel-type.oceanic.hardness.description = Water hardness expressed using the chosen hardness unit +channel-type.oceanic.multiregenerate.label = Start Multi-regeneration +channel-type.oceanic.multiregenerate.description = Start a multi-regeneration +channel-type.oceanic.number.label = Regenerations +channel-type.oceanic.number.description = Number of regenerations +channel-type.oceanic.pressure.label = Water Pressure +channel-type.oceanic.pressure.description = Water pressure, in bar +channel-type.oceanic.regeneratelater.label = Regenerate Later +channel-type.oceanic.regeneratelater.description = Start a delayed regeneration +channel-type.oceanic.regeneratenow.label = Regenerate Now +channel-type.oceanic.regeneratenow.description = Start immediate regeneration +channel-type.oceanic.reserve.label = Water Reserve +channel-type.oceanic.reserve.description = Water reserve in l before regeneration has to start +channel-type.oceanic.salt.label = Salt +channel-type.oceanic.salt.description = Volume of salt remaining, in kg +channel-type.oceanic.time.label = Date/Time +channel-type.oceanic.time.description = Date/Time stamp +channel-type.oceanic.time.state.pattern = %1$td.%1$tm.%1$tY %1$tT +channel-type.oceanic.unit.label = Unit +channel-type.oceanic.unit.description = Hardness unit used to express hardness diff --git a/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties new file mode 100644 index 0000000000000..0d13b2e47fd8e --- /dev/null +++ b/bundles/org.openhab.binding.ojelectronics/src/main/resources/OH-INF/i18n/ojelectronics.properties @@ -0,0 +1,55 @@ +# binding + +binding.ojelectronics.name = OJElectronics Binding +binding.ojelectronics.description = This is the binding for OJElectronics. + +# thing types + +thing-type.ojelectronics.ojcloud.label = OJ Electronics Cloud +thing-type.ojelectronics.ojcloud.description = Access to all OJ Electronic devices. +thing-type.ojelectronics.owd5.label = OWD5/MWD5 Thermostat +thing-type.ojelectronics.owd5.description = OWD5/MWD5 Thermostat + +# thing types config + +thing-type.config.ojelectronics.ojcloud.apiKey.label = API Key +thing-type.config.ojelectronics.ojcloud.apiKey.description = API-Key from your local distributor +thing-type.config.ojelectronics.ojcloud.apiUrl.label = API-URL +thing-type.config.ojelectronics.ojcloud.apiUrl.description = URL to cloud API-service. +thing-type.config.ojelectronics.ojcloud.customerId.label = Customer ID +thing-type.config.ojelectronics.ojcloud.customerId.description = Customer ID +thing-type.config.ojelectronics.ojcloud.password.label = Password +thing-type.config.ojelectronics.ojcloud.password.description = Password for access cloud service. +thing-type.config.ojelectronics.ojcloud.refreshDelayInSeconds.label = Refresh Delay +thing-type.config.ojelectronics.ojcloud.refreshDelayInSeconds.description = Refresh delay in seconds. +thing-type.config.ojelectronics.ojcloud.softwareVersion.label = Software Version +thing-type.config.ojelectronics.ojcloud.softwareVersion.description = Software Version +thing-type.config.ojelectronics.ojcloud.userName.label = User Name +thing-type.config.ojelectronics.ojcloud.userName.description = User Name for access cloud service. +thing-type.config.ojelectronics.owd5.serialNumber.label = Serial Number +thing-type.config.ojelectronics.owd5.serialNumber.description = Serial number of the thermostat. You can find the serial number in the app or on the thermostat itself. + +# channel types + +channel-type.ojelectronics.boostEndTime.label = End Time of Boost Mode +channel-type.ojelectronics.comfortEndTime.label = End Time of Comfort Mode +channel-type.ojelectronics.comfortSetpoint.label = Comfort Set Point Temperature +channel-type.ojelectronics.floorTemperature.label = Floor Temperature +channel-type.ojelectronics.groupId.label = Group ID +channel-type.ojelectronics.groupName.label = Group Name +channel-type.ojelectronics.heating.label = Heating +channel-type.ojelectronics.manualSetpoint.label = Manual Set Point Temperature +channel-type.ojelectronics.online.label = Online +channel-type.ojelectronics.regulationMode.label = Regulation Mode +channel-type.ojelectronics.regulationMode.state.option.auto = Auto +channel-type.ojelectronics.regulationMode.state.option.comfort = Comfort +channel-type.ojelectronics.regulationMode.state.option.manual = Manual +channel-type.ojelectronics.regulationMode.state.option.vacation = Vacation +channel-type.ojelectronics.regulationMode.state.option.frostProtection = Frost Protection +channel-type.ojelectronics.regulationMode.state.option.boost = Boost +channel-type.ojelectronics.regulationMode.state.option.eco = Eco +channel-type.ojelectronics.roomTemperature.label = Room Temperature +channel-type.ojelectronics.thermostatName.label = Thermostat Name +channel-type.ojelectronics.vacationBeginDay.label = Vacation Begin Day +channel-type.ojelectronics.vacationEnabled.label = Vacation Mode Enabled +channel-type.ojelectronics.vacationEndDay.label = Vacation End Day diff --git a/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/i18n/omnikinverter.properties b/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/i18n/omnikinverter.properties new file mode 100644 index 0000000000000..1033c3b5a3c0b --- /dev/null +++ b/bundles/org.openhab.binding.omnikinverter/src/main/resources/OH-INF/i18n/omnikinverter.properties @@ -0,0 +1,27 @@ +# binding + +binding.omnikinverter.name = OmnikInverter Binding +binding.omnikinverter.description = This is the binding for the Omnik solar grid inverters. The integration is based on the undocumented API, which is reverse engineered at https://github.com/Woutrrr/Omnik-Data-Logger. As such, the known supported inverters are known to work with inverters with wifi bridge which start with the serial number '602' and '606'. + +# thing types + +thing-type.omnikinverter.omnik.label = OmnikInverter Binding Thing +thing-type.omnikinverter.omnik.description = Thing for OmnikInverter Binding + +# thing types config + +thing-type.config.omnikinverter.omnik.hostname.label = Hostname +thing-type.config.omnikinverter.omnik.hostname.description = The hostname or IP of the Omnik Inverter +thing-type.config.omnikinverter.omnik.port.label = Port +thing-type.config.omnikinverter.omnik.port.description = The TCP port of the Omnik inverter, usually 8899 +thing-type.config.omnikinverter.omnik.serial.label = Serial +thing-type.config.omnikinverter.omnik.serial.description = The serial of the Omnik inverter's Wifi module. This the number part only. + +# channel types + +channel-type.omnikinverter.energyToday.label = Energy Today +channel-type.omnikinverter.energyToday.description = The amount of energy generated today +channel-type.omnikinverter.energyTotal.label = Total Generated Energy +channel-type.omnikinverter.energyTotal.description = The amount of generated energy in total +channel-type.omnikinverter.power.label = Instantaneous Power +channel-type.omnikinverter.power.description = The instantaneous power generation diff --git a/bundles/org.openhab.binding.omnilink/src/main/resources/OH-INF/i18n/omnilink.properties b/bundles/org.openhab.binding.omnilink/src/main/resources/OH-INF/i18n/omnilink.properties new file mode 100644 index 0000000000000..7186ac8a7bb56 --- /dev/null +++ b/bundles/org.openhab.binding.omnilink/src/main/resources/OH-INF/i18n/omnilink.properties @@ -0,0 +1,308 @@ +# binding + +binding.omnilink.name = OmniLink Binding +binding.omnilink.description = This is the binding for OmniLink, a security system that interfaces with many devices. + +# thing types + +thing-type.omnilink.area.label = Omni Area +thing-type.omnilink.area.description = An Omni area configured in the controller. +thing-type.omnilink.audio_source.label = Audio Source +thing-type.omnilink.audio_source.description = An audio source configured in the controller. +thing-type.omnilink.audio_zone.label = Audio Zone +thing-type.omnilink.audio_zone.description = An audio zone configured in the controller. +thing-type.omnilink.button.label = Button +thing-type.omnilink.button.description = A button configured in the controller. +thing-type.omnilink.console.label = Console +thing-type.omnilink.console.description = A console configured in the controller. +thing-type.omnilink.controller.label = OmniLink Controller +thing-type.omnilink.controller.description = An OmniLink controller. +thing-type.omnilink.controller.channel.beep.label = Beep Consoles +thing-type.omnilink.controller.channel.enable_disable_beeper.label = Console Beepers +thing-type.omnilink.dimmable.label = Dimmable Unit +thing-type.omnilink.dimmable.description = A dimmable unit configured in the controller. +thing-type.omnilink.flag.label = Flag +thing-type.omnilink.flag.description = A flag configured in the controller. +thing-type.omnilink.humidity_sensor.label = Humidity Sensor +thing-type.omnilink.humidity_sensor.description = A humidity sensor configured in the controller. +thing-type.omnilink.lock.label = Lock +thing-type.omnilink.lock.description = An access control reader lock configured in the controller. +thing-type.omnilink.lumina_area.label = Lumina Area +thing-type.omnilink.lumina_area.description = An Lumina area configured in the controller. +thing-type.omnilink.output.label = Voltage Output +thing-type.omnilink.output.description = A voltage output configured in the controller. +thing-type.omnilink.room.label = Room +thing-type.omnilink.room.description = A room configured in the controller. +thing-type.omnilink.room.channel.scene_a.label = Scene A +thing-type.omnilink.room.channel.scene_b.label = Scene B +thing-type.omnilink.room.channel.scene_c.label = Scene C +thing-type.omnilink.room.channel.scene_d.label = Scene D +thing-type.omnilink.temp_sensor.label = Temperature Sensor +thing-type.omnilink.temp_sensor.description = A temperature sensor configured in the controller. +thing-type.omnilink.thermostat.label = Thermostat +thing-type.omnilink.thermostat.description = A thermostat configured in the controller. +thing-type.omnilink.unit.label = Unit +thing-type.omnilink.unit.description = A basic unit configured in the controller. +thing-type.omnilink.upb.label = UPB Unit +thing-type.omnilink.upb.description = A UPB unit configured in the controller. +thing-type.omnilink.zone.label = Zone +thing-type.omnilink.zone.description = A zone configured in the controller. + +# thing types config + +thing-type.config.omnilink.area.number.label = Area Number +thing-type.config.omnilink.area.number.description = The area number. +thing-type.config.omnilink.audio_source.autostart.label = Autostart Polling +thing-type.config.omnilink.audio_source.autostart.description = Autostart polling of audio source on creation of thing. +thing-type.config.omnilink.audio_source.number.label = Audio Source Number +thing-type.config.omnilink.audio_source.number.description = The audio source number. +thing-type.config.omnilink.audio_zone.number.label = Audio Zone Number +thing-type.config.omnilink.audio_zone.number.description = The audio zone number. +thing-type.config.omnilink.button.number.label = Button Number +thing-type.config.omnilink.button.number.description = The button number. +thing-type.config.omnilink.console.number.label = Console Number +thing-type.config.omnilink.console.number.description = The console number. +thing-type.config.omnilink.controller.ipAddress.label = IP or Host Name +thing-type.config.omnilink.controller.ipAddress.description = The IP or host name of the controller. +thing-type.config.omnilink.controller.key1.label = Key 1 +thing-type.config.omnilink.controller.key1.description = The first network encription key. +thing-type.config.omnilink.controller.key2.label = Key 2 +thing-type.config.omnilink.controller.key2.description = The second network encription key. +thing-type.config.omnilink.controller.logPollingInterval.label = Log Polling Interval +thing-type.config.omnilink.controller.logPollingInterval.description = The interval to poll for new log messages on the controller. +thing-type.config.omnilink.controller.port.label = Port +thing-type.config.omnilink.controller.port.description = The port of the controller. +thing-type.config.omnilink.dimmable.number.label = Dimmable Unit Number +thing-type.config.omnilink.dimmable.number.description = The dimmable unit number. +thing-type.config.omnilink.flag.number.label = Flag Number +thing-type.config.omnilink.flag.number.description = The flag number. +thing-type.config.omnilink.humidity_sensor.number.label = Humidity Sensor Number +thing-type.config.omnilink.humidity_sensor.number.description = The humidity sensor number. +thing-type.config.omnilink.lock.number.label = Lock Number +thing-type.config.omnilink.lock.number.description = The lock number. +thing-type.config.omnilink.lumina_area.number.label = Area Number +thing-type.config.omnilink.lumina_area.number.description = The area number. +thing-type.config.omnilink.output.number.label = Voltage Output Number +thing-type.config.omnilink.output.number.description = The voltage output number. +thing-type.config.omnilink.room.number.label = Room Number +thing-type.config.omnilink.room.number.description = The room number. +thing-type.config.omnilink.temp_sensor.number.label = Temperature Sensor Number +thing-type.config.omnilink.temp_sensor.number.description = The temperature sensor number. +thing-type.config.omnilink.thermostat.number.label = Thermostat Number +thing-type.config.omnilink.thermostat.number.description = The thermostat number. +thing-type.config.omnilink.unit.number.label = Unit Number +thing-type.config.omnilink.unit.number.description = The unit number. +thing-type.config.omnilink.upb.number.label = UPB Unit Number +thing-type.config.omnilink.upb.number.description = The UPB unit number. +thing-type.config.omnilink.zone.number.label = Zone Number +thing-type.config.omnilink.zone.number.description = The zone number. + +# channel types + +channel-type.omnilink.ac_power_event.label = AC Power Event +channel-type.omnilink.ac_power_event.description = Event sent when AC trouble conditions are detected. +channel-type.omnilink.all_on_off_event.label = All On/Off Event +channel-type.omnilink.all_on_off_event.description = Event sent when an all on/off event occurs. +channel-type.omnilink.area_alarm.label = Area Alarm +channel-type.omnilink.area_alarm.description = Indicates if an alarm is active. +channel-type.omnilink.area_command.label = Security Command +channel-type.omnilink.area_command.description = Sends a 4 digit user code to activate the area command. +channel-type.omnilink.audio_source_polling.label = Audio Source Polling +channel-type.omnilink.audio_source_polling.description = Enable or disable polling of this audio source. +channel-type.omnilink.audio_source_text.label = Source Data +channel-type.omnilink.audio_source_text.description = A line of metadata from this audio source. +channel-type.omnilink.audio_zone_control.label = Control +channel-type.omnilink.audio_zone_control.description = Control the audio zone, e.g. start/stop/next/previous. +channel-type.omnilink.audio_zone_mute.label = Audio Zone Mute +channel-type.omnilink.audio_zone_mute.description = Mute status of this audio zone. +channel-type.omnilink.audio_zone_power.label = Audio Zone Power +channel-type.omnilink.audio_zone_power.description = Power status of this audio zone. +channel-type.omnilink.audio_zone_source.label = Source +channel-type.omnilink.audio_zone_source.description = Source for this audio zone. +channel-type.omnilink.audio_zone_volume.label = Audio Zone Volume +channel-type.omnilink.audio_zone_volume.description = Volume level of this audio zone. +channel-type.omnilink.battery_event.label = Battery Event +channel-type.omnilink.battery_event.description = Event sent when battery trouble conditions are detected. +channel-type.omnilink.button_activated.label = Button Activated +channel-type.omnilink.button_activated.description = Event sent when a button is activated. +channel-type.omnilink.button_press.label = Button Press +channel-type.omnilink.button_press.description = Sends a button event to the controller. +channel-type.omnilink.camera_trigger_event.label = Camera Trigger Event +channel-type.omnilink.camera_trigger_event.description = Event sent when a camera trigger is detected. +channel-type.omnilink.console_beep.label = Beep Console +channel-type.omnilink.console_beep.description = Send a beep command to this/all console(s). +channel-type.omnilink.console_beep.state.option.0 = Off +channel-type.omnilink.console_beep.state.option.1 = Indefinitely +channel-type.omnilink.console_beep.state.option.2 = 1 time +channel-type.omnilink.console_beep.state.option.3 = 2 times +channel-type.omnilink.console_beep.state.option.4 = 3 times +channel-type.omnilink.console_beep.state.option.5 = 4 times +channel-type.omnilink.console_beep.state.option.6 = 5 times +channel-type.omnilink.console_enable_disable_beeper.label = Enable/Disable Console Beeper +channel-type.omnilink.console_enable_disable_beeper.description = Enable/Disable the beeper for this/all console(s). +channel-type.omnilink.console_enable_disable_beeper.command.option.OFF = Off +channel-type.omnilink.console_enable_disable_beeper.command.option.ON = On +channel-type.omnilink.dcm_event.label = DCM Event +channel-type.omnilink.dcm_event.description = Event sent when digital communicator trouble conditions are detected. +channel-type.omnilink.energy_cost_event.label = Energy Cost Event +channel-type.omnilink.energy_cost_event.description = Event sent when the cost of energy changes. +channel-type.omnilink.flag_switch.label = Flag Switch +channel-type.omnilink.flag_switch.description = Turn this flag on/off. +channel-type.omnilink.flag_value.label = Flag Value +channel-type.omnilink.flag_value.description = Numeric value of this flag. +channel-type.omnilink.last_log.label = Last Log Entry +channel-type.omnilink.last_log.description = Last log message on the controller, represented in JSON. +channel-type.omnilink.lock_switch.label = Lock/Unlock +channel-type.omnilink.lock_switch.description = Lock or unlock this lock. +channel-type.omnilink.lumina_area_mode.label = Security Mode +channel-type.omnilink.lumina_area_mode.description = Represents the area security mode. +channel-type.omnilink.lumina_area_mode.state.option.1 = Home +channel-type.omnilink.lumina_area_mode.state.option.2 = Sleep +channel-type.omnilink.lumina_area_mode.state.option.3 = Away +channel-type.omnilink.lumina_area_mode.state.option.4 = Vacation +channel-type.omnilink.lumina_area_mode.state.option.5 = Party +channel-type.omnilink.lumina_area_mode.state.option.6 = Special +channel-type.omnilink.lumina_area_mode.state.option.9 = Setting home +channel-type.omnilink.lumina_area_mode.state.option.10 = Setting sleep +channel-type.omnilink.lumina_area_mode.state.option.11 = Setting away +channel-type.omnilink.lumina_area_mode.state.option.12 = Setting vacation +channel-type.omnilink.lumina_area_mode.state.option.13 = Setting party +channel-type.omnilink.lumina_area_mode.state.option.14 = Setting special +channel-type.omnilink.off_for_hours.label = Off for Hours +channel-type.omnilink.off_for_hours.description = Turn off this unit for a specified number of hours. +channel-type.omnilink.off_for_minutes.label = Off for Minutes +channel-type.omnilink.off_for_minutes.description = Turn off this unit for a specified number of minutes. +channel-type.omnilink.off_for_seconds.label = Off for Seconds +channel-type.omnilink.off_for_seconds.description = Turn off this unit for a specified number of seconds. +channel-type.omnilink.omni_activate_keypad_emergency.label = Activate Keypad Emergency +channel-type.omnilink.omni_activate_keypad_emergency.description = Activate a burglary, fire, or auxiliary keypad emergency alarm on Omni based models. +channel-type.omnilink.omni_activate_keypad_emergency.state.option.1 = Burglary +channel-type.omnilink.omni_activate_keypad_emergency.state.option.2 = Fire +channel-type.omnilink.omni_activate_keypad_emergency.state.option.3 = Auxiliary +channel-type.omnilink.omni_area_mode.label = Security Mode +channel-type.omnilink.omni_area_mode.description = Represents the area security mode. +channel-type.omnilink.omni_area_mode.state.option.0 = Off +channel-type.omnilink.omni_area_mode.state.option.1 = Day +channel-type.omnilink.omni_area_mode.state.option.2 = Night +channel-type.omnilink.omni_area_mode.state.option.3 = Away +channel-type.omnilink.omni_area_mode.state.option.4 = Vacation +channel-type.omnilink.omni_area_mode.state.option.5 = Day instant +channel-type.omnilink.omni_area_mode.state.option.6 = Night delayed +channel-type.omnilink.omni_area_mode.state.option.9 = Arming day +channel-type.omnilink.omni_area_mode.state.option.10 = Arming night +channel-type.omnilink.omni_area_mode.state.option.11 = Arming away +channel-type.omnilink.omni_area_mode.state.option.12 = Arming vacation +channel-type.omnilink.omni_area_mode.state.option.13 = Arming day instant +channel-type.omnilink.omni_area_mode.state.option.14 = Arming night delayed +channel-type.omnilink.on_for_hours.label = On for Hours +channel-type.omnilink.on_for_hours.description = Turn on this unit for a specified number of hours. +channel-type.omnilink.on_for_minutes.label = On for Minutes +channel-type.omnilink.on_for_minutes.description = Turn on this unit for a specified number of minutes. +channel-type.omnilink.on_for_seconds.label = On for Seconds +channel-type.omnilink.on_for_seconds.description = Turn on this unit for a specified number of seconds. +channel-type.omnilink.phone_line_event.label = Phone Line Event +channel-type.omnilink.phone_line_event.description = Event sent when the phone line changes state. +channel-type.omnilink.room_state.label = State +channel-type.omnilink.room_state.description = The current state of this room. +channel-type.omnilink.room_state.state.option.0 = Off +channel-type.omnilink.room_state.state.option.1 = On +channel-type.omnilink.room_state.state.option.2 = Scene A +channel-type.omnilink.room_state.state.option.3 = Scene B +channel-type.omnilink.room_state.state.option.4 = Scene C +channel-type.omnilink.room_state.state.option.5 = Scene D +channel-type.omnilink.room_switch.label = Switch +channel-type.omnilink.room_switch.description = Turn this room on/off. +channel-type.omnilink.scene_toggle.label = Scene Toggle +channel-type.omnilink.scene_toggle.description = Turn this scene on/off. +channel-type.omnilink.sensor_humidity.label = Humidity +channel-type.omnilink.sensor_humidity.description = The current relative humidity at this humidity sensor. +channel-type.omnilink.sensor_humidity_high_setpoint.label = High SetPoint +channel-type.omnilink.sensor_humidity_high_setpoint.description = The current high setpoint for this humidity sensor. +channel-type.omnilink.sensor_humidity_low_setpoint.label = Low SetPoint +channel-type.omnilink.sensor_humidity_low_setpoint.description = The current low setpoint for this humidity sensor. +channel-type.omnilink.sensor_temp_high_setpoint.label = High SetPoint +channel-type.omnilink.sensor_temp_high_setpoint.description = The current high setpoint of this temperature sensor. +channel-type.omnilink.sensor_temp_low_setpoint.label = Low SetPoint +channel-type.omnilink.sensor_temp_low_setpoint.description = The current low setpoint of this temperature sensor. +channel-type.omnilink.sensor_temperature.label = Temperature +channel-type.omnilink.sensor_temperature.description = The current temperature at this temperature sensor. +channel-type.omnilink.switch_press_event.label = Switch Press Event +channel-type.omnilink.switch_press_event.description = Event sent when an ALC, UPB, Radio RA, or Starlite switch is pressed. +channel-type.omnilink.sysDate.label = Date/Time +channel-type.omnilink.sysDate.description = Set controller date/time. +channel-type.omnilink.sysDate.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.omnilink.thermostat_comm_failure.label = Thermostat Communications Failure +channel-type.omnilink.thermostat_comm_failure.description = Closed during a communications failure with this thermostat. +channel-type.omnilink.thermostat_cool_setpoint.label = Cool SetPoint +channel-type.omnilink.thermostat_cool_setpoint.description = The current high/cooling setpoint of this thermostat. +channel-type.omnilink.thermostat_dehumidify_setpoint.label = Dehumidify SetPoint +channel-type.omnilink.thermostat_dehumidify_setpoint.description = The current high/dehumidify setpoint for this thermostat. +channel-type.omnilink.thermostat_fan_mode.label = Fan Mode +channel-type.omnilink.thermostat_fan_mode.description = The current fan mode of this thermostat. +channel-type.omnilink.thermostat_fan_mode.state.option.0 = Auto +channel-type.omnilink.thermostat_fan_mode.state.option.1 = On +channel-type.omnilink.thermostat_fan_mode.state.option.2 = Cycle +channel-type.omnilink.thermostat_freeze_alarm.label = Thermostat Freeze Alarm +channel-type.omnilink.thermostat_freeze_alarm.description = Closed when freeze alarm is triggered by this thermostat. +channel-type.omnilink.thermostat_heat_setpoint.label = Heat SetPoint +channel-type.omnilink.thermostat_heat_setpoint.description = The current low/heating setpoint of this thermostat. +channel-type.omnilink.thermostat_hold_status.label = Hold Status +channel-type.omnilink.thermostat_hold_status.description = The current hold status of this thermostat. +channel-type.omnilink.thermostat_hold_status.state.option.0 = Off +channel-type.omnilink.thermostat_hold_status.state.option.1 = Hold +channel-type.omnilink.thermostat_hold_status.state.option.2 = Vacation hold +channel-type.omnilink.thermostat_humidify_setpoint.label = Humidify SetPoint +channel-type.omnilink.thermostat_humidify_setpoint.description = The current low/humidify setpoint for this thermostat. +channel-type.omnilink.thermostat_humidity.label = Humidity +channel-type.omnilink.thermostat_humidity.description = The relative humidity at this thermostat. +channel-type.omnilink.thermostat_outdoor_temperature.label = Outdoor Temperature +channel-type.omnilink.thermostat_outdoor_temperature.description = The current outdoor temperature detected by this thermostat. +channel-type.omnilink.thermostat_status.label = Thermostat Status +channel-type.omnilink.thermostat_status.description = The current status of this thermostat. +channel-type.omnilink.thermostat_status.state.option.0 = Idle +channel-type.omnilink.thermostat_status.state.option.1 = Heating +channel-type.omnilink.thermostat_status.state.option.2 = Cooling +channel-type.omnilink.thermostat_status.state.option.3 = Humidifying +channel-type.omnilink.thermostat_status.state.option.4 = Dehumidifying +channel-type.omnilink.thermostat_system_mode.label = System Mode +channel-type.omnilink.thermostat_system_mode.description = The current system mode of this thermostat. +channel-type.omnilink.thermostat_system_mode.state.option.0 = Off +channel-type.omnilink.thermostat_system_mode.state.option.1 = Heat +channel-type.omnilink.thermostat_system_mode.state.option.2 = Cool +channel-type.omnilink.thermostat_system_mode.state.option.3 = Auto +channel-type.omnilink.thermostat_system_mode.state.option.4 = Emergency heat +channel-type.omnilink.thermostat_temperature.label = Temperature +channel-type.omnilink.thermostat_temperature.description = The current temperature at this thermostat. +channel-type.omnilink.unit_level.label = Unit Level +channel-type.omnilink.unit_level.description = Increase/Decrease the level of this unit. +channel-type.omnilink.unit_switch.label = Switch +channel-type.omnilink.unit_switch.description = Turn this unit on/off. +channel-type.omnilink.upb_link_activated_event.label = UPB Link +channel-type.omnilink.upb_link_activated_event.description = Event sent when a UPB link is activated. +channel-type.omnilink.upb_link_deactivated_event.label = UPB Link +channel-type.omnilink.upb_link_deactivated_event.description = Event sent when a UPB link is deactivated. +channel-type.omnilink.upb_status.label = UPB Status +channel-type.omnilink.upb_status.description = Send a UPB status request message for this unit to the controller. +channel-type.omnilink.upb_status.command.option.GET STATUS = Get Status +channel-type.omnilink.zone_arming_status.label = Arming Status +channel-type.omnilink.zone_arming_status.description = Arming status of this zone. +channel-type.omnilink.zone_arming_status.state.option.0 = Disarmed +channel-type.omnilink.zone_arming_status.state.option.1 = Armed +channel-type.omnilink.zone_arming_status.state.option.2 = Bypassed by user +channel-type.omnilink.zone_arming_status.state.option.3 = Bypassed by system +channel-type.omnilink.zone_bypass.label = Bypass Zone +channel-type.omnilink.zone_bypass.description = Send a 4 digit user code to bypass this zone. +channel-type.omnilink.zone_contact.label = Contact State +channel-type.omnilink.zone_contact.description = Contact state information of this zone. +channel-type.omnilink.zone_current_condition.label = Current Condition +channel-type.omnilink.zone_current_condition.description = Current condition of this zone. +channel-type.omnilink.zone_current_condition.state.option.0 = Secure +channel-type.omnilink.zone_current_condition.state.option.1 = Not Ready +channel-type.omnilink.zone_current_condition.state.option.2 = Trouble +channel-type.omnilink.zone_latched_alarm_status.label = Latched Alarm Status +channel-type.omnilink.zone_latched_alarm_status.description = Latched alarm status of this zone. +channel-type.omnilink.zone_latched_alarm_status.state.option.0 = Secure +channel-type.omnilink.zone_latched_alarm_status.state.option.1 = Tripped +channel-type.omnilink.zone_latched_alarm_status.state.option.2 = Reset, but previously tripped +channel-type.omnilink.zone_restore.label = Restore Zone +channel-type.omnilink.zone_restore.description = Send a 4 digit user code to restore this zone. diff --git a/bundles/org.openhab.binding.onebusaway/src/main/resources/OH-INF/i18n/onebusaway.properties b/bundles/org.openhab.binding.onebusaway/src/main/resources/OH-INF/i18n/onebusaway.properties new file mode 100644 index 0000000000000..92c5d95a56144 --- /dev/null +++ b/bundles/org.openhab.binding.onebusaway/src/main/resources/OH-INF/i18n/onebusaway.properties @@ -0,0 +1,45 @@ +# binding + +binding.onebusaway.name = OneBusAway Binding +binding.onebusaway.description = This is the binding for OneBusAway, an open system to provide transit data. + +# thing types + +thing-type.onebusaway.api.label = OneBusAway Service +thing-type.onebusaway.api.description = The Service settings to talk to a OneBusAway deployment. +thing-type.onebusaway.route.label = Route +thing-type.onebusaway.route.description = Provides data about a route at a specific stop. +thing-type.onebusaway.stop.label = Stop +thing-type.onebusaway.stop.description = Provides data about different routes at a specific stop. + +# thing types config + +thing-type.config.onebusaway.api.apiKey.label = API Key +thing-type.config.onebusaway.api.apiKey.description = The OneBusAway API key to use. +thing-type.config.onebusaway.api.apiServer.label = API Server +thing-type.config.onebusaway.api.apiServer.description = The OneBusAway API Server to use. +thing-type.config.onebusaway.config.routeId.label = Route ID +thing-type.config.onebusaway.config.routeId.description = The OneBusAway route ID. +thing-type.config.onebusaway.stop.interval.label = Interval +thing-type.config.onebusaway.stop.interval.description = Refresh interval for arrival data in seconds. +thing-type.config.onebusaway.stop.stopId.label = Stop ID +thing-type.config.onebusaway.stop.stopId.description = The OneBusAway stop ID. + +# channel types + +channel-type.onebusaway.arrival.label = Arrival Time +channel-type.onebusaway.arrival.description = The arrival time +channel-type.onebusaway.arrival.state.pattern = %1$tF %1$tR +channel-type.onebusaway.departure.label = Departure Time +channel-type.onebusaway.departure.description = The departure time +channel-type.onebusaway.departure.state.pattern = %1$tF %1$tR +channel-type.onebusaway.routeEvent.label = Route Event +channel-type.onebusaway.routeEvent.description = Route event +channel-type.onebusaway.update.label = Last Update Time +channel-type.onebusaway.update.description = The last time information was updated +channel-type.onebusaway.update.state.pattern = %1$tF %1$tR + +# channel types config + +channel-type.config.onebusaway.config.offset.label = Offset +channel-type.config.onebusaway.config.offset.description = Moves an event or datetime value backward (in seconds) diff --git a/bundles/org.openhab.binding.onewire/src/main/resources/OH-INF/i18n/onewire.properties b/bundles/org.openhab.binding.onewire/src/main/resources/OH-INF/i18n/onewire.properties new file mode 100644 index 0000000000000..320980f61b7c8 --- /dev/null +++ b/bundles/org.openhab.binding.onewire/src/main/resources/OH-INF/i18n/onewire.properties @@ -0,0 +1,185 @@ +# binding + +binding.onewire.name = OneWire Binding +binding.onewire.description = This is the binding for OneWire. + +# thing types + +thing-type.onewire.ams.label = Multisensor AMS +thing-type.onewire.ams.description = 1-wire multisensor (DS2438-based) +thing-type.onewire.bae091x.label = Multisensor BAE0910 +thing-type.onewire.bae091x.description = 1-wire multisensor (BAE0910-based) +thing-type.onewire.basic.label = Basic 1 Wire Sensor +thing-type.onewire.bms.label = Multisensor BMS +thing-type.onewire.bms.description = 1-wire multisensor (DS2438-based) +thing-type.onewire.edsenv.label = Multisensor EDS +thing-type.onewire.edsenv.description = A 1-wire multisensor (EDS00xx-based) +thing-type.onewire.ms-tx.label = Multisensor (T, TC, TH, TL, TV, Generic) +thing-type.onewire.ms-tx.description = A 1-wire multisensor (DS1923/DS2438-based) +thing-type.onewire.owserver.label = OW Server +thing-type.onewire.owserver.description = An owserver instance + +# thing types config + +thing-type.config.onewire.ams.id.label = TH(S) Sensor ID +thing-type.config.onewire.ams.id.description = Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches +thing-type.config.onewire.ams.refresh.label = Refresh Time for Analog Channels +thing-type.config.onewire.ams.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.ams.refreshdigital.label = Refresh Time for Digital Channels +thing-type.config.onewire.ams.refreshdigital.description = Time in seconds after which the digital I/Os are refreshed +thing-type.config.onewire.ams.temperaturesensor.label = Temperature Sensor +thing-type.config.onewire.ams.temperaturesensor.option.DS2438 = internal (DS2438) +thing-type.config.onewire.ams.temperaturesensor.option.DS18B20 = external (DS18B20) +thing-type.config.onewire.bae091x.id.label = Sensor ID +thing-type.config.onewire.bae091x.id.description = Sensor ID in format: xx.xxxxxxxxxxxx) +thing-type.config.onewire.bae091x.pin1.label = Pin 1 Mode Configuration +thing-type.config.onewire.bae091x.pin1.option.disabled = disabled +thing-type.config.onewire.bae091x.pin1.option.counter = Counter +thing-type.config.onewire.bae091x.pin2.label = Pin 2 Mode Configuration +thing-type.config.onewire.bae091x.pin2.option.disabled = disabled +thing-type.config.onewire.bae091x.pin2.option.output = Digital Output +thing-type.config.onewire.bae091x.pin2.option.pwm = Software PWM 4 +thing-type.config.onewire.bae091x.pin6.label = Pin 6 Mode Configuration +thing-type.config.onewire.bae091x.pin6.option.disabled = disabled +thing-type.config.onewire.bae091x.pin6.option.pio = PIO +thing-type.config.onewire.bae091x.pin6.option.pwm = Software PWM 3 +thing-type.config.onewire.bae091x.pin7.label = Pin 7 Mode Configuration +thing-type.config.onewire.bae091x.pin7.option.disabled = disabled +thing-type.config.onewire.bae091x.pin7.option.analog = Analog Input +thing-type.config.onewire.bae091x.pin7.option.output = Digital Output +thing-type.config.onewire.bae091x.pin7.option.pwm = Hardware PWM 2 +thing-type.config.onewire.bae091x.pin8.label = Pin 8 Mode Configuration +thing-type.config.onewire.bae091x.pin8.option.disabled = disabled +thing-type.config.onewire.bae091x.pin8.option.input = Digital Input +thing-type.config.onewire.bae091x.pin8.option.output = Digital Output +thing-type.config.onewire.bae091x.pin8.option.pwm = Hardware PWM 1 +thing-type.config.onewire.bae091x.refresh.label = Refresh Time +thing-type.config.onewire.bae091x.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.basethingconfig.id.label = Sensor ID +thing-type.config.onewire.basethingconfig.id.description = Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches +thing-type.config.onewire.basethingconfig.refresh.label = Refresh Time +thing-type.config.onewire.basethingconfig.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.bms.id.label = TH(S) Sensor ID +thing-type.config.onewire.bms.id.description = Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches +thing-type.config.onewire.bms.refresh.label = Refresh Time +thing-type.config.onewire.bms.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.bms.temperaturesensor.label = Temperature Sensor +thing-type.config.onewire.bms.temperaturesensor.option.DS2438 = internal (DS2438) +thing-type.config.onewire.bms.temperaturesensor.option.DS18B20 = external (DS18B20) +thing-type.config.onewire.edsenv.id.label = Sensor ID +thing-type.config.onewire.edsenv.id.description = Sensor ID in format: xx.xxxxxxxxxxxx) +thing-type.config.onewire.edsenv.refresh.label = Refresh Time +thing-type.config.onewire.edsenv.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.mstxconfig.id.label = Sensor ID +thing-type.config.onewire.mstxconfig.id.description = Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches +thing-type.config.onewire.mstxconfig.manualsensor.label = Manual Sensor Type +thing-type.config.onewire.mstxconfig.manualsensor.description = Overrides detected sensor type +thing-type.config.onewire.mstxconfig.manualsensor.option.DS2438 = Generic +thing-type.config.onewire.mstxconfig.manualsensor.option.MS_TH = MS-TH +thing-type.config.onewire.mstxconfig.manualsensor.option.MS_TV = MS-TV +thing-type.config.onewire.mstxconfig.manualsensor.option.MS_TL = MS-TL +thing-type.config.onewire.mstxconfig.manualsensor.option.MS_TC = MS-TC +thing-type.config.onewire.mstxconfig.refresh.label = Refresh Time +thing-type.config.onewire.mstxconfig.refresh.description = Time in seconds after which the thing is refreshed +thing-type.config.onewire.owserver.network-address.label = Network Address +thing-type.config.onewire.owserver.network-address.description = Network address of the host running the owserver +thing-type.config.onewire.owserver.port.label = Port +thing-type.config.onewire.owserver.port.description = Listening port of the owserver + +# channel types + +channel-type.onewire.abshumidity.label = Abs. Humidity +channel-type.onewire.abshumidity.description = absolute humidity (calculated from temperature and relative humidity) +channel-type.onewire.bae-analog.label = Analog Input +channel-type.onewire.bae-analog.description = Analog input (ADC) +channel-type.onewire.bae-counter.label = Counter +channel-type.onewire.bae-di.label = Digital In +channel-type.onewire.bae-do.label = Digital Out +channel-type.onewire.bae-pio.label = PIO +channel-type.onewire.bae-pio.description = Programmable I/O channel +channel-type.onewire.bae-pwm-duty.label = Duty Cycle +channel-type.onewire.bae-pwm-duty.description = Duty cycle of PWM output in % +channel-type.onewire.bae-pwm-frequency.label = Frequency +channel-type.onewire.bae-pwm-frequency.description = Frequency of PWM output in Hz +channel-type.onewire.counter.label = Counter +channel-type.onewire.counter.description = A single counter (reset on power loss) +channel-type.onewire.current.label = Current +channel-type.onewire.current.description = The current measured by the sensor +channel-type.onewire.dewpoint.label = Dewpoint +channel-type.onewire.dewpoint.description = dewpoint (calculated from temperature and relative humidity) +channel-type.onewire.dio.label = Digital I/O +channel-type.onewire.humidity.label = Humidity +channel-type.onewire.humidity.description = relative humidity (0-100%) +channel-type.onewire.humidityconf.label = Humidity +channel-type.onewire.humidityconf.description = relative humidity (0-100%) +channel-type.onewire.light.label = Illuminance +channel-type.onewire.light.description = Ambient light +channel-type.onewire.owfs-number.label = Direct Access to OWFS-Path (Number) +channel-type.onewire.owfs-number.description = Allows direct access to the OWFS +channel-type.onewire.owfs-string.label = Direct Access to OWFS-Path (String) +channel-type.onewire.owfs-string.description = Allows direct access to the OWFS +channel-type.onewire.present.label = Present +channel-type.onewire.present.description = ON if device present on OneWire bus +channel-type.onewire.pressure.label = Pressure +channel-type.onewire.pressure.description = The pressure measured by the sensor +channel-type.onewire.supplyvoltage.label = Supply Voltage +channel-type.onewire.supplyvoltage.description = The sensor's supply voltage +channel-type.onewire.temperature-por-res.label = Temperature +channel-type.onewire.temperature-por-res.description = temperature value of this sensor +channel-type.onewire.temperature-por.label = Temperature +channel-type.onewire.temperature-por.description = temperature value of this sensor +channel-type.onewire.temperature.label = Temperature +channel-type.onewire.temperature.description = temperature value of this sensor +channel-type.onewire.voltage.label = Voltage +channel-type.onewire.voltage.description = The voltage measured by the sensor + +# channel types config + +channel-type.config.onewire.bae-analog.hires.label = Hires +channel-type.config.onewire.bae-analog.hires.description = High resolution Mode (10bit) +channel-type.config.onewire.bae-pio.mode.label = Mode +channel-type.config.onewire.bae-pio.mode.option.input = Input +channel-type.config.onewire.bae-pio.mode.option.output = Output +channel-type.config.onewire.bae-pio.pulldevice.label = Pull-Up/Pull-Down Resistor +channel-type.config.onewire.bae-pio.pulldevice.option.disabled = disabled +channel-type.config.onewire.bae-pio.pulldevice.option.pullup = Pull-Up +channel-type.config.onewire.bae-pio.pulldevice.option.pulldown = Pull-Down +channel-type.config.onewire.bae-pwm-frequency.prescaler.label = Range +channel-type.config.onewire.bae-pwm-frequency.prescaler.description = defines the frequency range of PWM output +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.0 = 245 Hz - 8 MHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.1 = 123 Hz - 4 MHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.2 = 62 Hz - 2 MHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.3 = 31 Hz - 1 MHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.4 = 16 Hz - 500 kHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.5 = 8 Hz - 250 kHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.6 = 4 Hz - 125 kHz +channel-type.config.onewire.bae-pwm-frequency.prescaler.option.7 = 2 Hz - 62.5 kHz +channel-type.config.onewire.bae-pwm-frequency.reversePolarity.label = Reverse Polarity +channel-type.config.onewire.dio.logic.label = Channel Logic +channel-type.config.onewire.dio.logic.option.normal = normal +channel-type.config.onewire.dio.logic.option.inverted = inverted +channel-type.config.onewire.dio.mode.label = Mode +channel-type.config.onewire.dio.mode.option.input = Input +channel-type.config.onewire.dio.mode.option.output = Output +channel-type.config.onewire.humidityconf.humiditytype.label = Humidity Sensor-Type +channel-type.config.onewire.humidityconf.humiditytype.option./humidity = HIH-3610 +channel-type.config.onewire.humidityconf.humiditytype.option./HIH4000/humidity = HIH-4000 +channel-type.config.onewire.humidityconf.humiditytype.option./HTM1735/humidity = HTM-1735 +channel-type.config.onewire.humidityconf.humiditytype.option./DATANAB/humidity = Datanab +channel-type.config.onewire.owfs-number.path.label = OWFS Path +channel-type.config.onewire.owfs-number.path.description = full path to the OWFS-node (e.g. statistics/errors/CRC8_errors) +channel-type.config.onewire.owfs-number.refresh.label = Refresh Time +channel-type.config.onewire.owfs-number.refresh.description = Time in seconds after which the channel is refreshed +channel-type.config.onewire.owfs-string.path.label = OWFS Path +channel-type.config.onewire.owfs-string.path.description = full path to the OWFS-node (e.g. statistics/errors/CRC8_errors) +channel-type.config.onewire.owfs-string.refresh.label = Refresh Time +channel-type.config.onewire.owfs-string.refresh.description = Time in seconds after which the channel is refreshed +channel-type.config.onewire.temperature-por-res.ignorepor.label = Ignore POR-value +channel-type.config.onewire.temperature-por-res.ignorepor.description = filters all 85°C readings (POR-value), may suppress valid readings if enabled +channel-type.config.onewire.temperature-por-res.resolution.label = Sensor Resolution +channel-type.config.onewire.temperature-por-res.resolution.option.9 = 9 bit +channel-type.config.onewire.temperature-por-res.resolution.option.10 = 10 bit +channel-type.config.onewire.temperature-por-res.resolution.option.11 = 11 bit +channel-type.config.onewire.temperature-por-res.resolution.option.12 = 12 bit +channel-type.config.onewire.temperature-por.ignorepor.label = Ignore POR-value +channel-type.config.onewire.temperature-por.ignorepor.description = filters all 85°C readings (POR-value), may suppress valid readings if enabled diff --git a/bundles/org.openhab.binding.onewiregpio/src/main/resources/OH-INF/i18n/onewiregpio.properties b/bundles/org.openhab.binding.onewiregpio/src/main/resources/OH-INF/i18n/onewiregpio.properties new file mode 100644 index 0000000000000..71d7a0ba5abb6 --- /dev/null +++ b/bundles/org.openhab.binding.onewiregpio/src/main/resources/OH-INF/i18n/onewiregpio.properties @@ -0,0 +1,23 @@ +# binding + +binding.onewiregpio.name = OneWireGPIO Binding +binding.onewiregpio.description = Use GPIO in various devices like RaspberryPi to communicate the OneWire protocol + +# thing types + +thing-type.onewiregpio.sensor.label = Temperature Sensor +thing-type.onewiregpio.sensor.description = OneWire GPIO Temperature sensor + +# thing types config + +thing-type.config.onewiregpio.sensor.gpio_bus_file.label = Device Path +thing-type.config.onewiregpio.sensor.gpio_bus_file.description = device id in format: /sys/bus/w1/devices/DEVICE_ID_TO_SET/w1_slave +thing-type.config.onewiregpio.sensor.precision.label = Sensor Precision +thing-type.config.onewiregpio.sensor.precision.description = Sensor precision after floating point. +thing-type.config.onewiregpio.sensor.refresh_time.label = Refresh Time Interval +thing-type.config.onewiregpio.sensor.refresh_time.description = Refresh time interval in seconds. + +# channel types + +channel-type.onewiregpio.temperature.label = Temperature +channel-type.onewiregpio.temperature.description = Indicates the temperature read from one wire gpio sensor diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/OH-INF/i18n/onkyo.properties b/bundles/org.openhab.binding.onkyo/src/main/resources/OH-INF/i18n/onkyo.properties new file mode 100644 index 0000000000000..208a6f92669b9 --- /dev/null +++ b/bundles/org.openhab.binding.onkyo/src/main/resources/OH-INF/i18n/onkyo.properties @@ -0,0 +1,230 @@ +# binding + +binding.onkyo.name = Onkyo Binding +binding.onkyo.description = This is the binding for Onkyo receivers. + +# binding config + +binding.config.onkyo.callbackUrl.label = Callback URL +binding.config.onkyo.callbackUrl.description = url to use for playing notification sounds, e.g. http://192.168.0.2:8080 + +# thing types + +thing-type.onkyo.HT-RC560.label = Onkyo HT-RC560 AV Receiver +thing-type.onkyo.HT-RC560.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR3007.label = Onkyo TX-NR3007 AV Receiver +thing-type.onkyo.TX-NR3007.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR414.label = Onkyo TX-NR414 AV Receiver +thing-type.onkyo.TX-NR414.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR474.label = Onkyo TX-NR474 AV Receiver +thing-type.onkyo.TX-NR474.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR509.label = Onkyo TX-NR509 AV Receiver +thing-type.onkyo.TX-NR509.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR515.label = Onkyo TX-NR515 AV Receiver +thing-type.onkyo.TX-NR515.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR525.label = Onkyo TX-NR525 AV Receiver +thing-type.onkyo.TX-NR525.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR535.label = Onkyo TX-NR535 AV Receiver +thing-type.onkyo.TX-NR535.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR545.label = Onkyo TX-NR545 AV Receiver +thing-type.onkyo.TX-NR545.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR555.label = Onkyo TX-NR555 AV Receiver +thing-type.onkyo.TX-NR555.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR575.label = Onkyo TX-NR575 AV Receiver +thing-type.onkyo.TX-NR575.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR575E.label = Onkyo TX-NR575E AV Receiver +thing-type.onkyo.TX-NR575E.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR616.label = Onkyo TX-NR616 AV Receiver +thing-type.onkyo.TX-NR616.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR626.label = Onkyo TX-NR626 AV Receiver +thing-type.onkyo.TX-NR626.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR636.label = Onkyo TX-NR636 AV Receiver +thing-type.onkyo.TX-NR636.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR646.label = Onkyo TX-NR646 AV Receiver +thing-type.onkyo.TX-NR646.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR656.label = Onkyo TX-NR656 AV Receiver +thing-type.onkyo.TX-NR656.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR676.label = Onkyo TX-NR676 AV Receiver +thing-type.onkyo.TX-NR676.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR686.label = Onkyo TX-NR686 AV Receiver +thing-type.onkyo.TX-NR686.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR708.label = Onkyo TX-NR708 AV Receiver +thing-type.onkyo.TX-NR708.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR717.label = Onkyo TX-NR717 AV Receiver +thing-type.onkyo.TX-NR717.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR727.label = Onkyo TX-NR727 AV Receiver +thing-type.onkyo.TX-NR727.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR737.label = Onkyo TX-NR737 AV Receiver +thing-type.onkyo.TX-NR737.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR747.label = Onkyo TX-NR747 AV Receiver +thing-type.onkyo.TX-NR747.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR809.label = Onkyo TX-NR809 AV Receiver +thing-type.onkyo.TX-NR809.description = Network enabled Onkyo AV Receivers +thing-type.onkyo.TX-NR818.label = Onkyo TX-NR818 AV Receiver +thing-type.onkyo.TX-NR818.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR828.label = Onkyo TX-NR828 AV Receiver +thing-type.onkyo.TX-NR828.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-NR838.label = Onkyo TX-NR838 AV Receiver +thing-type.onkyo.TX-NR838.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.TX-RZ900.label = Onkyo TX-RZ900 AV Receiver +thing-type.onkyo.TX-RZ900.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.onkyoAVR.label = Onkyo AV Receiver +thing-type.onkyo.onkyoAVR.description = Network enabled Onkyo AV Receiver +thing-type.onkyo.onkyoUnsupported.label = Unsupported Onkyo AV Receiver +thing-type.onkyo.onkyoUnsupported.description = Network enabled Onkyo AV Receivers for models that are not officially supported. You may experience some odd behaviors. + +# thing types config + +thing-type.config.onkyo.config.ipAddress.label = Network Address +thing-type.config.onkyo.config.ipAddress.description = The IP or host name of the Onkyo Receiver +thing-type.config.onkyo.config.port.label = Port +thing-type.config.onkyo.config.port.description = Port of the Onkyo to control +thing-type.config.onkyo.config.refreshInterval.label = Refresh Interval +thing-type.config.onkyo.config.refreshInterval.description = The refresh interval in seconds for polling the receiver (0=disable). Binding receive automatically updates from +thing-type.config.onkyo.config.udn.label = Unique Device Name +thing-type.config.onkyo.config.udn.description = The UDN identifies the Onkyo AVR. +thing-type.config.onkyo.config.volumeLimit.label = Volume Limit +thing-type.config.onkyo.config.volumeLimit.description = Limit maximum volume level to defined percentage. +thing-type.config.onkyo.config.volumeScale.label = Volume Scale +thing-type.config.onkyo.config.volumeScale.description = Applies a scale to the volume. +thing-type.config.onkyo.config.volumeScale.option.1 = 0-100 +thing-type.config.onkyo.config.volumeScale.option.2 = 0-100 in 0.5 steps +thing-type.config.onkyo.config.volumeScale.option.0.8 = 0-80 +thing-type.config.onkyo.config.volumeScale.option.0.5 = 0-50 + +# channel group types + +channel-group-type.onkyo.netMenuControls.label = Net/USB Menu +channel-group-type.onkyo.netMenuControls.channel.item0.label = Menu Item 0 +channel-group-type.onkyo.netMenuControls.channel.item0.description = Net/USB menu item at position 0 +channel-group-type.onkyo.netMenuControls.channel.item1.label = Menu Item 1 +channel-group-type.onkyo.netMenuControls.channel.item1.description = Net/USB menu item at position 1 +channel-group-type.onkyo.netMenuControls.channel.item2.label = Menu Item 2 +channel-group-type.onkyo.netMenuControls.channel.item2.description = Net/USB menu item at position 2 +channel-group-type.onkyo.netMenuControls.channel.item3.label = Menu Item 3 +channel-group-type.onkyo.netMenuControls.channel.item3.description = Net/USB menu item at position 3 +channel-group-type.onkyo.netMenuControls.channel.item4.label = Menu Item 4 +channel-group-type.onkyo.netMenuControls.channel.item4.description = Net/USB menu item at position 4 +channel-group-type.onkyo.netMenuControls.channel.item5.label = Menu Item 5 +channel-group-type.onkyo.netMenuControls.channel.item5.description = Net/USB menu item at position 5 +channel-group-type.onkyo.netMenuControls.channel.item6.label = Menu Item 6 +channel-group-type.onkyo.netMenuControls.channel.item6.description = Net/USB menu item at position 6 +channel-group-type.onkyo.netMenuControls.channel.item7.label = Menu Item 7 +channel-group-type.onkyo.netMenuControls.channel.item7.description = Net/USB menu item at position 7 +channel-group-type.onkyo.netMenuControls.channel.item8.label = Menu Item 8 +channel-group-type.onkyo.netMenuControls.channel.item8.description = Net/USB menu item at position 8 +channel-group-type.onkyo.netMenuControls.channel.item9.label = Menu Item 9 +channel-group-type.onkyo.netMenuControls.channel.item9.description = Net/USB menu item at position 9 +channel-group-type.onkyo.playerControls.label = Player +channel-group-type.onkyo.zone1Controls.label = Zone 1 (Main Zone) +channel-group-type.onkyo.zone2Controls.label = Zone 2 +channel-group-type.onkyo.zone3Controls.label = Zone 3 + +# channel types + +channel-type.onkyo.album.label = Album +channel-type.onkyo.album.description = Album name of the current song +channel-type.onkyo.albumArt.label = Album Art +channel-type.onkyo.albumArt.description = Image of cover art of the current song +channel-type.onkyo.albumArtUrl.label = Album Art Url +channel-type.onkyo.albumArtUrl.description = Url to the image of cover art of the current song +channel-type.onkyo.artist.label = Artist +channel-type.onkyo.artist.description = Artist name of the current song +channel-type.onkyo.audioinfo.label = Audio Info +channel-type.onkyo.audioinfo.description = Detailed audio info +channel-type.onkyo.control.label = Control +channel-type.onkyo.control.description = Control the Zone Player, e.g. start/stop/next/previous/ffward/rewind +channel-type.onkyo.currentPlayingTime.label = Playing Time +channel-type.onkyo.currentPlayingTime.description = Current Playing Time +channel-type.onkyo.input.label = Input Source +channel-type.onkyo.input.description = Select the input source of the AVR +channel-type.onkyo.input.state.option.0 = DVR/VCR +channel-type.onkyo.input.state.option.1 = SATELLITE/CABLE +channel-type.onkyo.input.state.option.2 = GAME +channel-type.onkyo.input.state.option.3 = AUX +channel-type.onkyo.input.state.option.4 = GAME2 +channel-type.onkyo.input.state.option.5 = PC +channel-type.onkyo.input.state.option.16 = BLURAY/DVD +channel-type.onkyo.input.state.option.17 = STRM BOX +channel-type.onkyo.input.state.option.18 = TV +channel-type.onkyo.input.state.option.32 = TAPE1 +channel-type.onkyo.input.state.option.33 = TAPE2 +channel-type.onkyo.input.state.option.34 = PHONO +channel-type.onkyo.input.state.option.35 = CD/TV +channel-type.onkyo.input.state.option.36 = TUNER FM +channel-type.onkyo.input.state.option.37 = TUNER AM +channel-type.onkyo.input.state.option.38 = TUNER +channel-type.onkyo.input.state.option.39 = MUSICSERVER +channel-type.onkyo.input.state.option.40 = INTERNETRADIO +channel-type.onkyo.input.state.option.41 = USB +channel-type.onkyo.input.state.option.42 = USB_BACK +channel-type.onkyo.input.state.option.43 = NETWORK +channel-type.onkyo.input.state.option.44 = USB_TOGGLE +channel-type.onkyo.input.state.option.45 = AIRPLAY +channel-type.onkyo.input.state.option.46 = BLUETOOTH +channel-type.onkyo.input.state.option.48 = MULTICH +channel-type.onkyo.input.state.option.50 = SIRIUS +channel-type.onkyo.input.state.option.128 = SOURCE +channel-type.onkyo.listenmode.label = Listen Mode +channel-type.onkyo.listenmode.description = Listen mode +channel-type.onkyo.listenmode.state.option.0 = Stereo +channel-type.onkyo.listenmode.state.option.1 = Direct +channel-type.onkyo.listenmode.state.option.3 = Game RPG +channel-type.onkyo.listenmode.state.option.5 = Game Action +channel-type.onkyo.listenmode.state.option.6 = Game Rock +channel-type.onkyo.listenmode.state.option.8 = Orchestra +channel-type.onkyo.listenmode.state.option.9 = unplugged +channel-type.onkyo.listenmode.state.option.10 = Studio Mix +channel-type.onkyo.listenmode.state.option.11 = TV Logic +channel-type.onkyo.listenmode.state.option.12 = All Channel Stereo +channel-type.onkyo.listenmode.state.option.13 = Theater Dimensional +channel-type.onkyo.listenmode.state.option.14 = Game-Sports +channel-type.onkyo.listenmode.state.option.15 = Mono +channel-type.onkyo.listenmode.state.option.17 = Pure Audio +channel-type.onkyo.listenmode.state.option.19 = Full Mono +channel-type.onkyo.listenmode.state.option.22 = Audyssey DSX +channel-type.onkyo.listenmode.state.option.64 = 5.1ch Surround +channel-type.onkyo.listenmode.state.option.128 = PLII/PLIIx Movie +channel-type.onkyo.listenmode.state.option.129 = PLII/PLIIx Music +channel-type.onkyo.listenmode.state.option.130 = Neo 6/Neo:X Cinema + DTS:X/Neural:X +channel-type.onkyo.listenmode.state.option.131 = Neo 6/Neo:X Music +channel-type.onkyo.listenmode.state.option.134 = PLII/PLIIx Game +channel-type.onkyo.listenmode.state.option.160 = PLIIx/PLII Movie + Audyssey DSX +channel-type.onkyo.listenmode.state.option.161 = PLIIx/PLII Music + Audyssey DSX +channel-type.onkyo.listenmode.state.option.162 = PLIIx/PLII Game + Audyssey DSX +channel-type.onkyo.listenmode.state.option.163 = Neo Cinema DSX +channel-type.onkyo.listenmode.state.option.164 = Neo Music DSX +channel-type.onkyo.listenmode.state.option.165 = Neural Surround DSX +channel-type.onkyo.listenmode.state.option.166 = Neural Digital DSX +channel-type.onkyo.menuItem.label = Menu Item +channel-type.onkyo.menuItem.description = Net/USB menu item +channel-type.onkyo.menuSelection.label = Selected Item +channel-type.onkyo.menuSelection.description = Position of the currently selected menu item +channel-type.onkyo.mute.label = Mute +channel-type.onkyo.mute.description = Mute/unmute your device +channel-type.onkyo.netControl.label = Control +channel-type.onkyo.netControl.description = Control the USB/Net Menu, e.g. Up/Down/Select/Back/PageUp/PageDown/Select[0-9] +channel-type.onkyo.netControl.state.option.Up = Selection Up +channel-type.onkyo.netControl.state.option.Down = Selection Down +channel-type.onkyo.netControl.state.option.Select = Select Entry +channel-type.onkyo.netControl.state.option.Back = Go Back +channel-type.onkyo.netControl.state.option.PageUp = Scroll Page Up +channel-type.onkyo.netControl.state.option.PageDown = Scroll Page Down +channel-type.onkyo.netControl.state.option.Select0 = Select Entry 0 +channel-type.onkyo.netControl.state.option.Select1 = Select Entry 1 +channel-type.onkyo.netControl.state.option.Select2 = Select Entry 2 +channel-type.onkyo.netControl.state.option.Select3 = Select Entry 3 +channel-type.onkyo.netControl.state.option.Select4 = Select Entry 4 +channel-type.onkyo.netControl.state.option.Select5 = Select Entry 5 +channel-type.onkyo.netControl.state.option.Select6 = Select Entry 6 +channel-type.onkyo.netControl.state.option.Select7 = Select Entry 7 +channel-type.onkyo.netControl.state.option.Select8 = Select Entry 8 +channel-type.onkyo.netControl.state.option.Select9 = Select Entry 9 +channel-type.onkyo.playuri.label = Play URI +channel-type.onkyo.playuri.description = Plays a given URI +channel-type.onkyo.power.label = Power +channel-type.onkyo.power.description = Power on/off your device +channel-type.onkyo.title.label = Title +channel-type.onkyo.title.description = Title of the current song +channel-type.onkyo.volume.label = Volume +channel-type.onkyo.volume.description = Volume of your device diff --git a/bundles/org.openhab.binding.opengarage/src/main/resources/OH-INF/i18n/opengarage.properties b/bundles/org.openhab.binding.opengarage/src/main/resources/OH-INF/i18n/opengarage.properties new file mode 100644 index 0000000000000..ddf4fc7be8542 --- /dev/null +++ b/bundles/org.openhab.binding.opengarage/src/main/resources/OH-INF/i18n/opengarage.properties @@ -0,0 +1,51 @@ +# binding + +binding.opengarage.name = OpenGarage Binding +binding.opengarage.description = This is the binding for OpenGarage. + +# thing types + +thing-type.opengarage.opengarage.label = OpenGarage +thing-type.opengarage.opengarage.description = OpenGarage Controller + +# thing types config + +thing-type.config.opengarage.opengarage.hostname.label = Hostname/IP Address +thing-type.config.opengarage.opengarage.hostname.description = The host name or IP address of the OpenGarage Web API interface. +thing-type.config.opengarage.opengarage.password.label = Password +thing-type.config.opengarage.opengarage.password.description = The admin password used to access the Web API interface. +thing-type.config.opengarage.opengarage.port.label = Port +thing-type.config.opengarage.opengarage.port.description = Port of the OpenGarage Web API interface. +thing-type.config.opengarage.opengarage.refresh.label = Refresh Interval +thing-type.config.opengarage.opengarage.refresh.description = Specifies the refresh interval in seconds. + +# channel types + +channel-type.opengarage.opengarage-distance.label = Distance +channel-type.opengarage.opengarage-distance.description = Distance Reading from the OG unit +channel-type.opengarage.opengarage-status-contact.label = Contact Status +channel-type.opengarage.opengarage-status-contact.description = Contact Status of the OG unit +channel-type.opengarage.opengarage-status-rollershutter.label = Rollershutter Status +channel-type.opengarage.opengarage-status-rollershutter.description = Roller Shutter Status of the OG unit +channel-type.opengarage.opengarage-status-switch.label = Status +channel-type.opengarage.opengarage-status-switch.description = On/Off Status of the OG unit +channel-type.opengarage.opengarage-status.label = Status +channel-type.opengarage.opengarage-status.description = On/Off Status of the OG unit (now deprecated, use status-switch instead) +channel-type.opengarage.opengarage-vehicle-status.label = Vehicle Presence +channel-type.opengarage.opengarage-vehicle-status.description = Vehicle presence detection +channel-type.opengarage.opengarage-vehicle-status.state.option.0 = No vehicle detected +channel-type.opengarage.opengarage-vehicle-status.state.option.1 = Vehicle detected +channel-type.opengarage.opengarage-vehicle-status.state.option.2 = Vehicle status unknown +channel-type.opengarage.opengarage-vehicle.label = Vehicle Presence +channel-type.opengarage.opengarage-vehicle.description = Is a vehicle present or not (now deprecated, use vehicle-status instead) + +# channel types config + +channel-type.config.opengarage.opengarage-status-switch.invert.label = Invert Switch +channel-type.config.opengarage.opengarage-status-switch.invert.description = Invert switch to ON=Closed, OFF=Open +channel-type.config.opengarage.opengarage-status-switch.invert.option.true = Yes +channel-type.config.opengarage.opengarage-status-switch.invert.option.false = No +channel-type.config.opengarage.opengarage-status.invert.label = Invert Switch +channel-type.config.opengarage.opengarage-status.invert.description = Invert switch to ON=Closed, OFF=Open +channel-type.config.opengarage.opengarage-status.invert.option.true = Yes +channel-type.config.opengarage.opengarage-status.invert.option.false = No diff --git a/bundles/org.openhab.binding.opensprinkler/src/main/resources/OH-INF/i18n/opensprinkler.properties b/bundles/org.openhab.binding.opensprinkler/src/main/resources/OH-INF/i18n/opensprinkler.properties new file mode 100644 index 0000000000000..31a0be3cb9c17 --- /dev/null +++ b/bundles/org.openhab.binding.opensprinkler/src/main/resources/OH-INF/i18n/opensprinkler.properties @@ -0,0 +1,63 @@ +# binding + +binding.opensprinkler.name = OpenSprinkler Binding +binding.opensprinkler.description = This is the binding for OpenSprinkler. + +# thing types + +thing-type.opensprinkler.device.label = OpenSprinkler Device +thing-type.opensprinkler.device.description = A thing that receives data from the OpenSprinkler device directly. +thing-type.opensprinkler.http.label = OpenSprinkler HTTP Bridge +thing-type.opensprinkler.http.description = A connection to a stand alone OpenSprinkler device which communicates over HTTP. +thing-type.opensprinkler.station.label = OpenSprinkler Station +thing-type.opensprinkler.station.description = Controls a station connected to the OpenSprinkler device. + +# thing types config + +thing-type.config.opensprinkler.http.basicPassword.label = Basic Auth Password +thing-type.config.opensprinkler.http.basicPassword.description = Used if the OpenSprinkler device is behind a basic auth protected reverse proxy. +thing-type.config.opensprinkler.http.basicUsername.label = Basic Auth Username +thing-type.config.opensprinkler.http.basicUsername.description = Used if the OpenSprinkler device is behind a basic auth protected reverse proxy. +thing-type.config.opensprinkler.http.hostname.label = Hostname +thing-type.config.opensprinkler.http.hostname.description = The host name or IP address of the OpenSprinkler Web API interface. It may or may not start with the protocol, e.g. in order to use https:// instead of the default http://. +thing-type.config.opensprinkler.http.password.label = Password +thing-type.config.opensprinkler.http.password.description = The admin password used to access the Web API interface. +thing-type.config.opensprinkler.http.port.label = Port +thing-type.config.opensprinkler.http.port.description = Port of the OpenSprinkler Web API interface. +thing-type.config.opensprinkler.http.refresh.label = Refresh Interval +thing-type.config.opensprinkler.http.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.opensprinkler.station.stationIndex.label = Station Index +thing-type.config.opensprinkler.station.stationIndex.description = The index of the station, starting with 0, of the station. + +# channel types + +channel-type.opensprinkler.currentDraw.label = Current Draw +channel-type.opensprinkler.currentDraw.description = The current draw in mA +channel-type.opensprinkler.enablePrograms.label = Enable Programs +channel-type.opensprinkler.enablePrograms.description = Allow programs to auto run, when OFF, manually started stations still work. +channel-type.opensprinkler.flowSensorCount.label = Flow Sensor Count +channel-type.opensprinkler.flowSensorCount.description = A count of how many pulses the water flow sensor has given. +channel-type.opensprinkler.ignoreRain.label = Station Ignores Rain +channel-type.opensprinkler.ignoreRain.description = The station will ignore forecasted rain. +channel-type.opensprinkler.nextDuration.label = Next Duration +channel-type.opensprinkler.nextDuration.description = The duration the station will be opened the next time it is switched on. +channel-type.opensprinkler.programs.label = Run Program +channel-type.opensprinkler.programs.description = Run a program that is saved inside the OpenSprinkler Device. +channel-type.opensprinkler.queued.label = Queued +channel-type.opensprinkler.queued.description = Indicates if the station is queued to be turned on. Can be removed from the queue by turning off. ON is read-only. +channel-type.opensprinkler.rainDelay.label = Rain Delay +channel-type.opensprinkler.rainDelay.description = The amount of time in hours to delay the running of any program. +channel-type.opensprinkler.rainsensor.label = Rain Sensor +channel-type.opensprinkler.rainsensor.description = Provides feedback on whether the OpenSprinkler device has detected rain or not. +channel-type.opensprinkler.remainingWaterTime.label = Remaining Water Time +channel-type.opensprinkler.remainingWaterTime.description = Read-only property of the remaining water time of the station. +channel-type.opensprinkler.resetStations.label = Reset Stations +channel-type.opensprinkler.resetStations.description = Resets all stations back to CLOSED. +channel-type.opensprinkler.sensor2.label = Sensor 2 +channel-type.opensprinkler.sensor2.description = Sensor 2 can be setup as a rain, flow or soil moisture sensor. +channel-type.opensprinkler.stationState.label = Station State +channel-type.opensprinkler.stationState.description = Controls a station on the OpenSprinkler device. +channel-type.opensprinkler.stations.label = Open Station +channel-type.opensprinkler.stations.description = Opens the solenoid of a single station. +channel-type.opensprinkler.waterlevel.label = Water Level +channel-type.opensprinkler.waterlevel.description = The current watering level in percent diff --git a/bundles/org.openhab.binding.openthermgateway/src/main/resources/OH-INF/i18n/openthermgateway.properties b/bundles/org.openhab.binding.openthermgateway/src/main/resources/OH-INF/i18n/openthermgateway.properties new file mode 100644 index 0000000000000..e76bba2f9b0b5 --- /dev/null +++ b/bundles/org.openhab.binding.openthermgateway/src/main/resources/OH-INF/i18n/openthermgateway.properties @@ -0,0 +1,119 @@ +# binding + +binding.openthermgateway.name = OpenTherm Gateway Binding +binding.openthermgateway.description = This is the binding for the OpenTherm Gateway, designed by Schelte Bron. For more information about the OpenTherm Gateway please see http://otgw.tclcode.com/ + +# thing types + +thing-type.openthermgateway.otgw.label = OpenTherm Gateway +thing-type.openthermgateway.otgw.description = OpenTherm Gateway binding + +# thing types config + +thing-type.config.openthermgateway.otgw.connectionRetryInterval.label = Connection Retry Interval +thing-type.config.openthermgateway.otgw.connectionRetryInterval.description = The interval in seconds to retry connecting (0 = disabled). +thing-type.config.openthermgateway.otgw.group.connection.label = Connection +thing-type.config.openthermgateway.otgw.group.connection.description = Connection settings. +thing-type.config.openthermgateway.otgw.ipaddress.label = Hostname or IP address +thing-type.config.openthermgateway.otgw.ipaddress.description = The hostname or IP address to connect to the OpenTherm Gateway. +thing-type.config.openthermgateway.otgw.port.label = Port +thing-type.config.openthermgateway.otgw.port.description = The port used to connect to the OpenTherm Gateway. + +# channel types + +channel-type.openthermgateway.airpressfault.label = Air Pressure Fault +channel-type.openthermgateway.airpressfault.description = Air pressure fault +channel-type.openthermgateway.burnerhours.label = Burner Hours +channel-type.openthermgateway.burnerhours.description = Burner hours +channel-type.openthermgateway.burnerstarts.label = Burner Starts +channel-type.openthermgateway.burnerstarts.description = Burner starts +channel-type.openthermgateway.ch2_enable.label = Central Heating 2 Enabled +channel-type.openthermgateway.ch2_enable.description = Central heating 2 enabled set at boiler +channel-type.openthermgateway.ch2_enableoverride.label = Central Heating 2 Overridden +channel-type.openthermgateway.ch2_enableoverride.description = Central heating 2 enabled overridden at OTGW +channel-type.openthermgateway.ch2_enablerequested.label = Central Heating 2 Enabled Thermostat +channel-type.openthermgateway.ch2_enablerequested.description = Central heating 2 enabled requested by thermostat +channel-type.openthermgateway.ch_enable.label = Central Heating Enabled +channel-type.openthermgateway.ch_enable.description = Central heating enabled set at boiler +channel-type.openthermgateway.ch_enableoverride.label = Central Heating Overridden +channel-type.openthermgateway.ch_enableoverride.description = Central heating enabled overridden at OTGW +channel-type.openthermgateway.ch_enablerequested.label = Central Heating Enabled Thermostat +channel-type.openthermgateway.ch_enablerequested.description = Central heating enabled requested by thermostat +channel-type.openthermgateway.ch_mode.label = Central Heating Active +channel-type.openthermgateway.ch_mode.description = Central heating active +channel-type.openthermgateway.chpumphours.label = Central Heating Pump Hours +channel-type.openthermgateway.chpumphours.description = Central heating pump hours +channel-type.openthermgateway.chpumpstarts.label = Central Heating Pump Starts +channel-type.openthermgateway.chpumpstarts.description = Central heating pump starts +channel-type.openthermgateway.controlsetpoint.label = Control Setpoint +channel-type.openthermgateway.controlsetpoint.description = Central heating water setpoint set at boiler +channel-type.openthermgateway.controlsetpoint2.label = Control Setpoint 2 +channel-type.openthermgateway.controlsetpoint2.description = Central heating 2 water setpoint set at boiler +channel-type.openthermgateway.controlsetpoint2override.label = Control Setpoint 2 Override +channel-type.openthermgateway.controlsetpoint2override.description = Central heating 2 water setpoint configured on OTGW +channel-type.openthermgateway.controlsetpoint2requested.label = Control Setpoint 2 Requested +channel-type.openthermgateway.controlsetpoint2requested.description = Central heating 2 water setpoint requested by Thermostat +channel-type.openthermgateway.controlsetpointoverride.label = Control Setpoint Override +channel-type.openthermgateway.controlsetpointoverride.description = Central heating water setpoint configured on OTGW +channel-type.openthermgateway.controlsetpointrequested.label = Control Setpoint Requested +channel-type.openthermgateway.controlsetpointrequested.description = Central heating water setpoint requested by Thermostat +channel-type.openthermgateway.dhw_enable.label = Domestic Hot Water Enabled +channel-type.openthermgateway.dhw_enable.description = Domestic hot water enabled +channel-type.openthermgateway.dhw_mode.label = Domestic Hot Water Active +channel-type.openthermgateway.dhw_mode.description = Domestic hot water active +channel-type.openthermgateway.dhwburnerhours.label = Domestic Hot Water Burner Hours +channel-type.openthermgateway.dhwburnerhours.description = Domestic hot water burner hours +channel-type.openthermgateway.dhwburnerstarts.label = Domestic Hot Water Burner Starts +channel-type.openthermgateway.dhwburnerstarts.description = Domestic hot water burner starts +channel-type.openthermgateway.dhwpvhours.label = Domestic Hot Water Pump/Valve Hours +channel-type.openthermgateway.dhwpvhours.description = Domestic hot water pump/valve hours +channel-type.openthermgateway.dhwpvstarts.label = Domestic Hot Water Pump/Valve Starts +channel-type.openthermgateway.dhwpvstarts.description = Domestic hot water pump/valve starts +channel-type.openthermgateway.dhwtemp.label = Domestic Hot Water Temperature +channel-type.openthermgateway.dhwtemp.description = Domestic hot water temperature +channel-type.openthermgateway.diag.label = Diagnostics Indication +channel-type.openthermgateway.diag.description = Diagnostics indication +channel-type.openthermgateway.fault.label = Fault Indication +channel-type.openthermgateway.fault.description = Fault indication +channel-type.openthermgateway.flame.label = Burner Active +channel-type.openthermgateway.flame.description = Burner active +channel-type.openthermgateway.flowtemp.label = Boiler Water Temperature +channel-type.openthermgateway.flowtemp.description = Boiler water temperature +channel-type.openthermgateway.gasflamefault.label = Gas Or Flame Fault +channel-type.openthermgateway.gasflamefault.description = Gas or flame fault +channel-type.openthermgateway.lockout-reset.label = Lockout-Reset Enabled +channel-type.openthermgateway.lockout-reset.description = Lockout-reset enabled +channel-type.openthermgateway.lowwaterpress.label = Low Water Pressure Fault +channel-type.openthermgateway.lowwaterpress.description = Low water pressure fault +channel-type.openthermgateway.maxrelmdulevel.label = Maximum Relative Modulation Level +channel-type.openthermgateway.maxrelmdulevel.description = Maximum relative modulation level +channel-type.openthermgateway.modulevel.label = Relative Modulation Level +channel-type.openthermgateway.modulevel.description = Relative modulation level +channel-type.openthermgateway.oemfaultcode.label = OEM Fault Code +channel-type.openthermgateway.oemfaultcode.description = OEM fault code +channel-type.openthermgateway.outsidetemp.label = Outside Temperature +channel-type.openthermgateway.outsidetemp.description = Outside temperature +channel-type.openthermgateway.overridedhwsetpoint.label = Domestic Hot Water Setpoint Override +channel-type.openthermgateway.overridedhwsetpoint.description = Domestic hot water temperature setpoint override +channel-type.openthermgateway.returntemp.label = Return Water Temperature +channel-type.openthermgateway.returntemp.description = Return water temperature +channel-type.openthermgateway.roomsetpoint.label = Room Setpoint +channel-type.openthermgateway.roomsetpoint.description = Current room temperature setpoint +channel-type.openthermgateway.roomtemp.label = Room Temperature +channel-type.openthermgateway.roomtemp.description = Current sensed room temperature +channel-type.openthermgateway.sendcommand.label = Send Command +channel-type.openthermgateway.sendcommand.description = Channel to send commands to the OpenTherm Gateway device +channel-type.openthermgateway.servicerequest.label = Service Required +channel-type.openthermgateway.servicerequest.description = Service required +channel-type.openthermgateway.tdhwset.label = Domestic Hot Water Setpoint +channel-type.openthermgateway.tdhwset.description = Domestic hot water temperature setpoint +channel-type.openthermgateway.temperatureconstant.label = Constant Room Setpoint Override +channel-type.openthermgateway.temperatureconstant.description = Constant override room temperature setpoint +channel-type.openthermgateway.temperaturetemporary.label = Temporary Room Setpoint Override +channel-type.openthermgateway.temperaturetemporary.description = Temporary override room temperature setpoint +channel-type.openthermgateway.unsuccessfulburnerstarts.label = Unsuccessful Burner Starts +channel-type.openthermgateway.unsuccessfulburnerstarts.description = Unsuccessful burner starts +channel-type.openthermgateway.waterovtemp.label = Water Over-Temperature Fault +channel-type.openthermgateway.waterovtemp.description = Water over-temperature fault +channel-type.openthermgateway.waterpressure.label = Central Heating Water Pressure +channel-type.openthermgateway.waterpressure.description = Central heating water pressure diff --git a/bundles/org.openhab.binding.oppo/src/main/resources/OH-INF/i18n/oppo.properties b/bundles/org.openhab.binding.oppo/src/main/resources/OH-INF/i18n/oppo.properties new file mode 100644 index 0000000000000..1f8d292f65235 --- /dev/null +++ b/bundles/org.openhab.binding.oppo/src/main/resources/OH-INF/i18n/oppo.properties @@ -0,0 +1,165 @@ +# binding + +binding.oppo.name = Oppo Blu-ray Player Binding +binding.oppo.description = Controls the Oppo UDP-203/205 and BDP-83/93/95/103/105 Blu-ray Players + +# thing types + +thing-type.oppo.player.label = Oppo Blu-ray Disc Player +thing-type.oppo.player.description = Controls an Oppo Blu-ray Disc Player + +# thing types config + +thing-type.config.oppo.player.host.label = Address +thing-type.config.oppo.player.host.description = Host Name or IP Address of the Oppo Player or Machine Used for Serial Over IP. +thing-type.config.oppo.player.model.label = Player Model +thing-type.config.oppo.player.model.description = Choose Model of Oppo Player +thing-type.config.oppo.player.model.option.83 = BDP-83 or BDP-93/95 +thing-type.config.oppo.player.model.option.103 = BDP-103/103D +thing-type.config.oppo.player.model.option.105 = BDP-105/105D +thing-type.config.oppo.player.model.option.203 = UDP-203 +thing-type.config.oppo.player.model.option.205 = UDP-205 +thing-type.config.oppo.player.port.label = Port +thing-type.config.oppo.player.port.description = (Optional) Communication Port for Serial Over IP Connection. Leave blank If Connecting Directly to the Player. +thing-type.config.oppo.player.serialPort.label = Serial Port +thing-type.config.oppo.player.serialPort.description = Serial Port to Use for Connecting to the Oppo Player. +thing-type.config.oppo.player.verboseMode.label = Verbose Mode +thing-type.config.oppo.player.verboseMode.description = If true, the player will send time updates every second. If false, the binding polls the player evey 10 seconds + +# channel types + +channel-type.oppo.3d_indicator.label = 2D/3D Indicator +channel-type.oppo.3d_indicator.description = Indicates If the Content Playing is 2D or 3D +channel-type.oppo.aspect_ratio.label = Aspect Ratio +channel-type.oppo.aspect_ratio.description = The Aspect Ratio of the Current Video Output +channel-type.oppo.audio_type.label = Audio Type +channel-type.oppo.audio_type.description = The Current Audio Track Type +channel-type.oppo.control.label = Control +channel-type.oppo.control.description = Transport Controls e.g. Play/Pause/Next/Previous/Fast Forward/Rewind +channel-type.oppo.current_chapter.label = Current Chapter +channel-type.oppo.current_chapter.description = Current Chapter Number +channel-type.oppo.current_title.label = Current Title/Track +channel-type.oppo.current_title.description = Current Title or Track Number Playing +channel-type.oppo.disc_type.label = Disc Type +channel-type.oppo.disc_type.description = The Current Type of Disc in the Player +channel-type.oppo.hdmi_mode.label = HDMI Mode +channel-type.oppo.hdmi_mode.description = The Current HDMI Output Mode +channel-type.oppo.hdr_mode.label = HDR Mode +channel-type.oppo.hdr_mode.description = The Current HDR Output Mode +channel-type.oppo.hdr_mode.state.option.Auto = Auto +channel-type.oppo.hdr_mode.state.option.On = On +channel-type.oppo.hdr_mode.state.option.Off = Off +channel-type.oppo.osd_position.label = OSD Position +channel-type.oppo.osd_position.description = Set the OSD Position 0 to 5 +channel-type.oppo.output_resolution.label = Output Video Resolution +channel-type.oppo.output_resolution.description = The Video Resolution of the Player Output +channel-type.oppo.play_mode.label = Play Mode +channel-type.oppo.play_mode.description = The Current Playback Mode of the Source +channel-type.oppo.remote_button.label = Remote Button +channel-type.oppo.remote_button.description = Simulate Pressing a Button on the Remote Control +channel-type.oppo.remote_button.state.option.EJT = Eject +channel-type.oppo.remote_button.state.option.DIM = Dimmer +channel-type.oppo.remote_button.state.option.PUR = Pure Audio +channel-type.oppo.remote_button.state.option.VUP = Vol + +channel-type.oppo.remote_button.state.option.VDN = Vol - +channel-type.oppo.remote_button.state.option.MUT = Mute +channel-type.oppo.remote_button.state.option.NU1 = 1 +channel-type.oppo.remote_button.state.option.NU2 = 2 +channel-type.oppo.remote_button.state.option.NU3 = 3 +channel-type.oppo.remote_button.state.option.NU4 = 4 +channel-type.oppo.remote_button.state.option.NU5 = 5 +channel-type.oppo.remote_button.state.option.NU6 = 6 +channel-type.oppo.remote_button.state.option.NU7 = 7 +channel-type.oppo.remote_button.state.option.NU8 = 8 +channel-type.oppo.remote_button.state.option.NU9 = 9 +channel-type.oppo.remote_button.state.option.NU0 = 0 +channel-type.oppo.remote_button.state.option.CLR = Clear +channel-type.oppo.remote_button.state.option.GOT = Goto +channel-type.oppo.remote_button.state.option.HOM = Home +channel-type.oppo.remote_button.state.option.PUP = Page Up +channel-type.oppo.remote_button.state.option.PDN = Page Down +channel-type.oppo.remote_button.state.option.OSD = Info/Display +channel-type.oppo.remote_button.state.option.TTL = Top Menu +channel-type.oppo.remote_button.state.option.MNU = Pop-Up Menu +channel-type.oppo.remote_button.state.option.NUP = Up +channel-type.oppo.remote_button.state.option.NLT = Left +channel-type.oppo.remote_button.state.option.NRT = Right +channel-type.oppo.remote_button.state.option.NDN = Down +channel-type.oppo.remote_button.state.option.SEL = Select +channel-type.oppo.remote_button.state.option.SET = Setup +channel-type.oppo.remote_button.state.option.RET = Return +channel-type.oppo.remote_button.state.option.RED = Red +channel-type.oppo.remote_button.state.option.GRN = Green +channel-type.oppo.remote_button.state.option.BLU = Blue +channel-type.oppo.remote_button.state.option.YLW = Yellow +channel-type.oppo.remote_button.state.option.STP = Stop +channel-type.oppo.remote_button.state.option.PLA = Play +channel-type.oppo.remote_button.state.option.PAU = Pause +channel-type.oppo.remote_button.state.option.PRE = Previous +channel-type.oppo.remote_button.state.option.REV = Fast Reverse +channel-type.oppo.remote_button.state.option.FWD = Fast Forward +channel-type.oppo.remote_button.state.option.NXT = Next +channel-type.oppo.remote_button.state.option.AUD = Audio +channel-type.oppo.remote_button.state.option.SUB = Subtitle +channel-type.oppo.remote_button.state.option.ANG = Angle +channel-type.oppo.remote_button.state.option.ZOM = Zoom +channel-type.oppo.remote_button.state.option.SAP = SAP +channel-type.oppo.remote_button.state.option.ATB = AB Replay +channel-type.oppo.remote_button.state.option.RPT = Repeat +channel-type.oppo.remote_button.state.option.PIP = Picture in Picture +channel-type.oppo.remote_button.state.option.HDM = HDMI Mode +channel-type.oppo.remote_button.state.option.SUH = Subtitle +channel-type.oppo.remote_button.state.option.NFX = Netflix +channel-type.oppo.remote_button.state.option.VDU = Vudu +channel-type.oppo.remote_button.state.option.OPT = Option Menu +channel-type.oppo.remote_button.state.option.M3D = 3D Menu +channel-type.oppo.remote_button.state.option.SEH = Picture Adjustment +channel-type.oppo.remote_button.state.option.DRB = Darbee Adjustment +channel-type.oppo.remote_button.state.option.HDR = HDR Menu +channel-type.oppo.remote_button.state.option.INH = Extended OSD +channel-type.oppo.remote_button.state.option.RLH = Resolution Select +channel-type.oppo.remote_button.state.option.AVS = A/V Sync Menu +channel-type.oppo.remote_button.state.option.GPA = Gapless Play +channel-type.oppo.repeat_mode.label = Repeat Mode +channel-type.oppo.repeat_mode.description = The Current Repeat Mode +channel-type.oppo.repeat_mode.state.option.00 = Off +channel-type.oppo.repeat_mode.state.option.02 = Repeat Chapter +channel-type.oppo.repeat_mode.state.option.03 = Repeat All +channel-type.oppo.repeat_mode.state.option.04 = Repeat Title +channel-type.oppo.repeat_mode.state.option.05 = Shuffle +channel-type.oppo.repeat_mode.state.option.06 = Random +channel-type.oppo.source.label = Source Input +channel-type.oppo.source.description = Select the Source Input for the Player +channel-type.oppo.source_resolution.label = Source Video Resolution +channel-type.oppo.source_resolution.description = The Video Resolution of the Content Being Played +channel-type.oppo.sub_shift.label = Subtitle Shift +channel-type.oppo.sub_shift.description = Set the Subtitle Shift -10 to 10 +channel-type.oppo.subtitle_type.label = Subtitle Type +channel-type.oppo.subtitle_type.description = The Current Subtitle Selected +channel-type.oppo.time_display.label = Time Display (S) +channel-type.oppo.time_display.description = The Playback Time Elapsed/Remaining in Seconds +channel-type.oppo.time_mode.label = Time Display Mode +channel-type.oppo.time_mode.description = Sets the Time Information Display +channel-type.oppo.time_mode.state.option.T = Title Elapsed Time +channel-type.oppo.time_mode.state.option.X = Title Remaining Time +channel-type.oppo.time_mode.state.option.C = Chapter/Track Elapsed Time +channel-type.oppo.time_mode.state.option.K = Chapter/Track Remaining Time +channel-type.oppo.total_chapter.label = Total Number of Chapters +channel-type.oppo.total_chapter.description = The Total Number of Chapters in the Current Title +channel-type.oppo.total_title.label = Total Number of Titles/Tracks +channel-type.oppo.total_title.description = The Total Number of Titles or Tracks on the Disc +channel-type.oppo.zoom_mode.label = Zoom Mode +channel-type.oppo.zoom_mode.description = The Current Zoom Mode +channel-type.oppo.zoom_mode.state.option.00 = Off +channel-type.oppo.zoom_mode.state.option.01 = Stretch +channel-type.oppo.zoom_mode.state.option.02 = Full Screen +channel-type.oppo.zoom_mode.state.option.03 = Underscan +channel-type.oppo.zoom_mode.state.option.04 = 1.2x +channel-type.oppo.zoom_mode.state.option.05 = 1.3x +channel-type.oppo.zoom_mode.state.option.06 = 1.5x +channel-type.oppo.zoom_mode.state.option.07 = 2x +channel-type.oppo.zoom_mode.state.option.08 = 3x +channel-type.oppo.zoom_mode.state.option.09 = 4x +channel-type.oppo.zoom_mode.state.option.10 = 1/2 +channel-type.oppo.zoom_mode.state.option.11 = 1/3 +channel-type.oppo.zoom_mode.state.option.12 = 1/4 diff --git a/bundles/org.openhab.binding.orbitbhyve/src/main/resources/OH-INF/i18n/orbitbhyve.properties b/bundles/org.openhab.binding.orbitbhyve/src/main/resources/OH-INF/i18n/orbitbhyve.properties new file mode 100644 index 0000000000000..ffa8044b0d091 --- /dev/null +++ b/bundles/org.openhab.binding.orbitbhyve/src/main/resources/OH-INF/i18n/orbitbhyve.properties @@ -0,0 +1,43 @@ +# binding + +binding.orbitbhyve.name = Orbit B-hyve Binding +binding.orbitbhyve.description = This is the binding for Orbit B-hyve Wi-Fi irrigation systems. + +# thing types + +thing-type.orbitbhyve.bridge.label = Bridge +thing-type.orbitbhyve.bridge.description = Bridge for Orbit B-hyve Binding +thing-type.orbitbhyve.sprinkler.label = Sprinkler +thing-type.orbitbhyve.sprinkler.description = Orbit B-hyve Sprinkler + +# thing types config + +bridge-type.config.orbitbhyve.bridge.email.label = Email +bridge-type.config.orbitbhyve.bridge.email.description = This is a login to your B-hyve account. +bridge-type.config.orbitbhyve.bridge.password.label = Password +bridge-type.config.orbitbhyve.bridge.password.description = This is a password to your B-hyve account. +bridge-type.config.orbitbhyve.bridge.refresh.label = Refresh +bridge-type.config.orbitbhyve.bridge.refresh.description = Specifies the refresh time in seconds for polling data from Orbit cloud +thing-type.config.orbitbhyve.sprinkler.id.label = Sprinkler Device ID +thing-type.config.orbitbhyve.sprinkler.id.description = The identifier of the Orbit sprinkler device + +# channel types + +channel-type.orbitbhyve.control.label = Sprinkler State Control +channel-type.orbitbhyve.control.description = Channel for enabling/disabling the sprinkler (ON/OFF) +channel-type.orbitbhyve.mode.label = Irrigation Mode +channel-type.orbitbhyve.mode.description = Channel representing mode of Orbit B-hyve Device (auto/manual) +channel-type.orbitbhyve.mode.state.option.auto = Auto +channel-type.orbitbhyve.mode.state.option.manual = Manual +channel-type.orbitbhyve.next_start.label = Next Watering Time +channel-type.orbitbhyve.next_start.description = Channel representing start time of the next watering +channel-type.orbitbhyve.program.label = Program Channel +channel-type.orbitbhyve.program.description = Dynamic channel representing a program +channel-type.orbitbhyve.rain_delay.label = Rain Delay +channel-type.orbitbhyve.rain_delay.description = Channel representing rain delay in hours +channel-type.orbitbhyve.smart_watering.label = Smart Watering Control +channel-type.orbitbhyve.smart_watering.description = Channel for enabling/disabling the smart watering mode +channel-type.orbitbhyve.watering_time.label = Zone Watering Time +channel-type.orbitbhyve.watering_time.description = Channel representing the manual zone watering time in minutes +channel-type.orbitbhyve.zone.label = Zone Channel +channel-type.orbitbhyve.zone.description = Dynamic channel representing a zone diff --git a/bundles/org.openhab.binding.orvibo/src/main/resources/OH-INF/i18n/orvibo.properties b/bundles/org.openhab.binding.orvibo/src/main/resources/OH-INF/i18n/orvibo.properties new file mode 100644 index 0000000000000..d575653e1e853 --- /dev/null +++ b/bundles/org.openhab.binding.orvibo/src/main/resources/OH-INF/i18n/orvibo.properties @@ -0,0 +1,19 @@ +# binding + +binding.orvibo.name = Orvibo Binding +binding.orvibo.description = This is the binding for Orvibo devices. + +# thing types + +thing-type.orvibo.s20.label = Orvibo S20 Smart Wifi Socket +thing-type.orvibo.s20.description = This is an Orvibo S20 Smart Wifi Socket + +# thing types config + +thing-type.config.orvibo.s20.deviceId.label = MAC Address +thing-type.config.orvibo.s20.deviceId.description = The MAC address identifies a specific S20 Socket. + +# channel types + +channel-type.orvibo.power.label = Power +channel-type.orvibo.power.description = Switch on/off your S20 Socket. diff --git a/bundles/org.openhab.binding.paradoxalarm/src/main/resources/OH-INF/i18n/paradoxalarm.properties b/bundles/org.openhab.binding.paradoxalarm/src/main/resources/OH-INF/i18n/paradoxalarm.properties new file mode 100644 index 0000000000000..8981beb174179 --- /dev/null +++ b/bundles/org.openhab.binding.paradoxalarm/src/main/resources/OH-INF/i18n/paradoxalarm.properties @@ -0,0 +1,117 @@ +# binding + +binding.paradoxalarm.name = ParadoxAlarm Binding +binding.paradoxalarm.description = This is the binding for ParadoxAlarm. + +# thing types + +thing-type.paradoxalarm.ip150.label = Paradox IP150 Module Connector +thing-type.paradoxalarm.ip150.description = Paradox IP150 module connector +thing-type.paradoxalarm.panel.label = Paradox Panel +thing-type.paradoxalarm.panel.description = Paradox panel various information +thing-type.paradoxalarm.partition.label = Paradox Partition +thing-type.paradoxalarm.partition.description = Paradox Partition +thing-type.paradoxalarm.zone.label = Paradox Zone +thing-type.paradoxalarm.zone.description = Paradox zone + +# thing types config + +thing-type.config.paradoxalarm.ip150.encrypt.label = Use Encryption +thing-type.config.paradoxalarm.ip150.encrypt.description = If set to true will use encrypted communication. Default=false for backward compatibility +thing-type.config.paradoxalarm.ip150.ip150Password.label = IP150 Password +thing-type.config.paradoxalarm.ip150.ip150Password.description = Password for accessing IP150 +thing-type.config.paradoxalarm.ip150.ipAddress.label = Network Address +thing-type.config.paradoxalarm.ip150.ipAddress.description = IP address or host name of IP150 +thing-type.config.paradoxalarm.ip150.maxPartitions.label = Max Partitions +thing-type.config.paradoxalarm.ip150.maxPartitions.description = Maximum number of configured partitions to check (from partition 1 to maxPartitions) +thing-type.config.paradoxalarm.ip150.maxZones.label = Max Zones +thing-type.config.paradoxalarm.ip150.maxZones.description = Maximum number of configured zones to check (from zone 1 to maxZones) +thing-type.config.paradoxalarm.ip150.panelType.label = Panel Type +thing-type.config.paradoxalarm.ip150.panelType.description = PanelType +thing-type.config.paradoxalarm.ip150.pcPassword.label = PC Password +thing-type.config.paradoxalarm.ip150.pcPassword.description = PC Password (section 3012 of configuration) +thing-type.config.paradoxalarm.ip150.port.label = Port +thing-type.config.paradoxalarm.ip150.port.description = Port to connect to IP150 +thing-type.config.paradoxalarm.ip150.reconnectWaitTime.label = Reconnect Wait Time +thing-type.config.paradoxalarm.ip150.reconnectWaitTime.description = The time to wait before a reconnect occurs after socket timeout. Value is in seconds +thing-type.config.paradoxalarm.ip150.refresh.label = Refresh Interval +thing-type.config.paradoxalarm.ip150.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.paradoxalarm.partition.disarmEnabled.label = Disarm Command Enabled +thing-type.config.paradoxalarm.partition.disarmEnabled.description = Parameter that enables option to send DISARM command to the partition. (DANGEROUS !) +thing-type.config.paradoxalarm.partition.id.label = Partition Id +thing-type.config.paradoxalarm.partition.id.description = This is the partition ID of the Paradox partition (1-8 for Evo) +thing-type.config.paradoxalarm.zone.id.label = Zone Id +thing-type.config.paradoxalarm.zone.id.description = This is the zone ID in the Paradox configuration + +# channel types + +channel-type.paradoxalarm.additionalState.label = Partition Additional States +channel-type.paradoxalarm.additionalState.description = Additional states provided by panel (deprecated channel) +channel-type.paradoxalarm.alarmInMemory.label = Partition Has Alarm In Memory +channel-type.paradoxalarm.alarmInMemory.description = Partition has Alarm in Memory +channel-type.paradoxalarm.allZonesClosed.label = Partition Has All Zones Closed +channel-type.paradoxalarm.allZonesClosed.description = Partition has All Zones closed +channel-type.paradoxalarm.applicationVersion.label = Application Version +channel-type.paradoxalarm.applicationVersion.description = Panel application version +channel-type.paradoxalarm.bootloaderVersion.label = Boot Loader Version +channel-type.paradoxalarm.bootloaderVersion.description = Boot loader version +channel-type.paradoxalarm.bypassReady.label = Partition Is Bypass Ready +channel-type.paradoxalarm.bypassReady.description = Partition is Bypass Ready +channel-type.paradoxalarm.command.label = Partition Command +channel-type.paradoxalarm.command.description = Send command +channel-type.paradoxalarm.command.state.option.ARM = Arm +channel-type.paradoxalarm.command.state.option.STAY_ARM = Stay Arm +channel-type.paradoxalarm.command.state.option.INSTANT_ARM = Instant Arm +channel-type.paradoxalarm.command.state.option.FORCE_ARM = Force Arm +channel-type.paradoxalarm.command.state.option.DISARM = Disarm +channel-type.paradoxalarm.command.state.option.BEEP = Keyboard Beep +channel-type.paradoxalarm.command.label = Communicator Command +channel-type.paradoxalarm.command.description = Send Command +channel-type.paradoxalarm.communicationState.label = Bridge Communication State +channel-type.paradoxalarm.communicationState.description = Status of connection to Paradox system +channel-type.paradoxalarm.forceReady.label = Partition Is Force Ready +channel-type.paradoxalarm.forceReady.description = Partition is Force Ready +channel-type.paradoxalarm.hardwareVersion.label = Hardware Version +channel-type.paradoxalarm.hardwareVersion.description = Panel hardware version +channel-type.paradoxalarm.inEntryDelay.label = Partition In Entry Delay +channel-type.paradoxalarm.inEntryDelay.description = Partition in Entry Delay +channel-type.paradoxalarm.inExitDelay.label = Partition In Exit Delay +channel-type.paradoxalarm.inExitDelay.description = Partition in Exit Delay +channel-type.paradoxalarm.inTrouble.label = Partition In Trouble +channel-type.paradoxalarm.inTrouble.description = Partition in Trouble +channel-type.paradoxalarm.inhibitReady.label = Partition Is Inhibit Ready +channel-type.paradoxalarm.inhibitReady.description = Partition is Inhibit Ready +channel-type.paradoxalarm.openedState.label = Zone State +channel-type.paradoxalarm.openedState.description = State of zone +channel-type.paradoxalarm.panelState.label = Panel State +channel-type.paradoxalarm.panelState.description = Shows the state of the communication to panel (online/offline) +channel-type.paradoxalarm.panelTime.label = Date +channel-type.paradoxalarm.panelTime.description = The current date and time on the panel +channel-type.paradoxalarm.panelType.label = Panel Type +channel-type.paradoxalarm.panelType.description = Panel type (Evo, SP, etc) +channel-type.paradoxalarm.partitionLabel.label = Partition Label +channel-type.paradoxalarm.partitionLabel.description = Label of partition +channel-type.paradoxalarm.readyToArm.label = Partition Ready To Arm +channel-type.paradoxalarm.readyToArm.description = Partition ready to arm +channel-type.paradoxalarm.serialNumber.label = Serial Number +channel-type.paradoxalarm.serialNumber.description = Panel serial number +channel-type.paradoxalarm.state.label = Partition State +channel-type.paradoxalarm.state.description = State of partition +channel-type.paradoxalarm.stayInstantReady.label = Partition Is Stay Instant Ready +channel-type.paradoxalarm.stayInstantReady.description = Partition is Stay Instant Ready +channel-type.paradoxalarm.tamperedState.label = Tampered +channel-type.paradoxalarm.tamperedState.description = State of zone +channel-type.paradoxalarm.voltage.label = Voltage +channel-type.paradoxalarm.voltage.description = Voltage +channel-type.paradoxalarm.zoneBypass.label = Partition Has Zone Bypass +channel-type.paradoxalarm.zoneBypass.description = Partition has Zone Bypass +channel-type.paradoxalarm.zoneInFireLoopTrouble.label = Partition Has Zone In Fire Loop Trouble +channel-type.paradoxalarm.zoneInFireLoopTrouble.description = Partition has in Fire Loop Trouble +channel-type.paradoxalarm.zoneInLowBatteryTrouble.label = Partition Has Zone In Low Battery Trouble +channel-type.paradoxalarm.zoneInLowBatteryTrouble.description = Partition has in Low Battery Trouble +channel-type.paradoxalarm.zoneInSupervisionTrouble.label = Partition Has Zone In Supervision Trouble +channel-type.paradoxalarm.zoneInSupervisionTrouble.description = Partition has in Supervision Trouble +channel-type.paradoxalarm.zoneInTamperTrouble.label = Partition Has Zone In Tamper Trouble +channel-type.paradoxalarm.zoneInTamperTrouble.description = Partition has in Tamper Trouble +channel-type.paradoxalarm.zoneLabel.label = Zone Label +channel-type.paradoxalarm.zoneLabel.description = Label of zone diff --git a/bundles/org.openhab.binding.pentair/src/main/resources/OH-INF/i18n/pentair.properties b/bundles/org.openhab.binding.pentair/src/main/resources/OH-INF/i18n/pentair.properties new file mode 100644 index 0000000000000..ea8b14d3daad9 --- /dev/null +++ b/bundles/org.openhab.binding.pentair/src/main/resources/OH-INF/i18n/pentair.properties @@ -0,0 +1,81 @@ +# binding + +binding.pentair.name = Pentair Binding +binding.pentair.description = This is the binding for Pentair pool systems. + +# thing types + +thing-type.pentair.easytouch.label = EasyTouch Controller +thing-type.pentair.easytouch.description = Pentair EasyTouch Controller +thing-type.pentair.intellichlor.label = Intellichlor IC40 +thing-type.pentair.intellichlor.description = Pentair Intellichlor IC40 +thing-type.pentair.intelliflo.label = Intelliflo Pump +thing-type.pentair.intelliflo.description = Pentair Intelliflo Pump +thing-type.pentair.ip_bridge.label = IP Bridge +thing-type.pentair.ip_bridge.description = This bridge is for use over a network interface. +thing-type.pentair.pentair_serial_bridge.label = Serial Bridge +thing-type.pentair.pentair_serial_bridge.description = This bridge is used when using a USB->RS485 interface. + +# thing types config + +thing-type.config.pentair.easytouch.id.label = ID +thing-type.config.pentair.easytouch.id.description = The ID of the device (in decimal, not hex) +thing-type.config.pentair.intellichlor.id.label = ID +thing-type.config.pentair.intellichlor.id.description = The ID of the device (in decimal, not hex) +thing-type.config.pentair.intelliflo.id.label = ID +thing-type.config.pentair.intelliflo.id.description = The ID of the device (in decimal, not hex) +thing-type.config.pentair.ip_bridge.address.label = IP Address +thing-type.config.pentair.ip_bridge.address.description = The IP address to connect to. +thing-type.config.pentair.ip_bridge.id.label = Pentair ID +thing-type.config.pentair.ip_bridge.id.description = The ID to use to send commands on the Pentair bus (default: 34) +thing-type.config.pentair.ip_bridge.port.label = Port +thing-type.config.pentair.ip_bridge.port.description = The port to connect to. +thing-type.config.pentair.pentair_serial_bridge.id.label = Pentair ID +thing-type.config.pentair.pentair_serial_bridge.id.description = The ID to use to send commands on the Pentair bus (default: 34) +thing-type.config.pentair.pentair_serial_bridge.serialPort.label = Serial Port +thing-type.config.pentair.pentair_serial_bridge.serialPort.description = The serial port name. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux. + +# channel types + +channel-type.pentair.airtemp.label = Air Temperature +channel-type.pentair.airtemp.description = Air temperature. +channel-type.pentair.auxswitch.label = Auxillary Switch +channel-type.pentair.auxswitch.description = Auxillary Switch +channel-type.pentair.featureswitch.label = Feature Switch +channel-type.pentair.featureswitch.description = Feature Switch +channel-type.pentair.heatactive.label = Heat Active +channel-type.pentair.heatactive.description = Heat active state +channel-type.pentair.heatmode.label = Heat Mode +channel-type.pentair.heatmode.description = Heat mode +channel-type.pentair.heatmode.state.option.0 = None +channel-type.pentair.heatmode.state.option.1 = Heater +channel-type.pentair.heatmode.state.option.2 = Solar Preferred +channel-type.pentair.heatmode.state.option.3 = Solar +channel-type.pentair.heatmodestr.label = Heat Mode Text +channel-type.pentair.heatmodestr.description = Heat mode string +channel-type.pentair.poolsetpoint.label = Pool Temperature Set Point +channel-type.pentair.poolsetpoint.description = Pool temperature set point +channel-type.pentair.pooltemp.label = Pool Water Temperature +channel-type.pentair.pooltemp.description = Pool water temperature. Only valid when pool pump is running and in pool mode. +channel-type.pentair.power.label = Power +channel-type.pentair.power.description = Pump power +channel-type.pentair.ppc.label = PPC +channel-type.pentair.ppc.description = Pump PPC +channel-type.pentair.pumperror.label = Pump Error +channel-type.pentair.pumperror.description = Pump Error +channel-type.pentair.pumpmode.label = Pump Mode +channel-type.pentair.pumpmode.description = Pump mode +channel-type.pentair.rpm.label = RPM +channel-type.pentair.rpm.description = Pump RPM +channel-type.pentair.runswitch.label = Pump Running +channel-type.pentair.runswitch.description = Indicator on whether the pump is running or not. +channel-type.pentair.salinity.label = Salinity (PPM) +channel-type.pentair.salinity.description = Current salt content reading of the water (PPM). +channel-type.pentair.saltoutput.label = Salt Output (%) +channel-type.pentair.saltoutput.description = Current salt output setting for the chlorinator (%). +channel-type.pentair.solartemp.label = Solar Temperature +channel-type.pentair.solartemp.description = Solar temperature. +channel-type.pentair.spasetpoint.label = Spa Temperature Set Point +channel-type.pentair.spasetpoint.description = Spa temperature set point +channel-type.pentair.spatemp.label = Spa Water Temperature +channel-type.pentair.spatemp.description = Spa water temperature. Only valide when in spa mode. diff --git a/bundles/org.openhab.binding.phc/src/main/resources/OH-INF/i18n/phc.properties b/bundles/org.openhab.binding.phc/src/main/resources/OH-INF/i18n/phc.properties new file mode 100644 index 0000000000000..c7c4edd8764e1 --- /dev/null +++ b/bundles/org.openhab.binding.phc/src/main/resources/OH-INF/i18n/phc.properties @@ -0,0 +1,68 @@ +# binding + +binding.phc.name = PHC Binding +binding.phc.description = This is a binding for PHC modules (EM, AM, JRM and DIM). It communicates with the PHC Modulbus (RS485). + +# thing types + +thing-type.phc.AM.label = PHC AM +thing-type.phc.AM.description = Thing for an output/relay module (AM). +thing-type.phc.DIM.label = PHC DIM +thing-type.phc.DIM.description = Thing for a dimmer module (DM). +thing-type.phc.EM.label = PHC EM +thing-type.phc.EM.description = Thing for an input/switch module (EM). +thing-type.phc.JRM.label = PHC JRM +thing-type.phc.JRM.description = Thing for an shutter module (JRM). +thing-type.phc.bridge.label = PHC Bridge +thing-type.phc.bridge.description = The serial bridge to the PHC modules. Max 32 modules per model group(thing type) per Bridge, equates one STM. + +# thing types config + +thing-type.config.phc.AM.address.label = Address +thing-type.config.phc.AM.address.description = Address of the module as binary, like the DIP switches. +thing-type.config.phc.DIM.address.label = Address +thing-type.config.phc.DIM.address.description = Address of the module as binary, like the DIP switches. +thing-type.config.phc.DIM.dimTime1.label = Time Dimmer 1 +thing-type.config.phc.DIM.dimTime1.description = The time (in seconds) in which the first dimmer should dim 100%. +thing-type.config.phc.DIM.dimTime2.label = Time Dimmer 2 +thing-type.config.phc.DIM.dimTime2.description = The time (in seconds) in which the second dimmer should dim 100%. +thing-type.config.phc.EM.address.label = Address +thing-type.config.phc.EM.address.description = Address of the module as binary, like the DIP switches. +thing-type.config.phc.JRM.address.label = Address +thing-type.config.phc.JRM.address.description = Address of the module as binary, like the DIP switches. +thing-type.config.phc.JRM.upDownTime1.label = Time Shutter 1 +thing-type.config.phc.JRM.upDownTime1.description = The time (in seconds) which the first shutter needs to move up/down. +thing-type.config.phc.JRM.upDownTime2.label = Time Shutter 2 +thing-type.config.phc.JRM.upDownTime2.description = The time (in seconds) which the second shutter needs to move up/down. +thing-type.config.phc.JRM.upDownTime3.label = Time Shutter 3 +thing-type.config.phc.JRM.upDownTime3.description = The time (in seconds) which the third shutter needs to move up/down. +thing-type.config.phc.JRM.upDownTime4.label = Time Shutter 4 +thing-type.config.phc.JRM.upDownTime4.description = The time (in seconds) which the fourth shutter needs to move up/down. +thing-type.config.phc.bridge.port.label = Serial Port +thing-type.config.phc.bridge.port.description = Serial Port the PHC modules are connected to + +# channel group types + +channel-group-type.phc.amChannels.label = AM Channels +channel-group-type.phc.amChannels.description = Outgoing switch channels (relay). +channel-group-type.phc.dimChannels.label = DIM Channels +channel-group-type.phc.dimChannels.description = Outgoing dimmer channels. +channel-group-type.phc.emChannels.label = EM Channels +channel-group-type.phc.emChannels.description = Incoming channels. +channel-group-type.phc.jrmChannels.label = JRM Channels +channel-group-type.phc.jrmChannels.description = Outgoing shutter channels (relay). +channel-group-type.phc.jrmTimeChannels.label = JRM time Channels +channel-group-type.phc.jrmTimeChannels.description = Time for shutter channels in seconds with an accuracy of 1/10 seconds. + +# channel types + +channel-type.phc.am-channel.label = PHC AM Channel +channel-type.phc.am-channel.description = Channel to an AM or EM(LED) module. +channel-type.phc.dim-channel.label = DIM Channel +channel-type.phc.dim-channel.description = Channel for a DIM module. +channel-type.phc.em-channel.label = PHC EM Channel +channel-type.phc.em-channel.description = Channel from an EM module. +channel-type.phc.jrm-channel.label = PHC JRM Channel +channel-type.phc.jrm-channel.description = Channel to an JRM module. +channel-type.phc.jrmTime-channel.label = JRM-time Channel +channel-type.phc.jrmTime-channel.description = The Time in seconds for an JRM channel. diff --git a/bundles/org.openhab.binding.pilight/src/main/resources/OH-INF/i18n/pilight.properties b/bundles/org.openhab.binding.pilight/src/main/resources/OH-INF/i18n/pilight.properties new file mode 100644 index 0000000000000..dde79df31737a --- /dev/null +++ b/bundles/org.openhab.binding.pilight/src/main/resources/OH-INF/i18n/pilight.properties @@ -0,0 +1,42 @@ +# binding + +binding.pilight.name = Pilight Binding +binding.pilight.description = The pilight binding allows openHAB to communicate with a pilight instance. Pilight is a service used to control 'Click On Click Off' devices like 433 MHz remote controlled sockets a cheap way, e.g. by using a Raspberry Pi with corresponding 433 MHz sender. + +# thing types + +thing-type.pilight.bridge.label = Pilight Bridge +thing-type.pilight.bridge.description = Pilight Bridge which connects to a Pilight instance. +thing-type.pilight.contact.label = Pilight Contact +thing-type.pilight.contact.description = Pilight Contact +thing-type.pilight.dimmer.label = Pilight Dimmer +thing-type.pilight.dimmer.description = Pilight Dimmer +thing-type.pilight.generic.label = Pilight Generic Device +thing-type.pilight.generic.description = Pilight Generic Device +thing-type.pilight.switch.label = Pilight Switch +thing-type.pilight.switch.description = Pilight Switch + +# thing types config + +thing-type.config.pilight.bridge.delay.label = Delay between Commands +thing-type.config.pilight.bridge.delay.description = Delay (in millisecond) between consecutive commands. Recommended value without band pass filter: 1000. Recommended value with band pass filter: somewhere between 200-500. +thing-type.config.pilight.bridge.ipAddress.label = Network Address +thing-type.config.pilight.bridge.ipAddress.description = The IP or host name of the Pilight instance. +thing-type.config.pilight.bridge.port.label = Port +thing-type.config.pilight.bridge.port.description = Port of the Pilight daemon. You must explicitly configure the port in the Pilight daemon config or otherwise a random port will be used and the binding will not be able to connect. +thing-type.config.pilight.device.name.label = Name of Device +thing-type.config.pilight.device.name.description = The name of the pilight device. + +# channel types + +channel-type.pilight.contact-state.label = State of Contact +channel-type.pilight.contact-state.description = State of Pilight Contact. +channel-type.pilight.number.label = Number Value +channel-type.pilight.string.label = Text Value + +# channel types config + +channel-type.config.pilight.number.property.label = Property +channel-type.config.pilight.number.property.description = The Property of the Device. +channel-type.config.pilight.string.property.label = Property +channel-type.config.pilight.string.property.description = The Property of the Device. diff --git a/bundles/org.openhab.binding.pioneeravr/src/main/resources/OH-INF/i18n/pioneeravr.properties b/bundles/org.openhab.binding.pioneeravr/src/main/resources/OH-INF/i18n/pioneeravr.properties new file mode 100644 index 0000000000000..8f87d13671d4b --- /dev/null +++ b/bundles/org.openhab.binding.pioneeravr/src/main/resources/OH-INF/i18n/pioneeravr.properties @@ -0,0 +1,678 @@ +# binding + +binding.pioneeravr.name = PioneerAvr Binding +binding.pioneeravr.description = A binding for Pioneer AVRs. + +# thing types + +thing-type.pioneeravr.ipAvr.label = Pioneer Classic AVR over IP +thing-type.pioneeravr.ipAvr.description = Control a classic Pioneer AVR (SC-57, SC-LX85, SC-55, SC-1526, SC-LX75, VSX-53, VSX-1326, VSX-LX55, VSX-2021, VSA-LX55, VSX-52, VSX-1126, VSX-1121, VSX-51, VSX-1021, VSX-1026, VSA-1021, VSX-50, VSX-926, VSX-921, VSA-921, VSX-922) over IP +thing-type.pioneeravr.ipAvr.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2014.label = Pioneer AVR over IP 2014 +thing-type.pioneeravr.ipAvr2014.description = Control a 2014 Pioneer AVR (SC-LX87, SC-LX77, SC-LX57, SC-2023, SC-1223, VSX-1123, VSX-923) over IP +thing-type.pioneeravr.ipAvr2014.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2014.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2014.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2014.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2015.label = Pioneer AVR over IP 2015 +thing-type.pioneeravr.ipAvr2015.description = Control a 2015 Pioneer AVR (SC-89, SC-LX88, SC-87, SC-LX78, SC-85, SC-LX58, SC-82, SC-2024, SC-81, VSX-80) over IP +thing-type.pioneeravr.ipAvr2015.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2015.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2015.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2015.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2016.label = Pioneer AVR over IP 2016 +thing-type.pioneeravr.ipAvr2016.description = Control a 2016 Pioneer AVR (SC-99, SC-LX89, SC-97, SC-LX79, SC-95, SC-LX59, SC-92, SC-91, VSX-90, VSX-45, VSX-830, VSX-930, VSX-1130) over IP +thing-type.pioneeravr.ipAvr2016.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2016.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2016.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2016.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2017.label = Pioneer AVR over IP 2017 +thing-type.pioneeravr.ipAvr2017.description = Control a 2017 Pioneer AVR (VSX-531, VSX-531D, VSX-831, VSX-1131, VSX-LX101, VSX-LX301, VSX-LX501) over IP +thing-type.pioneeravr.ipAvr2017.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2017.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2017.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2017.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2018.label = Pioneer AVR over IP 2018 +thing-type.pioneeravr.ipAvr2018.description = Control a 2018 Pioneer AVR (VSX-532, VSX-832, VSX-932, VSX-LX102, VSX-LX302, VSX-LX502) over IP +thing-type.pioneeravr.ipAvr2018.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2018.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2018.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2018.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2019.label = Pioneer AVR over IP 2019 +thing-type.pioneeravr.ipAvr2019.description = Control a 2019 Pioneer AVR (VSX-833, VSX-933, VSX-LX103, VSX-LX303, VSX-LX503) over IP +thing-type.pioneeravr.ipAvr2019.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2019.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2019.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2019.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvr2020.label = Pioneer AVR over IP 2020 +thing-type.pioneeravr.ipAvr2020.description = Control a 2020 Pioneer AVR (VSX-534, VSX-534D, VSX-934, VSX-LX104, VSX-LX304, VSX-LX504) over IP +thing-type.pioneeravr.ipAvr2020.group.zone1.label = Zone 1 +thing-type.pioneeravr.ipAvr2020.group.zone2.label = Zone 2 +thing-type.pioneeravr.ipAvr2020.group.zone3.label = Zone 3 +thing-type.pioneeravr.ipAvr2020.group.zone4.label = HD Zone +thing-type.pioneeravr.ipAvrUnsupported.label = Pioneer AVR over IP (unsupported) +thing-type.pioneeravr.ipAvrUnsupported.description = Control a Pioneer AVR over IP for models that are not officially supported. You may experience some odd behaviors. +thing-type.pioneeravr.serialAvr.label = Pioneer AVR over Serial +thing-type.pioneeravr.serialAvr.description = Control a Pioneer AVR over a Serial port (RS-232). + +# thing types config + +thing-type.config.pioneeravr.ipAvr.address.label = Address +thing-type.config.pioneeravr.ipAvr.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2014.address.label = Address +thing-type.config.pioneeravr.ipAvr2014.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2014.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2014.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2015.address.label = Address +thing-type.config.pioneeravr.ipAvr2015.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2015.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2015.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2016.address.label = Address +thing-type.config.pioneeravr.ipAvr2016.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2016.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2016.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2017.address.label = Address +thing-type.config.pioneeravr.ipAvr2017.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2017.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2017.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2018.address.label = Address +thing-type.config.pioneeravr.ipAvr2018.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2018.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2018.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2019.address.label = Address +thing-type.config.pioneeravr.ipAvr2019.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2019.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2019.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvr2020.address.label = Address +thing-type.config.pioneeravr.ipAvr2020.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvr2020.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvr2020.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.ipAvrUnsupported.address.label = Address +thing-type.config.pioneeravr.ipAvrUnsupported.address.description = The address of the Pioneer AVR to control. +thing-type.config.pioneeravr.ipAvrUnsupported.tcpPort.label = TCP Port +thing-type.config.pioneeravr.ipAvrUnsupported.tcpPort.description = The TCP port number used to connect to the AVR. +thing-type.config.pioneeravr.serialAvr.serialPort.label = Serial Port Name +thing-type.config.pioneeravr.serialAvr.serialPort.description = The Serial port name to use to connect to the AVR. + +# channel group types + +channel-group-type.pioneeravr.MCACCMemoryGroup.label = MCACC Memory +channel-group-type.pioneeravr.controls2014.label = Controls 2014 +channel-group-type.pioneeravr.controls2015.label = Controls 2015 +channel-group-type.pioneeravr.controls2016.label = Controls 2016 +channel-group-type.pioneeravr.controls2017.label = Controls 2017 +channel-group-type.pioneeravr.controls2018.label = Controls 2018 +channel-group-type.pioneeravr.controls2019.label = Controls 2019 +channel-group-type.pioneeravr.controls2020.label = Controls 2020 +channel-group-type.pioneeravr.displayInformationGroup.label = Display +channel-group-type.pioneeravr.hdZoneControls2014.label = HD Zone Controls 2014 +channel-group-type.pioneeravr.hdZoneControls2015.label = HD Zone Controls 2015 +channel-group-type.pioneeravr.hdZoneControls2016.label = HD Zone Controls 2016 +channel-group-type.pioneeravr.hdZoneControls2017.label = HD Zone Controls 2017 +channel-group-type.pioneeravr.hdZoneControls2018.label = HD Zone Controls 2018 +channel-group-type.pioneeravr.hdZoneControls2019.label = HD Zone Controls 2019 +channel-group-type.pioneeravr.hdZoneControls2020.label = HD Zone Controls 2020 +channel-group-type.pioneeravr.zoneControls.label = Zone Controls +channel-group-type.pioneeravr.zoneControls2014.label = Zone Controls 2014 +channel-group-type.pioneeravr.zoneControls2015.label = Zone Controls 2015 +channel-group-type.pioneeravr.zoneControls2016.label = Zone Controls 2016 +channel-group-type.pioneeravr.zoneControls2017.label = Zone Controls 2017 +channel-group-type.pioneeravr.zoneControls2018.label = Zone Controls 2018 +channel-group-type.pioneeravr.zoneControls2019.label = Zone Controls 2019 +channel-group-type.pioneeravr.zoneControls2020.label = Zone Controls 2020 + +# channel types + +channel-type.pioneeravr.displayInformationChannel.label = Display +channel-type.pioneeravr.displayInformationChannel.description = Display the information displayed on the AVR front screen +channel-type.pioneeravr.listeningModeChannel.label = Listening Mode +channel-type.pioneeravr.listeningModeChannel.description = Set the listening mode +channel-type.pioneeravr.listeningModeChannel.state.option.0001 = STEREO (cyclic) +channel-type.pioneeravr.listeningModeChannel.state.option.0010 = STANDARD (cyclic) +channel-type.pioneeravr.listeningModeChannel.state.option.0009 = STEREO (direct set) +channel-type.pioneeravr.listeningModeChannel.state.option.0011 = (2ch source) +channel-type.pioneeravr.listeningModeChannel.state.option.0013 = PRO LOGIC2 MOVIE +channel-type.pioneeravr.listeningModeChannel.state.option.0018 = PRO LOGIC2x MOVIE +channel-type.pioneeravr.listeningModeChannel.state.option.0014 = PRO LOGIC2 MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0019 = PRO LOGIC2x MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0015 = PRO LOGIC2 GAME +channel-type.pioneeravr.listeningModeChannel.state.option.0020 = PRO LOGIC2x GAME +channel-type.pioneeravr.listeningModeChannel.state.option.0031 = PRO LOGIC2z HEIGHT +channel-type.pioneeravr.listeningModeChannel.state.option.0032 = WIDE SURROUND MOVIE +channel-type.pioneeravr.listeningModeChannel.state.option.0033 = WIDE SURROUND MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0012 = PRO LOGIC +channel-type.pioneeravr.listeningModeChannel.state.option.0016 = Neo:6 CINEMA +channel-type.pioneeravr.listeningModeChannel.state.option.0017 = Neo:6 MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0037 = Neo:X CINEMA +channel-type.pioneeravr.listeningModeChannel.state.option.0038 = Neo:X MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0039 = Neo:X GAME +channel-type.pioneeravr.listeningModeChannel.state.option.0040 = Dolby Surround +channel-type.pioneeravr.listeningModeChannel.state.option.0041 = EXTENDED STEREO +channel-type.pioneeravr.listeningModeChannel.state.option.0021 = (Multi ch source) Channel base straight decode +channel-type.pioneeravr.listeningModeChannel.state.option.0022 = (Multi ch source)+DOLBY EX +channel-type.pioneeravr.listeningModeChannel.state.option.0023 = (Multi ch source)+PRO LOGIC2x MOVIE +channel-type.pioneeravr.listeningModeChannel.state.option.0024 = (Multi ch source)+PRO LOGIC2x MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0034 = (Multi-ch Source)+PRO LOGIC2z HEIGHT +channel-type.pioneeravr.listeningModeChannel.state.option.0035 = (Multi-ch Source)+WIDE SURROUND MOVIE +channel-type.pioneeravr.listeningModeChannel.state.option.0036 = (Multi-ch Source)+WIDE SURROUND MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0025 = (Multi ch source)DTS-ES Neo:6 +channel-type.pioneeravr.listeningModeChannel.state.option.0026 = (Multi ch source)DTS-ES matrix +channel-type.pioneeravr.listeningModeChannel.state.option.0027 = (Multi ch source)DTS-ES discrete +channel-type.pioneeravr.listeningModeChannel.state.option.0030 = (Multi ch source)DTS-ES 8ch discrete +channel-type.pioneeravr.listeningModeChannel.state.option.0043 = (Multi ch source)+Neo:X CINEMA +channel-type.pioneeravr.listeningModeChannel.state.option.0044 = (Multi ch source)+Neo:X MUSIC +channel-type.pioneeravr.listeningModeChannel.state.option.0045 = (Multi ch source)+Neo:X GAME +channel-type.pioneeravr.listeningModeChannel.state.option.0050 = (Multi ch source)+Dolby Surround +channel-type.pioneeravr.listeningModeChannel.state.option.0100 = ADVANCED SURROUND (cyclic) +channel-type.pioneeravr.listeningModeChannel.state.option.0101 = ACTION +channel-type.pioneeravr.listeningModeChannel.state.option.0103 = DRAMA +channel-type.pioneeravr.listeningModeChannel.state.option.0118 = ADVANCED GAME +channel-type.pioneeravr.listeningModeChannel.state.option.0117 = SPORTS +channel-type.pioneeravr.listeningModeChannel.state.option.0107 = CLASSICAL +channel-type.pioneeravr.listeningModeChannel.state.option.0110 = ROCK/POP +channel-type.pioneeravr.listeningModeChannel.state.option.0003 = Front Stage Surround Advance +channel-type.pioneeravr.listeningModeChannel.state.option.0200 = ECO MODE (cyclic) +channel-type.pioneeravr.listeningModeChannel.state.option.0212 = ECO MODE 1 +channel-type.pioneeravr.listeningModeChannel.state.option.0213 = ECO MODE 2 +channel-type.pioneeravr.listeningModeChannel.state.option.0153 = RETRIEVER AIR +channel-type.pioneeravr.listeningModeChannel.state.option.0113 = PHONES SURROUND +channel-type.pioneeravr.listeningModeChannel.state.option.0005 = AUTO SURR/STREAM DIRECT (cyclic) +channel-type.pioneeravr.listeningModeChannel.state.option.0006 = AUTO SURROUND +channel-type.pioneeravr.listeningModeChannel.state.option.0151 = Auto Level Control (A.L.C.) +channel-type.pioneeravr.listeningModeChannel.state.option.0007 = DIRECT +channel-type.pioneeravr.listeningModeChannel.state.option.0008 = PURE DIRECT +channel-type.pioneeravr.listeningModeChannel.state.option.0152 = OPTIMUM SURROUND +channel-type.pioneeravr.muteChannel.label = Mute +channel-type.pioneeravr.muteChannel.description = Enable/Disable Mute on the AVR +channel-type.pioneeravr.playingListeningModeChannel.label = Playing Listening Mode +channel-type.pioneeravr.playingListeningModeChannel.description = Display the effective listening mode +channel-type.pioneeravr.powerChannel.label = Power +channel-type.pioneeravr.powerChannel.description = Power ON/OFF the AVR +channel-type.pioneeravr.setInputSourceChannel.label = Input Source +channel-type.pioneeravr.setInputSourceChannel.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel.state.option.05 = TV/SAT +channel-type.pioneeravr.setInputSourceChannel.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel.state.option.10 = VIDEO 1 +channel-type.pioneeravr.setInputSourceChannel.state.option.14 = VIDEO 2 +channel-type.pioneeravr.setInputSourceChannel.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceChannel.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel.state.option.18 = XM RADIO +channel-type.pioneeravr.setInputSourceChannel.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel.state.option.03 = CD-R/TAPE +channel-type.pioneeravr.setInputSourceChannel.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceChannel.state.option.27 = SIRIUS +channel-type.pioneeravr.setInputSourceChannel2014.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2014.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2014.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2014.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2014.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2014.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2014.state.option.10 = VIDEO 1 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.35 = HDMI 8 +channel-type.pioneeravr.setInputSourceChannel2014.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceChannel2014.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2014.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2014.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2014.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2014.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2014.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2014.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2014.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2014.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2014.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2014.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceChannel2014.state.option.48 = MHL +channel-type.pioneeravr.setInputSourceChannel2015.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2015.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2015.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2015.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2015.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2015.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2015.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2015.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceChannel2015.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2015.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2015.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2015.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2015.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2015.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2015.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2015.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2015.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2015.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2015.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2015.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceChannel2016.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2016.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2016.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2016.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2016.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2016.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2016.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2016.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceChannel2016.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2016.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2016.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2016.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2016.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2016.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2016.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2016.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2016.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2016.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2016.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2016.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceChannel2017.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2017.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2017.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2017.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2017.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2017.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2017.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2017.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceChannel2017.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2017.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2017.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2017.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2017.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2017.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2017.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2017.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2017.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2017.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2017.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2017.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceChannel2018.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2018.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2018.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2018.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2018.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2018.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2018.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2018.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceChannel2018.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2018.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2018.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2018.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2018.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2018.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2018.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2018.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2018.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2018.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2018.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2018.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceChannel2019.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2019.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2019.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2019.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2019.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2019.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2019.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2019.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceChannel2019.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2019.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2019.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2019.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2019.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2019.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2019.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2019.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2019.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2019.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2019.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2019.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceChannel2020.label = Input Source +channel-type.pioneeravr.setInputSourceChannel2020.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceChannel2020.state.option.25 = BD +channel-type.pioneeravr.setInputSourceChannel2020.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceChannel2020.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceChannel2020.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceChannel2020.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceChannel2020.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceChannel2020.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceChannel2020.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceChannel2020.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceChannel2020.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceChannel2020.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceChannel2020.state.option.05 = TV +channel-type.pioneeravr.setInputSourceChannel2020.state.option.01 = CD +channel-type.pioneeravr.setInputSourceChannel2020.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceChannel2020.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceChannel2020.state.option.00 = PHONO +channel-type.pioneeravr.setInputSourceChannel2020.state.option.12 = MULTI CH IN +channel-type.pioneeravr.setInputSourceChannel2020.state.option.33 = ADAPTER PORT/BT Audio +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.35 = HDMI 8 +channel-type.pioneeravr.setInputSourceHDZoneChannel2014.state.option.48 = MHL +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2015.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2016.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2017.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2018.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2019.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.label = Input Source +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.25 = BD +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.19 = HDMI 1 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.20 = HDMI 2 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.21 = HDMI 3 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.22 = HDMI 4 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.23 = HDMI 5 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.24 = HDMI 6 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.34 = HDMI 7 +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceHDZoneChannel2020.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2014.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2014.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.10 = VIDEO 1 +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2014.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2015.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2015.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2015.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2016.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2016.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2016.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2017.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2017.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2017.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2018.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2018.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2018.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2019.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2019.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2019.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setInputSourceZoneChannel2020.label = Input Source +channel-type.pioneeravr.setInputSourceZoneChannel2020.description = Select the input source of the AVR +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.04 = DVD +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.06 = SAT/CBL +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.15 = DVR/BDR +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.26 = HOME MEDIA GALLERY +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.38 = Internet Radio +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.40 = SiriusXM +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.41 = PANDORA +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.57 = Spotify +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.44 = Media Server +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.45 = Favourites +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.17 = iPod/USB +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.13 = USB-DAC +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.05 = TV +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.01 = CD +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.02 = TUNER +channel-type.pioneeravr.setInputSourceZoneChannel2020.state.option.33 = ADAPTER PORT +channel-type.pioneeravr.setMCACCMemoryChannel.label = MCACC Memory +channel-type.pioneeravr.setMCACCMemoryChannel.description = Set the MCACC Memory profile +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0000 = MCACC MEMORY (cyclic) +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0001 = MEMORY 1 +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0002 = MEMORY 2 +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0003 = MEMORY 3 +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0004 = MEMORY 4 +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0005 = MEMORY 5 +channel-type.pioneeravr.setMCACCMemoryChannel.state.option.0006 = MEMORY 6 +channel-type.pioneeravr.volumeChannelDb.label = Volume +channel-type.pioneeravr.volumeChannelDb.description = Set the volume level (dB) +channel-type.pioneeravr.volumeChannelDimmer.label = Volume +channel-type.pioneeravr.volumeChannelDimmer.description = Increase/Decrease the volume (%) and mute/un-mute diff --git a/bundles/org.openhab.binding.pjlinkdevice/src/main/resources/OH-INF/i18n/pjLinkDevice.properties b/bundles/org.openhab.binding.pjlinkdevice/src/main/resources/OH-INF/i18n/pjLinkDevice.properties new file mode 100644 index 0000000000000..6e53a01672e4f --- /dev/null +++ b/bundles/org.openhab.binding.pjlinkdevice/src/main/resources/OH-INF/i18n/pjLinkDevice.properties @@ -0,0 +1,55 @@ +# binding + +binding.pjLinkDevice.name = PJLinkDevice Binding +binding.pjLinkDevice.description = This binding can control PJLink compatible devices. The PJLink protocol was mainly standardized for digital projectors, but some other types of devices also use it, in particular TV screens. + +# thing types + +thing-type.pjLinkDevice.pjLinkDevice.label = PJLink Device +thing-type.pjLinkDevice.pjLinkDevice.description = A PJLink compatible device, e.g. a digital projector + +# thing types config + +thing-type.config.pjLinkDevice.pjLinkDevice.adminPassword.label = Password +thing-type.config.pjLinkDevice.pjLinkDevice.adminPassword.description = The password of the PJLink device. +thing-type.config.pjLinkDevice.pjLinkDevice.autoReconnectInterval.label = Auto Reconnect Interval +thing-type.config.pjLinkDevice.pjLinkDevice.autoReconnectInterval.description = Seconds between connection retries when connection to the PJLink device has been lost, 0 means never retry, minimum 30s +thing-type.config.pjLinkDevice.pjLinkDevice.group.basic.label = Basic Settings +thing-type.config.pjLinkDevice.pjLinkDevice.group.refresh.label = Polling Settings +thing-type.config.pjLinkDevice.pjLinkDevice.group.refresh.description = Use these settings to configure how the status of the PJLink device will be refreshed +thing-type.config.pjLinkDevice.pjLinkDevice.ipAddress.label = IP Address +thing-type.config.pjLinkDevice.pjLinkDevice.ipAddress.description = The address of the PJLink device to control. +thing-type.config.pjLinkDevice.pjLinkDevice.refreshInputChannel.label = Poll for Selected Input Channel +thing-type.config.pjLinkDevice.pjLinkDevice.refreshInputChannel.description = Enable polling for the selected input channel. Only considered if the refreshInterval interval is greater than zero. +thing-type.config.pjLinkDevice.pjLinkDevice.refreshInterval.label = Refresh Interval (s) +thing-type.config.pjLinkDevice.pjLinkDevice.refreshInterval.description = How often to poll the device state (in seconds). A value of zero will disable polling. +thing-type.config.pjLinkDevice.pjLinkDevice.refreshLampState.label = Poll for Lamp State +thing-type.config.pjLinkDevice.pjLinkDevice.refreshLampState.description = Enable polling for the lamp state. Only considered if the refresh interval is greater than zero. +thing-type.config.pjLinkDevice.pjLinkDevice.refreshMute.label = Poll for Mute State +thing-type.config.pjLinkDevice.pjLinkDevice.refreshMute.description = Enable polling for the mute state. Only considered if the refreshInterval interval is greater than zero. +thing-type.config.pjLinkDevice.pjLinkDevice.refreshPower.label = Poll for Power State +thing-type.config.pjLinkDevice.pjLinkDevice.refreshPower.description = Enable polling for the power state. Only considered if the refreshInterval interval is greater than zero. +thing-type.config.pjLinkDevice.pjLinkDevice.tcpPort.label = TCP Port +thing-type.config.pjLinkDevice.pjLinkDevice.tcpPort.description = The TCP port of the PJLink device to control. + +# channel types + +channel-type.pjLinkDevice.audioMute.label = Audio Mute +channel-type.pjLinkDevice.audioMute.description = Select the audio mute status +channel-type.pjLinkDevice.input.label = Input +channel-type.pjLinkDevice.input.description = Select the input signal to use +channel-type.pjLinkDevice.lampActive.label = Lamp Active +channel-type.pjLinkDevice.lampActive.description = Is the lamp in use? +channel-type.pjLinkDevice.lampHours.label = Lamp Hours +channel-type.pjLinkDevice.lampHours.description = How long the lamp has been in use (in hours) +channel-type.pjLinkDevice.power.label = Power +channel-type.pjLinkDevice.power.description = Power ON/OFF the projector +channel-type.pjLinkDevice.videoMute.label = Video Mute +channel-type.pjLinkDevice.videoMute.description = Select the video mute status + +# channel types config + +channel-type.config.pjLinkDevice.lampActive.lampNumber.label = Lamp Number +channel-type.config.pjLinkDevice.lampActive.lampNumber.description = Show activity for this lamp +channel-type.config.pjLinkDevice.lampHours.lampNumber.label = Lamp Number +channel-type.config.pjLinkDevice.lampHours.lampNumber.description = Show used hours for this lamp diff --git a/bundles/org.openhab.binding.plclogo/src/main/resources/OH-INF/i18n/plclogo.properties b/bundles/org.openhab.binding.plclogo/src/main/resources/OH-INF/i18n/plclogo.properties new file mode 100644 index 0000000000000..c0e3a79d26d8a --- /dev/null +++ b/bundles/org.openhab.binding.plclogo/src/main/resources/OH-INF/i18n/plclogo.properties @@ -0,0 +1,77 @@ +# binding + +binding.plclogo.name = PLCLogo Binding +binding.plclogo.description = This binding provides native support for Siemens LOGO! PLC. + +# thing types + +thing-type.plclogo.analog.label = Analog Blocks +thing-type.plclogo.analog.description = Siemens LOGO! analog input/output blocks +thing-type.plclogo.datetime.label = Date/Time Block +thing-type.plclogo.datetime.description = Siemens LOGO! date/time block +thing-type.plclogo.device.label = LOGO! PLC +thing-type.plclogo.device.description = Siemens LOGO! PLC +thing-type.plclogo.digital.label = Digital Blocks +thing-type.plclogo.digital.description = Siemens LOGO! digital input/output blocks +thing-type.plclogo.memory.label = Memory Address +thing-type.plclogo.memory.description = Siemens LOGO! memory address +thing-type.plclogo.pulse.label = Pulse Block +thing-type.plclogo.pulse.description = Siemens LOGO! pulse virtual block + +# thing types config + +thing-type.config.plclogo.analog.force.label = Force Channels Update +thing-type.config.plclogo.analog.force.description = Propagate channels update to openHAB whether value changed or not +thing-type.config.plclogo.analog.kind.label = LOGO! Analog Block Kind +thing-type.config.plclogo.analog.kind.description = LOGO! analog block kind +thing-type.config.plclogo.analog.threshold.label = Smallest Value Change to Sent +thing-type.config.plclogo.analog.threshold.description = Smallest value change will be sent to openHAB +thing-type.config.plclogo.bridge.address.label = Network Address +thing-type.config.plclogo.bridge.address.description = Network address of the PLC. +thing-type.config.plclogo.bridge.family.label = LOGO! Family +thing-type.config.plclogo.bridge.family.description = LOGO! PLC hardware family version +thing-type.config.plclogo.bridge.family.option.0BA7 = 0BA7 +thing-type.config.plclogo.bridge.family.option.0BA8 = 0BA8 +thing-type.config.plclogo.bridge.localTSAP.label = Local TSAP +thing-type.config.plclogo.bridge.localTSAP.description = Local TSAP of the client as hex string +thing-type.config.plclogo.bridge.refresh.label = Refresh Interval +thing-type.config.plclogo.bridge.refresh.description = Milliseconds between reread data from PLC. +thing-type.config.plclogo.bridge.remoteTSAP.label = Remote TSAP +thing-type.config.plclogo.bridge.remoteTSAP.description = Remote TSAP of the client as hex string +thing-type.config.plclogo.datetime.block.label = LOGO! Memory Address +thing-type.config.plclogo.datetime.block.description = LOGO! memory address +thing-type.config.plclogo.datetime.force.label = Force Channels Update +thing-type.config.plclogo.datetime.force.description = Propagate channels update to openHAB whether value changed or not +thing-type.config.plclogo.datetime.type.label = Send Value As +thing-type.config.plclogo.datetime.type.description = Interpret received channel value as date or time +thing-type.config.plclogo.datetime.type.option.date = date +thing-type.config.plclogo.datetime.type.option.time = time +thing-type.config.plclogo.digital.force.label = Force Channels Update +thing-type.config.plclogo.digital.force.description = Propagate channels update to openHAB whether value changed or not +thing-type.config.plclogo.digital.kind.label = LOGO! Digital Block Kind +thing-type.config.plclogo.digital.kind.description = LOGO! digital block kind +thing-type.config.plclogo.memory.block.label = LOGO! Memory Address +thing-type.config.plclogo.memory.block.description = LOGO! memory address +thing-type.config.plclogo.memory.force.label = Force Channel Update +thing-type.config.plclogo.memory.force.description = Update of the channel be should propagated to openHAB +thing-type.config.plclogo.memory.threshold.label = Smallest Value Change to Sent +thing-type.config.plclogo.memory.threshold.description = Smallest value change will be sent to openHAB +thing-type.config.plclogo.pulse.block.label = LOGO! Memory Address +thing-type.config.plclogo.pulse.block.description = LOGO! memory address +thing-type.config.plclogo.pulse.observe.label = LOGO! Block/Memory Address +thing-type.config.plclogo.pulse.observe.description = LOGO! block or memory address to observe +thing-type.config.plclogo.pulse.pulse.label = Pulse Length +thing-type.config.plclogo.pulse.pulse.description = Time to wait before state reset + +# channel types + +channel-type.plclogo.contact.label = Digital Input +channel-type.plclogo.datetime.label = Analog Date/Time +channel-type.plclogo.diagnostic.label = Diagnostic +channel-type.plclogo.diagnostic.description = The diagnostic reported by Siemens LOGO! +channel-type.plclogo.number.label = Analog Number +channel-type.plclogo.rtc.label = Real Time Clock +channel-type.plclogo.rtc.description = The value of Siemens LOGO! real time clock +channel-type.plclogo.switch.label = Digital Output +channel-type.plclogo.weekday.label = Day of Week +channel-type.plclogo.weekday.description = The day of week reported by Siemens LOGO! diff --git a/bundles/org.openhab.binding.plugwiseha/src/main/resources/OH-INF/i18n/plugwiseha.properties b/bundles/org.openhab.binding.plugwiseha/src/main/resources/OH-INF/i18n/plugwiseha.properties new file mode 100644 index 0000000000000..dba13ae55db8d --- /dev/null +++ b/bundles/org.openhab.binding.plugwiseha/src/main/resources/OH-INF/i18n/plugwiseha.properties @@ -0,0 +1,94 @@ +# binding + +binding.plugwiseha.name = Plugwise Home Automation Binding +binding.plugwiseha.description = This binding supports the Plugwise Home Automation 'Adam' gateway. It allows users to access temperature controls of zones defined on the gateway + +# thing types + +thing-type.plugwiseha.appliance_boiler.label = Boiler +thing-type.plugwiseha.appliance_boiler.description = A Plugwise Home Automation controlled boiler +thing-type.plugwiseha.appliance_pump.label = Central Heating Pump +thing-type.plugwiseha.appliance_pump.description = A Plugwise Home Automation smart plug switch connected to a central heating pump +thing-type.plugwiseha.appliance_thermostat.label = Plugwise Room Thermostat +thing-type.plugwiseha.appliance_thermostat.description = A Plugwise Home Automation room thermostat +thing-type.plugwiseha.appliance_valve.label = Plugwise Radiator Valve +thing-type.plugwiseha.appliance_valve.description = A Plugwise Home Automation radiator valve +thing-type.plugwiseha.gateway.label = Plugwise Home Automation Bridge +thing-type.plugwiseha.gateway.description = The Plugwise Home Automation Bridge is needed to connect to the Adam boiler gateway +thing-type.plugwiseha.zone.label = Plugwise Zone +thing-type.plugwiseha.zone.description = A Plugwise Home Automation heating zone + +# thing types config + +bridge-type.config.plugwiseha.gateway.host.label = Host +bridge-type.config.plugwiseha.gateway.host.description = Hostname or IP address of the boiler gateway +bridge-type.config.plugwiseha.gateway.refresh.label = Refresh Interval +bridge-type.config.plugwiseha.gateway.refresh.description = Refresh interval in seconds +bridge-type.config.plugwiseha.gateway.smileId.label = Smile ID +bridge-type.config.plugwiseha.gateway.smileId.description = The Smile ID is the 8 letter code on the sticker on the back of the Adam boiler gateway +bridge-type.config.plugwiseha.gateway.username.label = Username +bridge-type.config.plugwiseha.gateway.username.description = Adam HA gateway username (default: smile) +thing-type.config.plugwiseha.appliance_boiler.id.label = ID +thing-type.config.plugwiseha.appliance_boiler.id.description = Appliance ID +thing-type.config.plugwiseha.appliance_pump.id.label = ID +thing-type.config.plugwiseha.appliance_pump.id.description = Appliance ID +thing-type.config.plugwiseha.appliance_thermostat.id.label = ID +thing-type.config.plugwiseha.appliance_thermostat.id.description = Appliance ID +thing-type.config.plugwiseha.appliance_thermostat.lowBatteryPercentage.label = Low Battery Threshold +thing-type.config.plugwiseha.appliance_thermostat.lowBatteryPercentage.description = Battery charge remaining at which to trigger battery low warning +thing-type.config.plugwiseha.appliance_valve.id.label = ID +thing-type.config.plugwiseha.appliance_valve.id.description = Appliance ID +thing-type.config.plugwiseha.appliance_valve.lowBatteryPercentage.label = Low Battery Threshold +thing-type.config.plugwiseha.appliance_valve.lowBatteryPercentage.description = Battery charge remaining at which to trigger battery low warning +thing-type.config.plugwiseha.zone.id.label = ID +thing-type.config.plugwiseha.zone.id.description = Location ID for the zone + +# channel types + +channel-type.plugwiseha.boilerTemperature.label = Boiler Temperature +channel-type.plugwiseha.boilerTemperature.description = Gets the temperature of this boiler +channel-type.plugwiseha.chState.label = Central Heating Active +channel-type.plugwiseha.chState.description = Is the boiler active for central heating, On or OFF +channel-type.plugwiseha.coolingState.label = Cooling State +channel-type.plugwiseha.coolingState.description = Is the boiler active for cooling, On or OFF +channel-type.plugwiseha.dhwComfortMode.label = Domestic Hot Water Comfort Mode +channel-type.plugwiseha.dhwComfortMode.description = Is the boiler's domestic hot water mode set to comfort, On or OFF +channel-type.plugwiseha.dhwSetpoint.label = Domestic Hot Water Setpoint Temperature +channel-type.plugwiseha.dhwSetpoint.description = Gets the temperature of the domestic hot water setpoint +channel-type.plugwiseha.dhwState.label = Domestic Hot Water Active +channel-type.plugwiseha.dhwState.description = Is the boiler active for domestic hot water, On or OFF +channel-type.plugwiseha.dhwTemperature.label = Domestic Hot Water Temperature +channel-type.plugwiseha.dhwTemperature.description = Gets the temperature of the domestic hot water +channel-type.plugwiseha.flameState.label = Flame State +channel-type.plugwiseha.flameState.description = Is the boiler's flame active, On or OFF +channel-type.plugwiseha.intendedBoilerTemp.label = Intended Boiler Temperature +channel-type.plugwiseha.intendedBoilerTemp.description = Gets the intended temperature of this boiler +channel-type.plugwiseha.intendedHeatingState.label = Intended Heating State +channel-type.plugwiseha.intendedHeatingState.description = Should the boiler be active for central heating, On or OFF +channel-type.plugwiseha.lock.label = Lock +channel-type.plugwiseha.lock.description = Locks the switch state of the Plugwise Smart plug +channel-type.plugwiseha.maxBoilerTemperature.label = Max Boiler Temperature +channel-type.plugwiseha.maxBoilerTemperature.description = Gets the maximum temperature ofthis boiler +channel-type.plugwiseha.modulationLevel.label = Modulelation Level +channel-type.plugwiseha.modulationLevel.description = Gets the modulation level of this boiler +channel-type.plugwiseha.offsetTemperature.label = Thermostat Temperature Offset +channel-type.plugwiseha.offsetTemperature.description = Gets or sets the temperature offset for this thermostat +channel-type.plugwiseha.otAppFaultCode.label = Opentherm Application Faultcode +channel-type.plugwiseha.otAppFaultCode.description = Gets the Opentherm application fault code of this boiler +channel-type.plugwiseha.otOEMFaultCode.label = OEM Fault Code +channel-type.plugwiseha.otOEMFaultCode.description = Gets the OEM fault code of this boiler +channel-type.plugwiseha.power.label = Power +channel-type.plugwiseha.power.description = Switch the Plugwise Smart plug ON or OFF +channel-type.plugwiseha.powerUsage.label = Power Usage +channel-type.plugwiseha.preHeat.label = Preheat +channel-type.plugwiseha.preHeat.description = Switch the preheating of a zone ON or OFF +channel-type.plugwiseha.presetScene.label = Preset Scene +channel-type.plugwiseha.presetScene.description = Gets the preset scene of the zone +channel-type.plugwiseha.setpointTemperature.label = Setpoint Temperature +channel-type.plugwiseha.setpointTemperature.description = Gets or sets the set point of this zone +channel-type.plugwiseha.temperature.label = Zone Temperature +channel-type.plugwiseha.temperature.description = Gets the temperature of this zone +channel-type.plugwiseha.valvePosition.label = Valve Position +channel-type.plugwiseha.valvePosition.description = Gets the position of the valve (0% closed, 100% open) +channel-type.plugwiseha.waterPressure.label = Water Pressure +channel-type.plugwiseha.waterPressure.description = Gets the water pressure of the boiler diff --git a/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/i18n/pulseaudio.properties b/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/i18n/pulseaudio.properties new file mode 100644 index 0000000000000..62471edcad5e4 --- /dev/null +++ b/bundles/org.openhab.binding.pulseaudio/src/main/resources/OH-INF/i18n/pulseaudio.properties @@ -0,0 +1,73 @@ +# binding + +binding.pulseaudio.name = Pulseaudio Binding +binding.pulseaudio.description = This is the binding for Pulseaudio. + +# binding config + +binding.config.pulseaudio.sink.label = Import Sinks +binding.config.pulseaudio.sink.description = Activate the import of sink elements. +binding.config.pulseaudio.sinkInput.label = Import Sink Inputs +binding.config.pulseaudio.sinkInput.description = Activate the import of sink-input elements. +binding.config.pulseaudio.source.label = Import Sources +binding.config.pulseaudio.source.description = Activate the import of source elements. +binding.config.pulseaudio.sourceOutput.label = Import Source Outputs +binding.config.pulseaudio.sourceOutput.description = Activate the import of source-output elements. + +# thing types + +thing-type.pulseaudio.bridge.label = Pulseaudio Server +thing-type.pulseaudio.bridge.description = This bridge represents a pulseaudio server. +thing-type.pulseaudio.combinedSink.label = A Pulseaudio Combined Sink +thing-type.pulseaudio.combinedSink.description = represents a group of pulseaudio sinks, which are combined for synchronous audio +thing-type.pulseaudio.sink.label = A Pulseaudio Sink +thing-type.pulseaudio.sink.description = represents a pulseaudio sink +thing-type.pulseaudio.sinkInput.label = A Pulseaudio Sink-input +thing-type.pulseaudio.sinkInput.description = represents a pulseaudio sink-input +thing-type.pulseaudio.source.label = A Pulseaudio Source +thing-type.pulseaudio.source.description = represents a pulseaudio source +thing-type.pulseaudio.sourceOutput.label = A Pulseaudio Source Output +thing-type.pulseaudio.sourceOutput.description = represents a pulseaudio source-output + +# thing types config + +thing-type.config.pulseaudio.bridge.host.label = Hostname +thing-type.config.pulseaudio.bridge.host.description = Hostname or IP address of the pulseaudio server +thing-type.config.pulseaudio.bridge.port.label = Port +thing-type.config.pulseaudio.bridge.port.description = Port of the pulseaudio server +thing-type.config.pulseaudio.bridge.refreshInterval.label = Refresh Interval +thing-type.config.pulseaudio.bridge.refreshInterval.description = The refresh interval in ms which is used to poll given pulseaudio server. +thing-type.config.pulseaudio.combinedSink.name.label = Name +thing-type.config.pulseaudio.combinedSink.name.description = The name of the combined sink. +thing-type.config.pulseaudio.sink.activateSimpleProtocolSink.label = Create an Audio Sink with simple-protocol-tcp +thing-type.config.pulseaudio.sink.activateSimpleProtocolSink.description = Activation of a corresponding sink in OpenHAB (module-simple-protocol-tcp must be available on the pulseaudio server) +thing-type.config.pulseaudio.sink.name.label = Name +thing-type.config.pulseaudio.sink.name.description = The name of one specific device. +thing-type.config.pulseaudio.sink.simpleProtocolSinkIdleTimeout.label = Idle Timeout +thing-type.config.pulseaudio.sink.simpleProtocolSinkIdleTimeout.description = Timeout in ms after which the connection will be closed when no stream is running. This ensures that your speaker is not on all the time and the pulseaudio sink can go to idle mode. -1 for no disconnection. +thing-type.config.pulseaudio.sink.simpleProtocolSinkPort.label = Simple Protocol Port +thing-type.config.pulseaudio.sink.simpleProtocolSinkPort.description = Default Port to allocate for use by module-simple-protocol-tcp on the pulseaudio server +thing-type.config.pulseaudio.sinkInput.name.label = Name +thing-type.config.pulseaudio.sinkInput.name.description = The name of one specific device. +thing-type.config.pulseaudio.source.name.label = Name +thing-type.config.pulseaudio.source.name.description = The name of one specific device. +thing-type.config.pulseaudio.sourceOutput.name.label = Name +thing-type.config.pulseaudio.sourceOutput.name.description = The name of one specific device. + +# channel types + +channel-type.pulseaudio.mute.label = Mute +channel-type.pulseaudio.mute.description = Mutes the device +channel-type.pulseaudio.routeToSink.label = Route to Sink +channel-type.pulseaudio.routeToSink.description = Shows the sink a sink-input is currently routed to +channel-type.pulseaudio.slaves.label = Slaves +channel-type.pulseaudio.slaves.description = Slave sinks of a combined sink +channel-type.pulseaudio.state.label = State +channel-type.pulseaudio.state.description = Current state of the device +channel-type.pulseaudio.state.state.option.SUSPENDED = Suspended +channel-type.pulseaudio.state.state.option.IDLE = Idle +channel-type.pulseaudio.state.state.option.RUNNING = Running +channel-type.pulseaudio.state.state.option.CORKED = Corked +channel-type.pulseaudio.state.state.option.DRAINED = Drained +channel-type.pulseaudio.volume.label = Volume +channel-type.pulseaudio.volume.description = Volume of an audio item in percent diff --git a/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus.properties b/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus.properties new file mode 100644 index 0000000000000..927884f80873e --- /dev/null +++ b/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus.properties @@ -0,0 +1,72 @@ +# binding + +binding.qbus.name = Qbus Binding +binding.qbus.description = This is the binding for the Qbus home automation system. Qbus is a system made and developed in Belgium (https://www.qbus.be/nl-nl) + +# thing types + +thing-type.qbus.bridge.label = Qbus Bridge +thing-type.qbus.bridge.description = This bridge represents a Qbus client +thing-type.qbus.co2.label = CO2 +thing-type.qbus.co2.description = Qbus CO2 +thing-type.qbus.dimmer.label = Dimmer +thing-type.qbus.dimmer.description = Qbus Dimmer Output +thing-type.qbus.onOff.label = Switch +thing-type.qbus.onOff.description = Bistabiel-Mono-Timer-Interval Output +thing-type.qbus.rollershutter.label = RollerShutter +thing-type.qbus.rollershutter.description = Qbus shutter (ROL02P) control +thing-type.qbus.rollershutter_slats.label = RollerShutter (With Slats) +thing-type.qbus.rollershutter_slats.description = Qbus shutter with slats control +thing-type.qbus.scene.label = Scene +thing-type.qbus.scene.description = Qbus Scene +thing-type.qbus.thermostat.label = Thermostat +thing-type.qbus.thermostat.description = Qbus Thermostat + +# thing types config + +thing-type.config.qbus.bridge.addr.label = Hostname +thing-type.config.qbus.bridge.addr.description = IP address or hostname of Qbus server, usually 'localhost' +thing-type.config.qbus.bridge.port.label = Bridge Port +thing-type.config.qbus.bridge.port.description = Port to communicate with Qbus server, default 8447 +thing-type.config.qbus.bridge.serverCheck.label = Server Check +thing-type.config.qbus.bridge.serverCheck.description = Time to check communication with Qbus Server (min), default 10. If set to 0 or left empty, no refresh will be scheduled +thing-type.config.qbus.bridge.sn.label = Serial Number +thing-type.config.qbus.bridge.sn.description = Serial number of the CTD controller +thing-type.config.qbus.co2.co2Id.label = Qbus CO2 ID +thing-type.config.qbus.co2.co2Id.description = Qbus CO2 ID +thing-type.config.qbus.dimmer.dimmerId.label = Output ID +thing-type.config.qbus.dimmer.dimmerId.description = Qbus Dimmer ID +thing-type.config.qbus.dimmer.step.label = Step Value +thing-type.config.qbus.dimmer.step.description = Step value used for increase/decrease of dimmer brightness, default 10% +thing-type.config.qbus.onOff.bistabielId.label = Qbus ID +thing-type.config.qbus.onOff.bistabielId.description = Qbus Bistabiel ID +thing-type.config.qbus.rollershutter.rolId.label = Rol ID +thing-type.config.qbus.rollershutter.rolId.description = Qbus Rol Id +thing-type.config.qbus.rollershutter_slats.rolId.label = Rol ID +thing-type.config.qbus.rollershutter_slats.rolId.description = Qbus Rol Id +thing-type.config.qbus.scene.sceneId.label = Qbus Scene ID +thing-type.config.qbus.scene.sceneId.description = Qbus Scene ID +thing-type.config.qbus.thermostat.thermostatId.label = Thermostat ID +thing-type.config.qbus.thermostat.thermostatId.description = Qbus Thermostat ID + +# channel types + +channel-type.qbus.co2.label = CO2 +channel-type.qbus.co2.description = CO2 value for Qbus +channel-type.qbus.measured.label = Measured +channel-type.qbus.measured.description = Temperature Measured by Thermostat +channel-type.qbus.mode.label = Mode +channel-type.qbus.mode.description = Thermostat Mode +channel-type.qbus.mode.state.option.0 = Manual +channel-type.qbus.mode.state.option.1 = Freeze +channel-type.qbus.mode.state.option.2 = Economic +channel-type.qbus.mode.state.option.3 = Comfort +channel-type.qbus.mode.state.option.4 = Night +channel-type.qbus.rollershutter.label = Rollershutter +channel-type.qbus.rollershutter.description = Rollershutter Control for Qbus +channel-type.qbus.scene.label = Scene +channel-type.qbus.scene.description = Scene Control for Qbus +channel-type.qbus.setpoint.label = Setpoint +channel-type.qbus.setpoint.description = Setpoint Temperature of Thermostat +channel-type.qbus.slats.label = Slatcontrol +channel-type.qbus.slats.description = Slatcontrol for Qbus diff --git a/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/i18n/radiothermostat.properties b/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/i18n/radiothermostat.properties new file mode 100644 index 0000000000000..999cfd7098830 --- /dev/null +++ b/bundles/org.openhab.binding.radiothermostat/src/main/resources/OH-INF/i18n/radiothermostat.properties @@ -0,0 +1,78 @@ +# binding + +binding.radiothermostat.name = Radio Thermostat Binding +binding.radiothermostat.description = Controls the RadioThermostat model CT30, CT50 or CT80 via the built-in WIFI module + +# thing types + +thing-type.radiothermostat.rtherm.label = Thermostat +thing-type.radiothermostat.rtherm.description = CT30, CT50/3M50 or CT80 Wi-Fi Thermostat + +# thing types config + +thing-type.config.radiothermostat.rtherm.clockSync.label = Enable Thermostat Clock Sync +thing-type.config.radiothermostat.rtherm.clockSync.description = Optional Flag to snyc the thermostat's clock with the host system clock +thing-type.config.radiothermostat.rtherm.disableLogs.label = Disable Retrieval of Run-time Data +thing-type.config.radiothermostat.rtherm.disableLogs.description = Optional Flag to Disable the Retrieval of Run-time Data from the Thermostat +thing-type.config.radiothermostat.rtherm.hostName.label = Thermostat Host Name/IP Address +thing-type.config.radiothermostat.rtherm.hostName.description = Host Name or IP Address of the Thermostat +thing-type.config.radiothermostat.rtherm.isCT80.label = Enable CT80 Thermostat Options +thing-type.config.radiothermostat.rtherm.isCT80.description = Optional Flag to Enable Additional Features Only Available on the CT80 Thermostat +thing-type.config.radiothermostat.rtherm.logRefresh.label = Run-time Log Refresh Interval +thing-type.config.radiothermostat.rtherm.logRefresh.description = Specifies the Run-time Log and Humidity Refresh Interval in Minutes +thing-type.config.radiothermostat.rtherm.refresh.label = Refresh Interval +thing-type.config.radiothermostat.rtherm.refresh.description = Specifies the Refresh Interval in Minutes +thing-type.config.radiothermostat.rtherm.setpointMode.label = Setpoint Mode +thing-type.config.radiothermostat.rtherm.setpointMode.description = Run in absolute or temporary setpoint mode +thing-type.config.radiothermostat.rtherm.setpointMode.option.absolute = Absolute +thing-type.config.radiothermostat.rtherm.setpointMode.option.temporary = Temporary + +# channel types + +channel-type.radiothermostat.dt_stamp.label = Thermostat Date +channel-type.radiothermostat.dt_stamp.description = The Current Day of the Week and Time Reported by the Thermostat +channel-type.radiothermostat.fan_mode.label = Fan Mode +channel-type.radiothermostat.fan_mode.description = The Current Operating Mode of the Fan +channel-type.radiothermostat.fan_status.label = Fan Status +channel-type.radiothermostat.fan_status.description = Indicates the Current Fan Status of the HVAC System +channel-type.radiothermostat.hold.label = Hold +channel-type.radiothermostat.hold.description = Indicates If the Current Set Point Temperature Is to Be Held Indefinitely +channel-type.radiothermostat.humidity.label = Humidity +channel-type.radiothermostat.humidity.description = The Current Humidity Reading of the Thermostat +channel-type.radiothermostat.mode.label = Mode +channel-type.radiothermostat.mode.description = The Current Operating Mode of the HVAC System +channel-type.radiothermostat.mode.state.option.0 = Off +channel-type.radiothermostat.mode.state.option.1 = Heat +channel-type.radiothermostat.mode.state.option.2 = Cool +channel-type.radiothermostat.mode.state.option.3 = Auto +channel-type.radiothermostat.override.label = Override +channel-type.radiothermostat.override.description = Indicates If the Normal Program Setpoint Has Been Manually Overriden +channel-type.radiothermostat.program_mode.label = Program Mode +channel-type.radiothermostat.program_mode.description = The Program Schedule That the Thermostat Is Running +channel-type.radiothermostat.program_mode.state.option.-1 = None +channel-type.radiothermostat.program_mode.state.option.0 = Program A +channel-type.radiothermostat.program_mode.state.option.1 = Program B +channel-type.radiothermostat.program_mode.state.option.2 = Vacation +channel-type.radiothermostat.program_mode.state.option.3 = Holiday +channel-type.radiothermostat.remote_temp.label = Remote Temperature +channel-type.radiothermostat.remote_temp.description = The remote temperature takes the place of the ambient temperature as read by the local thermostat temperature sensor +channel-type.radiothermostat.status.label = Status +channel-type.radiothermostat.status.description = Indicates the Current Running Status of the HVAC System +channel-type.radiothermostat.t_day.label = Day +channel-type.radiothermostat.t_day.description = The Current Day of the Week Reported by the Thermostat +channel-type.radiothermostat.t_hour.label = Hour +channel-type.radiothermostat.t_hour.description = The Current Hour of the Day Reported by the Thermostat +channel-type.radiothermostat.t_minute.label = Minute +channel-type.radiothermostat.t_minute.description = The Current Minute Past the Hour Reported by the Thermostat +channel-type.radiothermostat.temp-sp.label = Setpoint +channel-type.radiothermostat.temp-sp.description = The Current Temperature Set Point of the Thermostat +channel-type.radiothermostat.temp-temperature.label = Temperature +channel-type.radiothermostat.temp-temperature.description = The Current Temperature Reading of the Thermostat +channel-type.radiothermostat.today_cool_runtime.label = Today's Cooling Runtime +channel-type.radiothermostat.today_cool_runtime.description = The Number of Minutes of Cooling Run-time Today +channel-type.radiothermostat.today_heat_runtime.label = Today's Heating Runtime +channel-type.radiothermostat.today_heat_runtime.description = The Number of Minutes of Heating Run-time Today +channel-type.radiothermostat.yesterday_cool_runtime.label = Yesterday's Cooling Runtime +channel-type.radiothermostat.yesterday_cool_runtime.description = The Number of Minutes of Cooling Run-time Yesterday +channel-type.radiothermostat.yesterday_heat_runtime.label = Yesterday's Heating Runtime +channel-type.radiothermostat.yesterday_heat_runtime.description = The Number of Minutes of Heating Run-time Yesterday diff --git a/bundles/org.openhab.binding.regoheatpump/src/main/resources/OH-INF/i18n/regoheatpump.properties b/bundles/org.openhab.binding.regoheatpump/src/main/resources/OH-INF/i18n/regoheatpump.properties new file mode 100644 index 0000000000000..c5f2c9fa14477 --- /dev/null +++ b/bundles/org.openhab.binding.regoheatpump/src/main/resources/OH-INF/i18n/regoheatpump.properties @@ -0,0 +1,191 @@ +# binding + +binding.regoheatpump.name = RegoHeatPump Binding +binding.regoheatpump.description = The Rego controller based heat pumps binding. + +# thing types + +thing-type.regoheatpump.ipHusdata.label = Husdata Interface +thing-type.regoheatpump.ipHusdata.description = Access heat pump over Husdata interface connected via TCP/IP +thing-type.regoheatpump.ipRego6xx.label = Heat Pump +thing-type.regoheatpump.ipRego6xx.description = Manage Rego 6xx based heat pump over TCP/IP +thing-type.regoheatpump.serialHusdata.label = Husdata Interface +thing-type.regoheatpump.serialHusdata.description = Access heat pump over Husdata interface connected via serial port +thing-type.regoheatpump.serialRego6xx.label = Heat Pump +thing-type.regoheatpump.serialRego6xx.description = Manage Rego 6xx based heat pump over serial port + +# thing types config + +thing-type.config.regoheatpump.ipHusdata.address.label = Address +thing-type.config.regoheatpump.ipHusdata.address.description = The IP address of the Rego to control. +thing-type.config.regoheatpump.ipHusdata.tcpPort.label = TCP Port +thing-type.config.regoheatpump.ipHusdata.tcpPort.description = The TCP port number used to connect to the Rego controller. +thing-type.config.regoheatpump.ipRego6xx.address.label = Address +thing-type.config.regoheatpump.ipRego6xx.address.description = The IP address of the Rego to control. +thing-type.config.regoheatpump.ipRego6xx.refreshInterval.label = Refresh Interval +thing-type.config.regoheatpump.ipRego6xx.refreshInterval.description = Refresh interval in seconds. +thing-type.config.regoheatpump.ipRego6xx.tcpPort.label = TCP Port +thing-type.config.regoheatpump.ipRego6xx.tcpPort.description = The TCP port number used to connect to the Rego controller. +thing-type.config.regoheatpump.serialHusdata.portName.label = Port +thing-type.config.regoheatpump.serialHusdata.portName.description = The serial port used to connect to the Husdata interface. +thing-type.config.regoheatpump.serialRego6xx.portName.label = Port +thing-type.config.regoheatpump.serialRego6xx.portName.description = The serial port used to connect to the Rego controller. +thing-type.config.regoheatpump.serialRego6xx.refreshInterval.label = Refresh Interval +thing-type.config.regoheatpump.serialRego6xx.refreshInterval.description = Refresh interval in seconds. + +# channel group types + +channel-group-type.regoheatpump.controlData.label = Control Data +channel-group-type.regoheatpump.deviceValues.label = Device Values +channel-group-type.regoheatpump.frontPanel.label = Front Panel +channel-group-type.regoheatpump.operatingTimes.label = Operating Times +channel-group-type.regoheatpump.sensorValues.label = Sensor Values +channel-group-type.regoheatpump.settings.label = Settings +channel-group-type.regoheatpump.status.label = Status + +# channel types + +channel-type.regoheatpump.addHeatInOperationDHW.label = Add. Heat in Oper. - DHW +channel-type.regoheatpump.addHeatInOperationDHW.description = Additional heat in operation heating DHW - number of hours +channel-type.regoheatpump.addHeatInOperationRAD.label = Add. Heat in Oper. - Radiators +channel-type.regoheatpump.addHeatInOperationRAD.description = Additional heat in operation heating radiators - number of hours +channel-type.regoheatpump.addHeatPowerEnergy.label = Additional Heat Power +channel-type.regoheatpump.addHeatPowerPercent.label = Additional Heat Power +channel-type.regoheatpump.additionalHeat3kWState.label = Additional Heat 3kW +channel-type.regoheatpump.additionalHeat6kWState.label = Additional Heat 6kW +channel-type.regoheatpump.additionalHeatLamp.label = Additional Heat Lamp +channel-type.regoheatpump.additionalHeatLamp.description = Lamp on when the heat pump is using additional heat from an electric cassette +channel-type.regoheatpump.adjCurveAt0.label = Adjust Heat Curve At 0 °C +channel-type.regoheatpump.adjCurveAt0.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAt10.label = Adjust Heat Curve At 10 °C +channel-type.regoheatpump.adjCurveAt10.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAt15.label = Adjust Heat Curve At 15 °C +channel-type.regoheatpump.adjCurveAt15.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAt20.label = Adjust Heat Curve At 20 °C +channel-type.regoheatpump.adjCurveAt20.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAt5.label = Adjust Heat Curve At 5 °C +channel-type.regoheatpump.adjCurveAt5.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus10.label = Adjust Heat Curve At -10 °C +channel-type.regoheatpump.adjCurveAtMinus10.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus15.label = Adjust Heat Curve At -15 °C +channel-type.regoheatpump.adjCurveAtMinus15.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus20.label = Adjust Heat Curve At -20 °C +channel-type.regoheatpump.adjCurveAtMinus20.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus25.label = Adjust Heat Curve At -25 °C +channel-type.regoheatpump.adjCurveAtMinus25.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus30.label = Adjust Heat Curve At -30 °C +channel-type.regoheatpump.adjCurveAtMinus30.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus35.label = Adjust Heat Curve At -35 °C +channel-type.regoheatpump.adjCurveAtMinus35.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.adjCurveAtMinus5.label = Adjust Heat Curve At -5 °C +channel-type.regoheatpump.adjCurveAtMinus5.description = Heat curve can be adjusted up or down every fifth outdoor degree. The purpose of breaking the curve is to be able to influence the heat pump's heat production at extra sensitive outdoor temperatures +channel-type.regoheatpump.airIntakeTemp.label = Air Intake +channel-type.regoheatpump.alarmLamp.label = Alarm Lamp +channel-type.regoheatpump.alarmLamp.description = Lamp indicates that a fault has occurred in the heat pump +channel-type.regoheatpump.alarmState.label = Alarm +channel-type.regoheatpump.coldFluidInTemp.label = Cold Fluid In +channel-type.regoheatpump.coldFluidInTemp.description = Temperature of the heat transfer fluid that is led into the heat pump from the bore hole or the ground +channel-type.regoheatpump.coldFluidOutTemp.label = Cold Fluid Out +channel-type.regoheatpump.coldFluidOutTemp.description = Temperature of the heat transfer fluid that is led out of the heat pump to the bore hole or the ground +channel-type.regoheatpump.coldFluidPumpState.label = Cold Fluid Pump +channel-type.regoheatpump.compressorSpeed.label = Compressor Speed +channel-type.regoheatpump.compressorState.label = Compressor +channel-type.regoheatpump.compressorTemp.label = Compressor +channel-type.regoheatpump.compressorTemp.description = Compressor’s working temperature +channel-type.regoheatpump.crankCaseHeaterState.label = Crank Case Heater +channel-type.regoheatpump.curveInflByInTemp.label = Room Sensor Influence +channel-type.regoheatpump.curveInflByInTemp.description = Set how much the room sensor should influence the heat curve +channel-type.regoheatpump.elMeter1.label = Collected Pulses Meter 1 +channel-type.regoheatpump.elMeter2.label = Collected Pulses Meter 2 +channel-type.regoheatpump.externalHotWaterTemp.label = External Hot Water +channel-type.regoheatpump.externalHotWaterTemp.description = Temperature in the external hot water cylinder +channel-type.regoheatpump.fanState.label = Fan +channel-type.regoheatpump.heatCurve.label = Heat Curve +channel-type.regoheatpump.heatCurve.description = Heat curve influences the heat pump’s production of heat +channel-type.regoheatpump.heatCurve2.label = Heat Curve 2 +channel-type.regoheatpump.heatCurve2FineAdj.label = Heat Curve 2 Fine Tune +channel-type.regoheatpump.heatCurve2FineAdj.description = Fine-tuning means that you offset the heat curve 2 in parallel +channel-type.regoheatpump.heatCurveCouplingDiff.label = Heat Curve Coupling Diff +channel-type.regoheatpump.heatCurveFineAdj.label = Heat Curve Fine Tune +channel-type.regoheatpump.heatCurveFineAdj.description = Fine-tuning means that you offset the heat curve in parallel +channel-type.regoheatpump.heatFluidInTemp.label = Heat Fluid In +channel-type.regoheatpump.heatFluidInTemp.description = Temperature of the water that is led into the heat pump +channel-type.regoheatpump.heatFluidOutTemp.label = Heat Fluid Out +channel-type.regoheatpump.heatFluidOutTemp.description = Temperature of the radiator water as it leaves the heat pump +channel-type.regoheatpump.heatFluidPumpState.label = Heat Fluid Pump +channel-type.regoheatpump.heatPumpInOperationDHW.label = Heat Pump in Oper. - DHW +channel-type.regoheatpump.heatPumpInOperationDHW.description = Heat pump in operation while heating DHW - number of hours +channel-type.regoheatpump.heatPumpInOperationRAD.label = Heat Pump in Oper. - Radiators +channel-type.regoheatpump.heatPumpInOperationRAD.description = Heat pump in operation while heating radiators - number of hours +channel-type.regoheatpump.heatPumpLamp.label = Heat Pump Lamp +channel-type.regoheatpump.heatPumpLamp.description = Lamp on when the heat pump (compressor) is operational +channel-type.regoheatpump.heatingCableState.label = Heating Cable +channel-type.regoheatpump.highPressostatState.label = High Pressostat +channel-type.regoheatpump.hotWaterLamp.label = Hot Water Lamp +channel-type.regoheatpump.hotWaterLamp.description = Lamp on when the heat pump is heating water in the heater +channel-type.regoheatpump.hotWaterOff.label = Maximal Hot Water +channel-type.regoheatpump.hotWaterOff.description = Maximal (stop) hot water temperature +channel-type.regoheatpump.hotWaterOn.label = Minimal Hot Water +channel-type.regoheatpump.hotWaterOn.description = Minimal (start) hot water temperature +channel-type.regoheatpump.hotWaterTarget.label = Hot Water Target +channel-type.regoheatpump.hotWaterTarget.description = Desired radiator return temperature +channel-type.regoheatpump.hotWaterTargetHysteresis.label = Hot Water Hysteresis +channel-type.regoheatpump.hotWaterTargetHysteresis.description = The function measures below and above the value set in hotWaterTarget +channel-type.regoheatpump.hotWaterTemp.label = Hot Water +channel-type.regoheatpump.hotWaterTemp.description = Temperature in the hot water cylinder +channel-type.regoheatpump.indoorTemp.label = Indoor +channel-type.regoheatpump.indoorTemp.description = Present temperature in the room where the sensor is fitted +channel-type.regoheatpump.indoorTempSetting.label = Indoor Target +channel-type.regoheatpump.indoorTempSetting.description = Desired temperature in the room where the sensor is fitted +channel-type.regoheatpump.lastErrorTimestamp.label = Last Error Date +channel-type.regoheatpump.lastErrorTimestamp.description = Information about when last alarm occurred +channel-type.regoheatpump.lastErrorTimestamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS +channel-type.regoheatpump.lastErrorType.label = Last Error Type +channel-type.regoheatpump.lastErrorType.description = Information about the alarm type that occured last +channel-type.regoheatpump.lastErrorType.state.option.0 = Sensor radiator return (GT1) +channel-type.regoheatpump.lastErrorType.state.option.1 = Outdoor sensor (GT2) +channel-type.regoheatpump.lastErrorType.state.option.2 = Sensor hot water (GT3) +channel-type.regoheatpump.lastErrorType.state.option.3 = Mixing valve sensor (GT4) +channel-type.regoheatpump.lastErrorType.state.option.4 = Room sensor (GT5) +channel-type.regoheatpump.lastErrorType.state.option.5 = Sensor compressor (GT6) +channel-type.regoheatpump.lastErrorType.state.option.6 = Sensor heat transfer fluid out (GT8) +channel-type.regoheatpump.lastErrorType.state.option.7 = Sensor heat transfer fluid in (GT9) +channel-type.regoheatpump.lastErrorType.state.option.8 = Sensor cold transfer fluid in (GT10) +channel-type.regoheatpump.lastErrorType.state.option.9 = Sensor cold transfer fluid in (GT11) +channel-type.regoheatpump.lastErrorType.state.option.10 = Compressor circuit switch +channel-type.regoheatpump.lastErrorType.state.option.11 = Electrical cassette +channel-type.regoheatpump.lastErrorType.state.option.12 = HTF C=pump switch (MB2) +channel-type.regoheatpump.lastErrorType.state.option.13 = Low pressure switch (LP) +channel-type.regoheatpump.lastErrorType.state.option.14 = High pressure switch (HP) +channel-type.regoheatpump.lastErrorType.state.option.15 = High return HP (GT9) +channel-type.regoheatpump.lastErrorType.state.option.16 = HTF out max (GT8) +channel-type.regoheatpump.lastErrorType.state.option.17 = HTF in under limit (GT10) +channel-type.regoheatpump.lastErrorType.state.option.18 = HTF out under limit (GT11) +channel-type.regoheatpump.lastErrorType.state.option.19 = Compressor superheat (GT6) +channel-type.regoheatpump.lastErrorType.state.option.20 = Three phase incorrect order +channel-type.regoheatpump.lastErrorType.state.option.21 = Power failure +channel-type.regoheatpump.lastErrorType.state.option.22 = High delta GT8/GT9 +channel-type.regoheatpump.lowPressostatState.label = Low Pressostat +channel-type.regoheatpump.outdoorTemp.label = Outdoor +channel-type.regoheatpump.outdoorTemp.description = The outdoor temperature. Determines how much heating the heat pump should produce +channel-type.regoheatpump.poolTemp.label = Pool +channel-type.regoheatpump.powerLamp.label = Power Lamp +channel-type.regoheatpump.powerLamp.description = Lamp on when the heat pump is on +channel-type.regoheatpump.radiatorForwardTarget.label = Radiator Forward Target +channel-type.regoheatpump.radiatorForwardTarget.description = Calculated desired radiator forward temperature +channel-type.regoheatpump.radiatorForwardTemp.label = Radiator Forward +channel-type.regoheatpump.radiatorForwardTemp.description = Temperature on the flow water in the circuit +channel-type.regoheatpump.radiatorPumpState.label = Radiator Pump +channel-type.regoheatpump.radiatorReturnOff.label = Maximal Radiator Return +channel-type.regoheatpump.radiatorReturnOff.description = Calculated maximal (stop) radiator return temperature +channel-type.regoheatpump.radiatorReturnOn.label = Minimal Radiator Return +channel-type.regoheatpump.radiatorReturnOn.description = Calculated minimal (start) radiator return temperature +channel-type.regoheatpump.radiatorReturnTarget.label = Radiator Return Target +channel-type.regoheatpump.radiatorReturnTarget.description = Calculated desired radiator return temperature +channel-type.regoheatpump.radiatorReturnTemp.label = Radiator Return +channel-type.regoheatpump.radiatorReturnTemp.description = Temperature of the water that returns to the heat pump from the radiators +channel-type.regoheatpump.summerDisconnection.label = Summer Disconnection +channel-type.regoheatpump.summerDisconnection.description = The function means the heat pump only produces hot water when the outdoor temperature rises above the set value +channel-type.regoheatpump.switchValve2State.label = Switch Valve 2 +channel-type.regoheatpump.switchValveState.label = Switch Valve +channel-type.regoheatpump.switchValveState.description = The valve switches between heating the heating water and hot water diff --git a/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/i18n/renault.properties b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/i18n/renault.properties new file mode 100644 index 0000000000000..2269672aa0474 --- /dev/null +++ b/bundles/org.openhab.binding.renault/src/main/resources/OH-INF/i18n/renault.properties @@ -0,0 +1,57 @@ +# binding + +binding.renault.name = Renault Binding +binding.renault.description = This is the binding for Renault electric cars. + +# thing types + +thing-type.renault.car.label = Renault Car +thing-type.renault.car.description = A MyRenault registered car. + +# thing types config + +thing-type.config.renault.car.locale.label = MyRenault Location +thing-type.config.renault.car.locale.description = The country (and language combination) that best fits with your MyRenault registered car. +thing-type.config.renault.car.locale.option.de_AT = Austria +thing-type.config.renault.car.locale.option.nl_BE = Belgium (Dutch) +thing-type.config.renault.car.locale.option.fr_BE = Belgium (French) +thing-type.config.renault.car.locale.option.bg_BG = Bulgaria +thing-type.config.renault.car.locale.option.hr_HR = Croatia +thing-type.config.renault.car.locale.option.cs_CZ = Czech +thing-type.config.renault.car.locale.option.da_DK = Denmark +thing-type.config.renault.car.locale.option.it_IT = Italy +thing-type.config.renault.car.locale.option.fi_FI = Finland +thing-type.config.renault.car.locale.option.fr_FR = France +thing-type.config.renault.car.locale.option.de_DE = Germany +thing-type.config.renault.car.locale.option.hu_HU = Hungary +thing-type.config.renault.car.locale.option.en_IE = Ireland +thing-type.config.renault.car.locale.option.fr_LU = Luxembourg +thing-type.config.renault.car.locale.option.es_MX = Mexico +thing-type.config.renault.car.locale.option.nl_NL = Netherlands +thing-type.config.renault.car.locale.option.no_NO = Norway +thing-type.config.renault.car.locale.option.pl_PL = Poland +thing-type.config.renault.car.locale.option.pt_PT = Portugal +thing-type.config.renault.car.locale.option.ro_RO = Romania +thing-type.config.renault.car.locale.option.ru_RU = Russian +thing-type.config.renault.car.locale.option.sk_SK = Slovakia +thing-type.config.renault.car.locale.option.sl_SI = Slovenia +thing-type.config.renault.car.locale.option.es_ES = Spain +thing-type.config.renault.car.locale.option.sv_SE = Sweden +thing-type.config.renault.car.locale.option.fr_CH = Switzerland (French) +thing-type.config.renault.car.locale.option.de_CH = Switzerland (German) +thing-type.config.renault.car.locale.option.it_CH = Switzerland (Italian) +thing-type.config.renault.car.locale.option.en_GB = United Kingdom +thing-type.config.renault.car.myRenaultPassword.label = MyRenault Password +thing-type.config.renault.car.myRenaultUsername.label = MyRenault Username +thing-type.config.renault.car.refreshInterval.label = Refresh Interval +thing-type.config.renault.car.refreshInterval.description = Interval the car is polled in minutes. +thing-type.config.renault.car.vin.label = VIN +thing-type.config.renault.car.vin.description = Vehicle Identification Number + +# channel types + +channel-type.renault.hvacstatus.label = HVAC Status +channel-type.renault.image.label = Image URL +channel-type.renault.image.description = Image URL of MyRenault +channel-type.renault.odometer.label = Odometer +channel-type.renault.odometer.description = Total distance travelled diff --git a/bundles/org.openhab.binding.resol/src/main/resources/OH-INF/i18n/resol.properties b/bundles/org.openhab.binding.resol/src/main/resources/OH-INF/i18n/resol.properties new file mode 100644 index 0000000000000..6500ec0ca55bb --- /dev/null +++ b/bundles/org.openhab.binding.resol/src/main/resources/OH-INF/i18n/resol.properties @@ -0,0 +1,90 @@ +# binding + +binding.resol.name = Resol Binding +binding.resol.description = This is the binding for Resol solar and system controllers (including branded versions). + +# thing types + +thing-type.resol.device.label = Resol Device +thing-type.resol.device.description = Solar or system controller (or any other real device on the VBus) from Resol. +thing-type.resol.emulatedEM.label = Emulated EM Device +thing-type.resol.emulatedEM.description = Emulation of an Extension Module (EM) device which can be connected through the VBUS to Resol controllers which support the EM devices. Replaces a physically available EM by openHAB. +thing-type.resol.emulatedEM.channel.bas_mode_1.label = Operating Mode 1 +thing-type.resol.emulatedEM.channel.bas_mode_2.label = Operating Mode 2 +thing-type.resol.emulatedEM.channel.bas_mode_3.label = Operating Mode 3 +thing-type.resol.emulatedEM.channel.bas_mode_4.label = Operating Mode 4 +thing-type.resol.emulatedEM.channel.bas_mode_5.label = Operating Mode 5 +thing-type.resol.emulatedEM.channel.bas_mode_6.label = Operating Mode 6 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_1.label = Temperature Adjustment 1 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_2.label = Temperature Adjustment 2 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_3.label = Temperature Adjustment 3 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_4.label = Temperature Adjustment 4 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_5.label = Temperature Adjustment 5 +thing-type.resol.emulatedEM.channel.bas_temp_adjust_6.label = Temperature Adjustment 6 +thing-type.resol.emulatedEM.channel.relay_1.label = Relay 1 +thing-type.resol.emulatedEM.channel.relay_2.label = Relay 2 +thing-type.resol.emulatedEM.channel.relay_3.label = Relay 3 +thing-type.resol.emulatedEM.channel.relay_4.label = Relay 4 +thing-type.resol.emulatedEM.channel.relay_5.label = Relay 5 +thing-type.resol.emulatedEM.channel.resistor_1.label = Resistor 1 +thing-type.resol.emulatedEM.channel.resistor_2.label = Resistor 2 +thing-type.resol.emulatedEM.channel.resistor_3.label = Resistor 3 +thing-type.resol.emulatedEM.channel.resistor_4.label = Resistor 4 +thing-type.resol.emulatedEM.channel.resistor_5.label = Resistor 5 +thing-type.resol.emulatedEM.channel.resistor_6.label = Resistor 6 +thing-type.resol.emulatedEM.channel.switch_1.label = Switch 1 +thing-type.resol.emulatedEM.channel.switch_2.label = Switch 2 +thing-type.resol.emulatedEM.channel.switch_3.label = Switch 3 +thing-type.resol.emulatedEM.channel.switch_4.label = Switch 4 +thing-type.resol.emulatedEM.channel.switch_5.label = Switch 5 +thing-type.resol.emulatedEM.channel.switch_6.label = Switch 6 +thing-type.resol.emulatedEM.channel.temperature_1.label = Temperature 1 +thing-type.resol.emulatedEM.channel.temperature_2.label = Temperature 2 +thing-type.resol.emulatedEM.channel.temperature_3.label = Temperature 3 +thing-type.resol.emulatedEM.channel.temperature_4.label = Temperature 4 +thing-type.resol.emulatedEM.channel.temperature_5.label = Temperature 5 +thing-type.resol.emulatedEM.channel.temperature_6.label = Temperature 6 +thing-type.resol.vbuslan.label = Bridge VBusLAN Adapter +thing-type.resol.vbuslan.description = This bridge represents the Resol VBus-LAN adapter which can be any device with a TCP/IP live port, either the standalone device VBus-LAN Adapter, KM2, DL2/3 or similar. + +# thing types config + +thing-type.config.resol.emulatedEM.deviceId.label = Module ID +thing-type.config.resol.emulatedEM.deviceId.description = The (sub-)address of the emulated EM device, usable range depends on the used controller. +thing-type.config.resol.vbuslan.adapterSerial.label = Adapter Serial Number +thing-type.config.resol.vbuslan.adapterSerial.description = The serial number of the adapter (informative). +thing-type.config.resol.vbuslan.ipAddress.label = IP Address +thing-type.config.resol.vbuslan.ipAddress.description = The IP address of the of the VBus-LAN gateway. +thing-type.config.resol.vbuslan.password.label = Password +thing-type.config.resol.vbuslan.password.description = The password for the VBusLAN connection. +thing-type.config.resol.vbuslan.port.label = Live Data Port +thing-type.config.resol.vbuslan.port.description = Port for live data on the VBUS-LAN gateway. +thing-type.config.resol.vbuslan.refreshInterval.label = Refresh Interval +thing-type.config.resol.vbuslan.refreshInterval.description = Refresh time in seconds to check the connection to the VBus gateway. Data updates are propagated to openHAB independently from this setting as soon as they are received on the VBus. + +# channel types + +channel-type.resol.None.label = Any +channel-type.resol.NoneHidden.label = Any +channel-type.resol.datetime.label = Time +channel-type.resol.datetime.description = Time and date. +channel-type.resol.operationmode.label = Operating Mode +channel-type.resol.operationmode.description = Virtual operating mode of the heating circuit controlled by the emulated BAS (RCP12 room control unit). +channel-type.resol.operationmode.state.option.0 = OFF +channel-type.resol.operationmode.state.option.1 = Summer +channel-type.resol.operationmode.state.option.2 = Night +channel-type.resol.operationmode.state.option.3 = Party +channel-type.resol.operationmode.state.option.4 = Automatic +channel-type.resol.relay.label = Relay State +channel-type.resol.relay.description = Virtual relay output, will be set by the controller and can be used to communicate data from the Resol controller to openHAB. +channel-type.resol.resistance.label = Resistance +channel-type.resol.resistance.description = Virtual resistance input. +channel-type.resol.switch.label = Switch +channel-type.resol.switch.description = Virtual switch input. +channel-type.resol.temperature.label = Temperature +channel-type.resol.temperature.description = Virtual temperature sensor input. +channel-type.resol.temperatureAdjust.label = Temperature Adjustment +channel-type.resol.temperatureAdjust.description = Virtual temperature offset on heating circuit of an emulated BAS (RCP12 room control unit). +channel-type.resol.time.label = Time +channel-type.resol.weektime.label = Time +channel-type.resol.weektime.description = Time and day of week. diff --git a/bundles/org.openhab.binding.revogi/src/main/resources/OH-INF/i18n/revogi.properties b/bundles/org.openhab.binding.revogi/src/main/resources/OH-INF/i18n/revogi.properties new file mode 100644 index 0000000000000..fe91241154d33 --- /dev/null +++ b/bundles/org.openhab.binding.revogi/src/main/resources/OH-INF/i18n/revogi.properties @@ -0,0 +1,40 @@ +# binding + +binding.revogi.name = Revogi Binding +binding.revogi.description = This is the binding for Revogi devices. Revogi is a vendor of several smart home devices like light bulbs, power strips and sensors. + +# thing types + +thing-type.revogi.smartstrip.label = SmartStrip +thing-type.revogi.smartstrip.description = A Thing to control Revogi SmartStrip +thing-type.revogi.smartstrip.group.plug1.label = Plug 1 +thing-type.revogi.smartstrip.group.plug2.label = Plug 2 +thing-type.revogi.smartstrip.group.plug3.label = Plug 3 +thing-type.revogi.smartstrip.group.plug4.label = Plug 4 +thing-type.revogi.smartstrip.group.plug5.label = Plug 5 +thing-type.revogi.smartstrip.group.plug6.label = Plug 6 + +# thing types config + +thing-type.config.revogi.smartstrip.ipAddress.label = IP Address +thing-type.config.revogi.smartstrip.ipAddress.description = IP Address of your smart strip +thing-type.config.revogi.smartstrip.pollInterval.label = Poll Interval +thing-type.config.revogi.smartstrip.pollInterval.description = How often (seconds) should the smart strip status be polled? +thing-type.config.revogi.smartstrip.serialNumber.label = Serial Number +thing-type.config.revogi.smartstrip.serialNumber.description = Serial number of your smart strip. + +# channel group types + +channel-group-type.revogi.overallPlugActuator.label = Overall Plug Actuator +channel-group-type.revogi.overallPlugActuator.description = Switches all plugs +channel-group-type.revogi.plugActuator.label = Single Plug Actuator +channel-group-type.revogi.plugActuator.description = Switches a single plug and retrieve stats for it + +# channel types + +channel-type.revogi.amps.label = Current +channel-type.revogi.amps.description = Contains the current Amp value for the given plug +channel-type.revogi.single-plug.label = Switch +channel-type.revogi.single-plug.description = Switch a single plug +channel-type.revogi.watts.label = Power +channel-type.revogi.watts.description = Contains the current watt value for the given plug diff --git a/bundles/org.openhab.binding.rme/src/main/resources/OH-INF/i18n/rme.properties b/bundles/org.openhab.binding.rme/src/main/resources/OH-INF/i18n/rme.properties new file mode 100644 index 0000000000000..8af6d184796f9 --- /dev/null +++ b/bundles/org.openhab.binding.rme/src/main/resources/OH-INF/i18n/rme.properties @@ -0,0 +1,38 @@ +# binding + +binding.rme.name = openHAB RME Binding +binding.rme.description = This is the binding for RME Rain Manager. + +# thing types + +thing-type.rme.manager.label = RME Rain Manager +thing-type.rme.manager.description = The RME Rain Manager is a controllable water supply unit that can monitor a gauge in a cistern, and switch between rain water and city provided water +thing-type.rme.manager.channel.cisternblockedalarm.label = Cistern Blocked Alarm +thing-type.rme.manager.channel.cisternsupplyalarm.label = Cistern Supply Alarm +thing-type.rme.manager.channel.entrypump.label = Entry Pump Active +thing-type.rme.manager.channel.exitpump.label = Exit Pump Active +thing-type.rme.manager.channel.filtercleaning.label = Filter Cleaning Required +thing-type.rme.manager.channel.overflowalarm.label = Overflow Alarm +thing-type.rme.manager.channel.waterexchange.label = Water Exchange Active + +# thing types config + +thing-type.config.rme.manager.port.label = Serial Port +thing-type.config.rme.manager.port.description = Serial Port the RME Rain Manager is connected to + +# channel types + +channel-type.rme.mode.label = Operation Mode +channel-type.rme.mode.description = Indicates the operation mode of the RME Rain Manager +channel-type.rme.mode.state.option.Automatic = Automatic +channel-type.rme.mode.state.option.Manual = Manual +channel-type.rme.source.label = Water Source +channel-type.rme.source.description = Indicates water source used to supply water, e.g cistern or city +channel-type.rme.source.state.option.Rain = Rain +channel-type.rme.source.state.option.City = City +channel-type.rme.statusflag.label = Status Flag +channel-type.rme.statusflag.description = Status Flag of an RME operational parameter, e.g ON if set, OFF if unset +channel-type.rme.statusflag.state.option.ON = ON +channel-type.rme.statusflag.state.option.OFF = OFF +channel-type.rme.waterlevel.label = Water Level +channel-type.rme.waterlevel.description = Indicates the % the cistern is filled with water diff --git a/bundles/org.openhab.binding.robonect/src/main/resources/OH-INF/i18n/robonect.properties b/bundles/org.openhab.binding.robonect/src/main/resources/OH-INF/i18n/robonect.properties new file mode 100644 index 0000000000000..eba22b4f8d26d --- /dev/null +++ b/bundles/org.openhab.binding.robonect/src/main/resources/OH-INF/i18n/robonect.properties @@ -0,0 +1,95 @@ +# binding + +binding.robonect.name = Robonect Binding +binding.robonect.description = This is the binding for Robonect. + +# thing types + +thing-type.robonect.mower.label = Mower +thing-type.robonect.mower.description = Mower robot connected via robonect module +thing-type.robonect.mower.channel.last-error-code.label = Last Error Code +thing-type.robonect.mower.channel.last-error-code.description = The Error code of the last error occurred +thing-type.robonect.mower.channel.last-error-date.label = Last Error Date +thing-type.robonect.mower.channel.last-error-date.description = The date and time of the last error occurred +thing-type.robonect.mower.channel.last-error-message.label = Last Error Message +thing-type.robonect.mower.channel.last-error-message.description = The error message of the last error occurred + +# thing types config + +thing-type.config.robonect.mower.host.label = Host +thing-type.config.robonect.mower.host.description = Host name or network address of the Robonect module +thing-type.config.robonect.mower.offlineTimeout.label = Offline Timeout +thing-type.config.robonect.mower.offlineTimeout.description = The maximum time the mower may be offline before the offline trigger is triggered. +thing-type.config.robonect.mower.password.label = Password +thing-type.config.robonect.mower.password.description = The password if authentication has been enabled on the mower +thing-type.config.robonect.mower.pollInterval.label = Polling Interval +thing-type.config.robonect.mower.pollInterval.description = The interval for the binding to poll the mowers status information. +thing-type.config.robonect.mower.timezone.label = Timezone +thing-type.config.robonect.mower.timezone.description = The timezone configured on the robot (e.g. Europe/Berlin). +thing-type.config.robonect.mower.user.label = User +thing-type.config.robonect.mower.user.description = The user id if authentication has been enabled on the mower + +# channel types + +channel-type.robonect.commentType.label = Robonect Firmware Comment +channel-type.robonect.compiledType.label = Robonect Version +channel-type.robonect.distanceType.label = Status Distance +channel-type.robonect.distanceType.description = The distance the mower is away from the charging station when searching the remote start. +channel-type.robonect.durationType.label = Status Duration +channel-type.robonect.durationType.description = The number of seconds the mower is in the current status. +channel-type.robonect.errorCodeType.label = Error Code +channel-type.robonect.errorCodeType.description = Error code defined by the mower manufacturer +channel-type.robonect.errorDateType.label = Error Date +channel-type.robonect.errorDateType.description = The date and time the error occurred +channel-type.robonect.errorMessageType.label = Error Message +channel-type.robonect.errorMessageType.description = The error message +channel-type.robonect.hoursType.label = Total Mowing Hours +channel-type.robonect.hoursType.description = The number of total mowing hours +channel-type.robonect.humidityType.label = Humidity +channel-type.robonect.humidityType.description = The relative humidity in the mower in percent +channel-type.robonect.jobType.label = Mowing Job +channel-type.robonect.jobType.description = Starts a mowing job +channel-type.robonect.modeType.label = Mower Mode +channel-type.robonect.modeType.description = The mower mode +channel-type.robonect.modeType.state.option.AUTO = Auto +channel-type.robonect.modeType.state.option.HOME = Home +channel-type.robonect.modeType.state.option.MANUAL = Manual +channel-type.robonect.modeType.state.option.EOD = End of Day +channel-type.robonect.mowerStatusType.label = Mower Status +channel-type.robonect.mowerStatusType.description = The status of the mower +channel-type.robonect.mowerStatusType.state.option.0 = Detecting Status +channel-type.robonect.mowerStatusType.state.option.1 = Parking +channel-type.robonect.mowerStatusType.state.option.2 = Mowing +channel-type.robonect.mowerStatusType.state.option.3 = Search Charging Station +channel-type.robonect.mowerStatusType.state.option.4 = Charging +channel-type.robonect.mowerStatusType.state.option.5 = Searching +channel-type.robonect.mowerStatusType.state.option.6 = Unknown Status 6 +channel-type.robonect.mowerStatusType.state.option.7 = Error Status +channel-type.robonect.mowerStatusType.state.option.16 = Off +channel-type.robonect.mowerStatusType.state.option.17 = Sleeping +channel-type.robonect.mowerStatusType.state.option.99 = Unknown +channel-type.robonect.nameType.label = Mower Name +channel-type.robonect.nameType.description = The name of the mower +channel-type.robonect.nextTimerType.label = Next Timer Date +channel-type.robonect.nextTimerType.description = The next date the timer starts +channel-type.robonect.offlineTriggerType.label = Offline Trigger +channel-type.robonect.serialType.label = Robonect Serial Number +channel-type.robonect.startType.label = Start +channel-type.robonect.startType.description = On if started, Off if stopped +channel-type.robonect.temperatureType.label = Temperature +channel-type.robonect.temperatureType.description = The temperature inside the mower +channel-type.robonect.timerStatusType.label = Timer Status +channel-type.robonect.timerStatusType.description = The status of the timer +channel-type.robonect.timerStatusType.state.option.INACTIVE = Inactive +channel-type.robonect.timerStatusType.state.option.ACTIVE = Active +channel-type.robonect.timerStatusType.state.option.STANDBY = Standby +channel-type.robonect.versionType.label = Robonect Version + +# channel types config + +channel-type.config.robonect.jobType.afterMode.label = After Job Mode +channel-type.config.robonect.jobType.afterMode.description = The Mode to put the mower into after the job is done. +channel-type.config.robonect.jobType.duration.label = Job Duration +channel-type.config.robonect.jobType.duration.description = The duration of the job. +channel-type.config.robonect.jobType.remoteStart.label = Remote Start +channel-type.config.robonect.jobType.remoteStart.description = The location to start the mowing job from. diff --git a/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties new file mode 100644 index 0000000000000..14685dd973959 --- /dev/null +++ b/bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties @@ -0,0 +1,93 @@ +# binding + +binding.roku.name = Roku Binding +binding.roku.description = Controls Roku Streaming Media Players and TVs + +# thing types + +thing-type.roku.roku_player.label = Roku +thing-type.roku.roku_player.description = A Roku Streaming Media Player +thing-type.roku.roku_tv.label = Roku TV +thing-type.roku.roku_tv.description = A Roku Streaming Media TV + +# thing types config + +thing-type.config.roku.rokuconfig.hostName.label = Host Name/IP Address +thing-type.config.roku.rokuconfig.hostName.description = Host Name or IP Address of the Roku device +thing-type.config.roku.rokuconfig.port.label = Port +thing-type.config.roku.rokuconfig.port.description = Port for the ECP Connector of the Roku device +thing-type.config.roku.rokuconfig.refresh.label = Refresh Interval +thing-type.config.roku.rokuconfig.refresh.description = Specifies the Refresh Interval in Seconds + +# channel types + +channel-type.roku.activeApp.label = Active App +channel-type.roku.activeApp.description = The Currently Running App on the Roku +channel-type.roku.activeChannel.label = Active Channel +channel-type.roku.activeChannel.description = The TV Channel Currently Selected on the Roku TV +channel-type.roku.button.label = Remote Button +channel-type.roku.button.description = A Remote Button Press to Send to the Roku +channel-type.roku.button.state.option.Home = Home +channel-type.roku.button.state.option.Rev = Reverse +channel-type.roku.button.state.option.Fwd = Forward +channel-type.roku.button.state.option.Play = Play +channel-type.roku.button.state.option.Select = Select +channel-type.roku.button.state.option.Left = Left +channel-type.roku.button.state.option.Right = Right +channel-type.roku.button.state.option.Down = Down +channel-type.roku.button.state.option.Up = Up +channel-type.roku.button.state.option.Back = Back +channel-type.roku.button.state.option.InstantReplay = Instant Replay +channel-type.roku.button.state.option.Info = Info +channel-type.roku.button.state.option.Backspace = Backspace +channel-type.roku.button.state.option.Search = Search +channel-type.roku.button.state.option.Enter = Enter +channel-type.roku.button.state.option.FindRemote = Find Remote +channel-type.roku.buttonTv.label = Remote Button +channel-type.roku.buttonTv.description = A Remote Button Press to Send to the Roku TV +channel-type.roku.buttonTv.state.option.Home = Home +channel-type.roku.buttonTv.state.option.Rev = Reverse +channel-type.roku.buttonTv.state.option.Fwd = Forward +channel-type.roku.buttonTv.state.option.Play = Play +channel-type.roku.buttonTv.state.option.Select = Select +channel-type.roku.buttonTv.state.option.Left = Left +channel-type.roku.buttonTv.state.option.Right = Right +channel-type.roku.buttonTv.state.option.Down = Down +channel-type.roku.buttonTv.state.option.Up = Up +channel-type.roku.buttonTv.state.option.Back = Back +channel-type.roku.buttonTv.state.option.InstantReplay = Instant Replay +channel-type.roku.buttonTv.state.option.Info = Info +channel-type.roku.buttonTv.state.option.Backspace = Backspace +channel-type.roku.buttonTv.state.option.Search = Search +channel-type.roku.buttonTv.state.option.Enter = Enter +channel-type.roku.buttonTv.state.option.FindRemote = Find Remote +channel-type.roku.buttonTv.state.option.VolumeUp = Volume Up +channel-type.roku.buttonTv.state.option.VolumeDown = Volume Down +channel-type.roku.buttonTv.state.option.VolumeMute = Volume Mute +channel-type.roku.buttonTv.state.option.ChannelUp = Channel Up +channel-type.roku.buttonTv.state.option.Channel Down = Channel Down +channel-type.roku.buttonTv.state.option.InputTuner = Input Tuner +channel-type.roku.buttonTv.state.option.InputHDMI1 = Input HDMI1 +channel-type.roku.buttonTv.state.option.InputHDMI2 = Input HDMI2 +channel-type.roku.buttonTv.state.option.InputHDMI3 = Input HDMI3 +channel-type.roku.buttonTv.state.option.InputHDMI4 = Input HDMI4 +channel-type.roku.buttonTv.state.option.InputAV1 = Input AV1 +channel-type.roku.buttonTv.state.option.PowerOff = Power Off +channel-type.roku.channelName.label = Channel Name +channel-type.roku.channelName.description = The Name of the Channel Currently Selected +channel-type.roku.playMode.label = Play Mode +channel-type.roku.playMode.description = The Current Playback Mode +channel-type.roku.programDescription.label = Program Description +channel-type.roku.programDescription.description = The Description of the Current TV Program +channel-type.roku.programRating.label = Program Rating +channel-type.roku.programRating.description = The TV Parental Guideline Rating of the Current TV Program +channel-type.roku.programTitle.label = Program Title +channel-type.roku.programTitle.description = The Name of the Current TV Program +channel-type.roku.signalMode.label = Signal Mode +channel-type.roku.signalMode.description = The Signal Type of the Current TV Channel, ie: 1080i +channel-type.roku.signalQuality.label = Signal Quality +channel-type.roku.signalQuality.description = The Signal Quality of the Current TV Channel +channel-type.roku.timeElapsed.label = Playback Time +channel-type.roku.timeElapsed.description = The Current Playback Time Elapsed +channel-type.roku.timeTotal.label = Total Time +channel-type.roku.timeTotal.description = The Total Length of the Current Title diff --git a/bundles/org.openhab.binding.russound/src/main/resources/OH-INF/i18n/russound.properties b/bundles/org.openhab.binding.russound/src/main/resources/OH-INF/i18n/russound.properties new file mode 100644 index 0000000000000..0b6b48c73599d --- /dev/null +++ b/bundles/org.openhab.binding.russound/src/main/resources/OH-INF/i18n/russound.properties @@ -0,0 +1,170 @@ +# binding + +binding.russound.name = Russound Binding +binding.russound.description = This is the binding for Russound Whole House Audio systems (MCA and X-Systems). + +# thing types + +thing-type.russound.controller.label = Russound Controller +thing-type.russound.controller.description = Controller of Zones, Sources, etc +thing-type.russound.rio.label = Russound RIO Device +thing-type.russound.rio.description = Ethernet access point to Russound RIO control system (usually the main controller) +thing-type.russound.source.label = Russound Source +thing-type.russound.source.description = Source (tuner, streamer, etc) within the Russound System +thing-type.russound.zone.label = Russound Zone +thing-type.russound.zone.description = Zone within a Controller + +# thing types config + +thing-type.config.russound.controller.controller.label = Controller ID +thing-type.config.russound.controller.controller.description = The controller identifier +thing-type.config.russound.rio.ipAddress.label = IP or Host Name +thing-type.config.russound.rio.ipAddress.description = The IP or host name of the Russound RIO access point +thing-type.config.russound.rio.ping.label = Ping Interval +thing-type.config.russound.rio.ping.description = The ping interval in seconds to keep the connection alive +thing-type.config.russound.rio.retryPolling.label = Retry Polling +thing-type.config.russound.rio.retryPolling.description = The polling, in seconds, to retry a connection attempt +thing-type.config.russound.rio.scanDevice.label = Scan Device +thing-type.config.russound.rio.scanDevice.description = Scan device at startup (creating zones, sources, etc dynamically) +thing-type.config.russound.source.source.label = Source ID +thing-type.config.russound.source.source.description = The source identifier +thing-type.config.russound.zone.zone.label = Zone ID +thing-type.config.russound.zone.zone.description = The zone identifier + +# channel types + +channel-type.russound.ctlZones.label = Zones +channel-type.russound.ctlZones.description = JSON Array containing the zones ([{id: 1, name: 'xxx'}, ...]) +channel-type.russound.srcAlbumName.label = Album Name +channel-type.russound.srcAlbumName.description = Current song's album +channel-type.russound.srcArtistName.label = Artist Name +channel-type.russound.srcArtistName.description = Current song's artist name +channel-type.russound.srcBanks.label = Banks +channel-type.russound.srcBanks.description = JSON Array containing the banks ([{id: 1, name: 'xxx', presets: [{id:1 ,valid:true/false, name='xxx'}, ...], ...]) +channel-type.russound.srcChannel.label = Channel +channel-type.russound.srcChannel.description = Source's Channel +channel-type.russound.srcChannelName.label = ChannelName +channel-type.russound.srcChannelName.description = Source's Channel Name +channel-type.russound.srcComposerName.label = Composer Name +channel-type.russound.srcComposerName.description = Current song's composer name +channel-type.russound.srcCoverArtUrl.label = Cover Art URL +channel-type.russound.srcCoverArtUrl.description = Current song's covert art url +channel-type.russound.srcGenre.label = Genre +channel-type.russound.srcGenre.description = Current song's genre +channel-type.russound.srcMMAttr.label = MM Menus Attribute +channel-type.russound.srcMMAttr.description = The MM Menu Info Attributes +channel-type.russound.srcMMHelpText.label = MM Help Text +channel-type.russound.srcMMHelpText.description = The MM Help Text (label for form) +channel-type.russound.srcMMInfoText.label = MM Info Text +channel-type.russound.srcMMInfoText.description = The MM Info Text +channel-type.russound.srcMMMenu.label = MM Menus +channel-type.russound.srcMMMenu.description = The MM Menu Item JSON +channel-type.russound.srcMMMenuButtonBackText.label = MM Back Button Text +channel-type.russound.srcMMMenuButtonBackText.description = The MM Back Button Text +channel-type.russound.srcMMMenuButtonOkText.label = MM OK Button Text +channel-type.russound.srcMMMenuButtonOkText.description = The MM OK Button Text +channel-type.russound.srcMMScreen.label = MM Screen +channel-type.russound.srcMMScreen.description = The MM Screen ID +channel-type.russound.srcMMTextField.label = MM Text Field +channel-type.russound.srcMMTextField.description = The MM Text Field +channel-type.russound.srcMMTitle.label = MM Screen Title +channel-type.russound.srcMMTitle.description = The MM Screen Title +channel-type.russound.srcMode.label = Mode +channel-type.russound.srcMode.description = Provider Mode or Streaming Service +channel-type.russound.srcName.label = Name +channel-type.russound.srcName.description = Source Name +channel-type.russound.srcPlayListName.label = Play List Name +channel-type.russound.srcPlayListName.description = Name of the current playlist +channel-type.russound.srcProgramServiceName.label = Program Service Name +channel-type.russound.srcProgramServiceName.description = Program Service Name (PSN) +channel-type.russound.srcRadioText.label = Radio Text +channel-type.russound.srcRadioText.description = Radio Text +channel-type.russound.srcRadioText2.label = Radio Text 2 +channel-type.russound.srcRadioText2.description = Radio Text line 2 +channel-type.russound.srcRadioText3.label = Radio Text 3 +channel-type.russound.srcRadioText3.description = Radio Text line 3 +channel-type.russound.srcRadioText4.label = Radio Text 4 +channel-type.russound.srcRadioText4.description = Radio Text line 4 +channel-type.russound.srcRating.label = Song Rating +channel-type.russound.srcRating.description = Rating of the current song +channel-type.russound.srcRepeatMode.label = Repeat Mode +channel-type.russound.srcRepeatMode.description = Source Repeat Mode +channel-type.russound.srcShuffleMode.label = Shuffle Mode +channel-type.russound.srcShuffleMode.description = Source Shuffle Mode +channel-type.russound.srcSongName.label = Song Name +channel-type.russound.srcSongName.description = Name of the current song +channel-type.russound.srcType.label = Type +channel-type.russound.srcType.description = Source Type +channel-type.russound.srcVolume.label = Volume +channel-type.russound.srcVolume.description = The volume level of the source +channel-type.russound.sysAllOn.label = All Zones +channel-type.russound.sysAllOn.description = Toggles All Zones +channel-type.russound.sysControllers.label = Controllers +channel-type.russound.sysControllers.description = JSON Array containing the valid controllers ([{id: 1, name: 'xxx'}, ...]) +channel-type.russound.sysLang.label = Language +channel-type.russound.sysLang.description = System Language +channel-type.russound.sysLang.state.option.ENGLISH = English +channel-type.russound.sysLang.state.option.CHINESE = Chinese +channel-type.russound.sysLang.state.option.RUSSIAN = Russian +channel-type.russound.sysSources.label = Sources +channel-type.russound.sysSources.description = JSON Array containing the sources ([{id: 1, name: 'xxx'}, ...]) +channel-type.russound.zoneBalance.label = Balance +channel-type.russound.zoneBalance.description = Balance (-10 full left, 10 full right) +channel-type.russound.zoneBass.label = Bass +channel-type.russound.zoneBass.description = Bass Setting +channel-type.russound.zoneDoNotDisturb.label = Do Not Disturb +channel-type.russound.zoneDoNotDisturb.description = Do Not Disturb +channel-type.russound.zoneEnabled.label = Enabled +channel-type.russound.zoneEnabled.description = Whether the zone is enabled or not +channel-type.russound.zoneEvent.label = Generic Event +channel-type.russound.zoneEvent.description = Send a generic event to the zone +channel-type.russound.zoneFavorites.label = Zone Favorites +channel-type.russound.zoneFavorites.description = JSON Array containing the zone favorites ([{id: 1, valid: true/false, name: 'xxx'}, ...]) +channel-type.russound.zoneKeyCode.label = KeyCode Event +channel-type.russound.zoneKeyCode.description = Send a KeyCode event to the zone +channel-type.russound.zoneKeyHold.label = KeyHold Event +channel-type.russound.zoneKeyHold.description = Send a KeyHold event to the zone +channel-type.russound.zoneKeyPress.label = KeyPress Event +channel-type.russound.zoneKeyPress.description = Send a KeyPress event to the zone +channel-type.russound.zoneKeyRelease.label = KeyRelease Event +channel-type.russound.zoneKeyRelease.description = Send a KeyRelease event to the zone +channel-type.russound.zoneLastError.label = Last Error +channel-type.russound.zoneLastError.description = last Error encountered in the zone +channel-type.russound.zoneLoudness.label = Loudness +channel-type.russound.zoneLoudness.description = Loudness +channel-type.russound.zoneMMContextMenu.label = MM Context Menu +channel-type.russound.zoneMMContextMenu.description = Request a source context menu +channel-type.russound.zoneMMInit.label = MM Initialize +channel-type.russound.zoneMMInit.description = Send MM back to home screen +channel-type.russound.zoneMute.label = Mute +channel-type.russound.zoneMute.description = Whether the zone is muted +channel-type.russound.zoneName.label = Zone Name +channel-type.russound.zoneName.description = The name of the zone +channel-type.russound.zonePage.label = Page +channel-type.russound.zonePage.description = Whether the zone is paging +channel-type.russound.zonePartyMode.label = Party Mode +channel-type.russound.zonePartyMode.description = Party Mode +channel-type.russound.zonePresets.label = Zone Presets +channel-type.russound.zonePresets.description = JSON Array containing the zone presets ([{id: 1, valid: true/false, name: 'xxx'}, ...]) +channel-type.russound.zoneRating.label = Rating +channel-type.russound.zoneRating.description = How to rate the current song (like/dislike) +channel-type.russound.zoneRepeat.label = Source Repeat +channel-type.russound.zoneRepeat.description = Toggle the zone's repeat mode +channel-type.russound.zoneSharedSource.label = Shared Source +channel-type.russound.zoneSharedSource.description = Whether the zone is sharing it's source +channel-type.russound.zoneShuffle.label = Source Shuffle +channel-type.russound.zoneShuffle.description = Toggle the zone's shuffle mode +channel-type.russound.zoneSleepTimeRemaining.label = Sleep Time Remaining +channel-type.russound.zoneSleepTimeRemaining.description = Sleep Time (in seconds) remaining +channel-type.russound.zoneSource.label = Source +channel-type.russound.zoneSource.description = Physical Source Number +channel-type.russound.zoneStatus.label = Status +channel-type.russound.zoneStatus.description = Whether the zone is ON or OFF +channel-type.russound.zoneSysFavorites.label = System Favorites +channel-type.russound.zoneSysFavorites.description = JSON Array containing the system favorites ([{id: 1, valid: true/false, name: 'xxx'}, ...]) +channel-type.russound.zoneTreble.label = Treble +channel-type.russound.zoneTreble.description = Treble Setting +channel-type.russound.zoneTurnOnVolume.label = Turn On Volume +channel-type.russound.zoneTurnOnVolume.description = The volume the zone will default to when turned on +channel-type.russound.zoneVolume.label = Volume +channel-type.russound.zoneVolume.description = Volume level of zone diff --git a/bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv.properties b/bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv.properties new file mode 100644 index 0000000000000..7f759ba29e2a6 --- /dev/null +++ b/bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv.properties @@ -0,0 +1,309 @@ +# binding + +binding.samsungtv.name = Samsung TV Binding +binding.samsungtv.description = This is the binding for Samsung TV. Binding should support all Samsung TV C (2010), D (2011) and E (2012) models + +# thing types + +thing-type.samsungtv.tv.label = Samsung TV +thing-type.samsungtv.tv.description = Allows to control Samsung TV + +# thing types config + +thing-type.config.samsungtv.tv.hostName.label = Host Name +thing-type.config.samsungtv.tv.hostName.description = Network address of the Samsung TV. +thing-type.config.samsungtv.tv.macAddress.label = MAC Address +thing-type.config.samsungtv.tv.macAddress.description = MAC Address of the Samsung TV. +thing-type.config.samsungtv.tv.port.label = TCP Port +thing-type.config.samsungtv.tv.port.description = TCP port of the Samsung TV. +thing-type.config.samsungtv.tv.protocol.label = Remote Control Protocol +thing-type.config.samsungtv.tv.protocol.description = The type of remote control protocol. This depends on the age of the TV. +thing-type.config.samsungtv.tv.protocol.option.None = None +thing-type.config.samsungtv.tv.protocol.option.Legacy = Legacy (Before 2014) +thing-type.config.samsungtv.tv.protocol.option.WebSocket = Websocket (2016 and later TV's) +thing-type.config.samsungtv.tv.protocol.option.SecureWebSocket = Secure websocket (2016 and later TV's) +thing-type.config.samsungtv.tv.refreshInterval.label = Refresh Interval +thing-type.config.samsungtv.tv.refreshInterval.description = States how often a refresh shall occur in milliseconds. +thing-type.config.samsungtv.tv.webSocketToken.label = Websocket Token +thing-type.config.samsungtv.tv.webSocketToken.description = Security token for secure websocket connection + +# channel types + +channel-type.samsungtv.artmode.label = Art Mode +channel-type.samsungtv.artmode.description = TV Art Mode. +channel-type.samsungtv.brightness.label = Brightness +channel-type.samsungtv.brightness.description = Brightness of the TV picture. +channel-type.samsungtv.channel.label = Channel +channel-type.samsungtv.channel.description = Selected TV channel number. +channel-type.samsungtv.channelname.label = Channel Name +channel-type.samsungtv.channelname.description = Name of the current TV channel. +channel-type.samsungtv.colortemperature.label = Color Temperature +channel-type.samsungtv.colortemperature.description = Color temperature of the TV picture. Minimum value is 0 and maximum 4. +channel-type.samsungtv.contrast.label = Contrast +channel-type.samsungtv.contrast.description = Contrast of the TV picture. +channel-type.samsungtv.keycode.label = Key Code +channel-type.samsungtv.keycode.description = The key code channel emulates the infrared remote controller and allows to send virtual button presses. +channel-type.samsungtv.keycode.state.option.KEY_0 = KEY_0 +channel-type.samsungtv.keycode.state.option.KEY_1 = KEY_1 +channel-type.samsungtv.keycode.state.option.KEY_2 = KEY_2 +channel-type.samsungtv.keycode.state.option.KEY_3 = KEY_3 +channel-type.samsungtv.keycode.state.option.KEY_4 = KEY_4 +channel-type.samsungtv.keycode.state.option.KEY_5 = KEY_5 +channel-type.samsungtv.keycode.state.option.KEY_6 = KEY_6 +channel-type.samsungtv.keycode.state.option.KEY_7 = KEY_7 +channel-type.samsungtv.keycode.state.option.KEY_8 = KEY_8 +channel-type.samsungtv.keycode.state.option.KEY_9 = KEY_9 +channel-type.samsungtv.keycode.state.option.KEY_11 = KEY_11 +channel-type.samsungtv.keycode.state.option.KEY_12 = KEY_12 +channel-type.samsungtv.keycode.state.option.KEY_3SPEED = KEY_3SPEED +channel-type.samsungtv.keycode.state.option.KEY_4_3 = KEY_4_3 +channel-type.samsungtv.keycode.state.option.KEY_16_9 = KEY_16_9 +channel-type.samsungtv.keycode.state.option.KEY_AD = KEY_AD +channel-type.samsungtv.keycode.state.option.KEY_ADDDEL = KEY_ADDDEL +channel-type.samsungtv.keycode.state.option.KEY_ALT_MHP = KEY_ALT_MHP +channel-type.samsungtv.keycode.state.option.KEY_ANGLE = KEY_ANGLE +channel-type.samsungtv.keycode.state.option.KEY_ANTENA = KEY_ANTENA +channel-type.samsungtv.keycode.state.option.KEY_ANYNET = KEY_ANYNET +channel-type.samsungtv.keycode.state.option.KEY_ANYVIEW = KEY_ANYVIEW +channel-type.samsungtv.keycode.state.option.KEY_APP_LIST = KEY_APP_LIST +channel-type.samsungtv.keycode.state.option.KEY_ASPECT = KEY_ASPECT +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_ANTENNA_AIR = KEY_AUTO_ARC_ANTENNA_AIR +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_ANTENNA_CABLE = KEY_AUTO_ARC_ANTENNA_CABLE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_ANTENNA_SATELLITE = KEY_AUTO_ARC_ANTENNA_SATELLITE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_ANYNET_AUTO_START = KEY_AUTO_ARC_ANYNET_AUTO_START +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_ANYNET_MODE_OK = KEY_AUTO_ARC_ANYNET_MODE_OK +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_AUTOCOLOR_FAIL = KEY_AUTO_ARC_AUTOCOLOR_FAIL +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_AUTOCOLOR_SUCCESS = KEY_AUTO_ARC_AUTOCOLOR_SUCCESS +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_CAPTION_ENG = KEY_AUTO_ARC_CAPTION_ENG +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_CAPTION_KOR = KEY_AUTO_ARC_CAPTION_KOR +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_CAPTION_OFF = KEY_AUTO_ARC_CAPTION_OFF +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_CAPTION_ON = KEY_AUTO_ARC_CAPTION_ON +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_C_FORCE_AGING = KEY_AUTO_ARC_C_FORCE_AGING +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_JACK_IDENT = KEY_AUTO_ARC_JACK_IDENT +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_LNA_OFF = KEY_AUTO_ARC_LNA_OFF +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_LNA_ON = KEY_AUTO_ARC_LNA_ON +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_CH_CHANGE = KEY_AUTO_ARC_PIP_CH_CHANGE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_DOUBLE = KEY_AUTO_ARC_PIP_DOUBLE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_LARGE = KEY_AUTO_ARC_PIP_LARGE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_LEFT_BOTTOM = KEY_AUTO_ARC_PIP_LEFT_BOTTOM +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_LEFT_TOP = KEY_AUTO_ARC_PIP_LEFT_TOP +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_RIGHT_BOTTOM = KEY_AUTO_ARC_PIP_RIGHT_BOTTOM +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_RIGHT_TOP = KEY_AUTO_ARC_PIP_RIGHT_TOP +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_SMALL = KEY_AUTO_ARC_PIP_SMALL +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_SOURCE_CHANGE = KEY_AUTO_ARC_PIP_SOURCE_CHANGE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_PIP_WIDE = KEY_AUTO_ARC_PIP_WIDE +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_RESET = KEY_AUTO_ARC_RESET +channel-type.samsungtv.keycode.state.option.KEY_AUTO_ARC_USBJACK_INSPECT = KEY_AUTO_ARC_USBJACK_INSPECT +channel-type.samsungtv.keycode.state.option.KEY_AUTO_FORMAT = KEY_AUTO_FORMAT +channel-type.samsungtv.keycode.state.option.KEY_AUTO_PROGRAM = KEY_AUTO_PROGRAM +channel-type.samsungtv.keycode.state.option.KEY_AV1 = KEY_AV1 +channel-type.samsungtv.keycode.state.option.KEY_AV2 = KEY_AV2 +channel-type.samsungtv.keycode.state.option.KEY_AV3 = KEY_AV3 +channel-type.samsungtv.keycode.state.option.KEY_BACK_MHP = KEY_BACK_MHP +channel-type.samsungtv.keycode.state.option.KEY_BOOKMARK = KEY_BOOKMARK +channel-type.samsungtv.keycode.state.option.KEY_CALLER_ID = KEY_CALLER_ID +channel-type.samsungtv.keycode.state.option.KEY_CAPTION = KEY_CAPTION +channel-type.samsungtv.keycode.state.option.KEY_CATV_MODE = KEY_CATV_MODE +channel-type.samsungtv.keycode.state.option.KEY_CHDOWN = KEY_CHDOWN +channel-type.samsungtv.keycode.state.option.KEY_CHUP = KEY_CHUP +channel-type.samsungtv.keycode.state.option.KEY_CH_LIST = KEY_CH_LIST +channel-type.samsungtv.keycode.state.option.KEY_CLEAR = KEY_CLEAR +channel-type.samsungtv.keycode.state.option.KEY_CLOCK_DISPLAY = KEY_CLOCK_DISPLAY +channel-type.samsungtv.keycode.state.option.KEY_COMPONENT1 = KEY_COMPONENT1 +channel-type.samsungtv.keycode.state.option.KEY_COMPONENT2 = KEY_COMPONENT2 +channel-type.samsungtv.keycode.state.option.KEY_CONTENTS = KEY_CONTENTS +channel-type.samsungtv.keycode.state.option.KEY_CONVERGENCE = KEY_CONVERGENCE +channel-type.samsungtv.keycode.state.option.KEY_CONVERT_AUDIO_MAINSUB = KEY_CONVERT_AUDIO_MAINSUB +channel-type.samsungtv.keycode.state.option.KEY_CUSTOM = KEY_CUSTOM +channel-type.samsungtv.keycode.state.option.KEY_CYAN = KEY_CYAN +channel-type.samsungtv.keycode.state.option.KEY_BLUE = KEY_BLUE +channel-type.samsungtv.keycode.state.option.KEY_DEVICE_CONNECT = KEY_DEVICE_CONNECT +channel-type.samsungtv.keycode.state.option.KEY_DISC_MENU = KEY_DISC_MENU +channel-type.samsungtv.keycode.state.option.KEY_DMA = KEY_DMA +channel-type.samsungtv.keycode.state.option.KEY_DNET = KEY_DNET +channel-type.samsungtv.keycode.state.option.KEY_DNIE = KEY_DNIE +channel-type.samsungtv.keycode.state.option.KEY_DNSE = KEY_DNSE +channel-type.samsungtv.keycode.state.option.KEY_DOOR = KEY_DOOR +channel-type.samsungtv.keycode.state.option.KEY_DOWN = KEY_DOWN +channel-type.samsungtv.keycode.state.option.KEY_DSS_MODE = KEY_DSS_MODE +channel-type.samsungtv.keycode.state.option.KEY_DTV = KEY_DTV +channel-type.samsungtv.keycode.state.option.KEY_DTV_LINK = KEY_DTV_LINK +channel-type.samsungtv.keycode.state.option.KEY_DTV_SIGNAL = KEY_DTV_SIGNAL +channel-type.samsungtv.keycode.state.option.KEY_DVD_MODE = KEY_DVD_MODE +channel-type.samsungtv.keycode.state.option.KEY_DVI = KEY_DVI +channel-type.samsungtv.keycode.state.option.KEY_DVR = KEY_DVR +channel-type.samsungtv.keycode.state.option.KEY_DVR_MENU = KEY_DVR_MENU +channel-type.samsungtv.keycode.state.option.KEY_DYNAMIC = KEY_DYNAMIC +channel-type.samsungtv.keycode.state.option.KEY_ENTER = KEY_ENTER +channel-type.samsungtv.keycode.state.option.KEY_ENTERTAINMENT = KEY_ENTERTAINMENT +channel-type.samsungtv.keycode.state.option.KEY_ESAVING = KEY_ESAVING +channel-type.samsungtv.keycode.state.option.KEY_EXIT = KEY_EXIT +channel-type.samsungtv.keycode.state.option.KEY_EXT1 = KEY_EXT1 +channel-type.samsungtv.keycode.state.option.KEY_EXT2 = KEY_EXT2 +channel-type.samsungtv.keycode.state.option.KEY_EXT3 = KEY_EXT3 +channel-type.samsungtv.keycode.state.option.KEY_EXT4 = KEY_EXT4 +channel-type.samsungtv.keycode.state.option.KEY_EXT5 = KEY_EXT5 +channel-type.samsungtv.keycode.state.option.KEY_EXT6 = KEY_EXT6 +channel-type.samsungtv.keycode.state.option.KEY_EXT7 = KEY_EXT7 +channel-type.samsungtv.keycode.state.option.KEY_EXT8 = KEY_EXT8 +channel-type.samsungtv.keycode.state.option.KEY_EXT9 = KEY_EXT9 +channel-type.samsungtv.keycode.state.option.KEY_EXT10 = KEY_EXT10 +channel-type.samsungtv.keycode.state.option.KEY_EXT11 = KEY_EXT11 +channel-type.samsungtv.keycode.state.option.KEY_EXT12 = KEY_EXT12 +channel-type.samsungtv.keycode.state.option.KEY_EXT13 = KEY_EXT13 +channel-type.samsungtv.keycode.state.option.KEY_EXT14 = KEY_EXT14 +channel-type.samsungtv.keycode.state.option.KEY_EXT15 = KEY_EXT15 +channel-type.samsungtv.keycode.state.option.KEY_EXT16 = KEY_EXT16 +channel-type.samsungtv.keycode.state.option.KEY_EXT17 = KEY_EXT17 +channel-type.samsungtv.keycode.state.option.KEY_EXT18 = KEY_EXT18 +channel-type.samsungtv.keycode.state.option.KEY_EXT19 = KEY_EXT19 +channel-type.samsungtv.keycode.state.option.KEY_EXT20 = KEY_EXT20 +channel-type.samsungtv.keycode.state.option.KEY_EXT21 = KEY_EXT21 +channel-type.samsungtv.keycode.state.option.KEY_EXT22 = KEY_EXT22 +channel-type.samsungtv.keycode.state.option.KEY_EXT23 = KEY_EXT23 +channel-type.samsungtv.keycode.state.option.KEY_EXT24 = KEY_EXT24 +channel-type.samsungtv.keycode.state.option.KEY_EXT25 = KEY_EXT25 +channel-type.samsungtv.keycode.state.option.KEY_EXT26 = KEY_EXT26 +channel-type.samsungtv.keycode.state.option.KEY_EXT27 = KEY_EXT27 +channel-type.samsungtv.keycode.state.option.KEY_EXT28 = KEY_EXT28 +channel-type.samsungtv.keycode.state.option.KEY_EXT29 = KEY_EXT29 +channel-type.samsungtv.keycode.state.option.KEY_EXT30 = KEY_EXT30 +channel-type.samsungtv.keycode.state.option.KEY_EXT31 = KEY_EXT31 +channel-type.samsungtv.keycode.state.option.KEY_EXT32 = KEY_EXT32 +channel-type.samsungtv.keycode.state.option.KEY_EXT33 = KEY_EXT33 +channel-type.samsungtv.keycode.state.option.KEY_EXT34 = KEY_EXT34 +channel-type.samsungtv.keycode.state.option.KEY_EXT35 = KEY_EXT35 +channel-type.samsungtv.keycode.state.option.KEY_EXT36 = KEY_EXT36 +channel-type.samsungtv.keycode.state.option.KEY_EXT37 = KEY_EXT37 +channel-type.samsungtv.keycode.state.option.KEY_EXT38 = KEY_EXT38 +channel-type.samsungtv.keycode.state.option.KEY_EXT39 = KEY_EXT39 +channel-type.samsungtv.keycode.state.option.KEY_EXT40 = KEY_EXT40 +channel-type.samsungtv.keycode.state.option.KEY_EXT41 = KEY_EXT41 +channel-type.samsungtv.keycode.state.option.KEY_FACTORY = KEY_FACTORY +channel-type.samsungtv.keycode.state.option.KEY_FAVCH = KEY_FAVCH +channel-type.samsungtv.keycode.state.option.KEY_FF = KEY_FF +channel-type.samsungtv.keycode.state.option.KEY_FM_RADIO = KEY_FM_RADIO +channel-type.samsungtv.keycode.state.option.KEY_GAME = KEY_GAME +channel-type.samsungtv.keycode.state.option.KEY_GREEN = KEY_GREEN +channel-type.samsungtv.keycode.state.option.KEY_GUIDE = KEY_GUIDE +channel-type.samsungtv.keycode.state.option.KEY_HDMI = KEY_HDMI +channel-type.samsungtv.keycode.state.option.KEY_HDMI1 = KEY_HDMI1 +channel-type.samsungtv.keycode.state.option.KEY_HDMI2 = KEY_HDMI2 +channel-type.samsungtv.keycode.state.option.KEY_HDMI3 = KEY_HDMI3 +channel-type.samsungtv.keycode.state.option.KEY_HDMI4 = KEY_HDMI4 +channel-type.samsungtv.keycode.state.option.KEY_HELP = KEY_HELP +channel-type.samsungtv.keycode.state.option.KEY_HOME = KEY_HOME +channel-type.samsungtv.keycode.state.option.KEY_ID_INPUT = KEY_ID_INPUT +channel-type.samsungtv.keycode.state.option.KEY_ID_SETUP = KEY_ID_SETUP +channel-type.samsungtv.keycode.state.option.KEY_INFO = KEY_INFO +channel-type.samsungtv.keycode.state.option.KEY_INSTANT_REPLAY = KEY_INSTANT_REPLAY +channel-type.samsungtv.keycode.state.option.KEY_LEFT = KEY_LEFT +channel-type.samsungtv.keycode.state.option.KEY_LINK = KEY_LINK +channel-type.samsungtv.keycode.state.option.KEY_LIVE = KEY_LIVE +channel-type.samsungtv.keycode.state.option.KEY_MAGIC_BRIGHT = KEY_MAGIC_BRIGHT +channel-type.samsungtv.keycode.state.option.KEY_MAGIC_CHANNEL = KEY_MAGIC_CHANNEL +channel-type.samsungtv.keycode.state.option.KEY_MDC = KEY_MDC +channel-type.samsungtv.keycode.state.option.KEY_MENU = KEY_MENU +channel-type.samsungtv.keycode.state.option.KEY_MIC = KEY_MIC +channel-type.samsungtv.keycode.state.option.KEY_MORE = KEY_MORE +channel-type.samsungtv.keycode.state.option.KEY_MOVIE1 = KEY_MOVIE1 +channel-type.samsungtv.keycode.state.option.KEY_MS = KEY_MS +channel-type.samsungtv.keycode.state.option.KEY_MTS = KEY_MTS +channel-type.samsungtv.keycode.state.option.KEY_MUTE = KEY_MUTE +channel-type.samsungtv.keycode.state.option.KEY_NINE_SEPERATE = KEY_NINE_SEPERATE +channel-type.samsungtv.keycode.state.option.KEY_OPEN = KEY_OPEN +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_CHDOWN = KEY_PANNEL_CHDOWN +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_CHUP = KEY_PANNEL_CHUP +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_ENTER = KEY_PANNEL_ENTER +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_MENU = KEY_PANNEL_MENU +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_POWER = KEY_PANNEL_POWER +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_SOURCE = KEY_PANNEL_SOURCE +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_VOLDOW = KEY_PANNEL_VOLDOW +channel-type.samsungtv.keycode.state.option.KEY_PANNEL_VOLUP = KEY_PANNEL_VOLUP +channel-type.samsungtv.keycode.state.option.KEY_PANORAMA = KEY_PANORAMA +channel-type.samsungtv.keycode.state.option.KEY_PAUSE = KEY_PAUSE +channel-type.samsungtv.keycode.state.option.KEY_PCMODE = KEY_PCMODE +channel-type.samsungtv.keycode.state.option.KEY_PERPECT_FOCUS = KEY_PERPECT_FOCUS +channel-type.samsungtv.keycode.state.option.KEY_PICTURE_SIZE = KEY_PICTURE_SIZE +channel-type.samsungtv.keycode.state.option.KEY_PIP_CHDOWN = KEY_PIP_CHDOWN +channel-type.samsungtv.keycode.state.option.KEY_PIP_CHUP = KEY_PIP_CHUP +channel-type.samsungtv.keycode.state.option.KEY_PIP_ONOFF = KEY_PIP_ONOFF +channel-type.samsungtv.keycode.state.option.KEY_PIP_SCAN = KEY_PIP_SCAN +channel-type.samsungtv.keycode.state.option.KEY_PIP_SIZE = KEY_PIP_SIZE +channel-type.samsungtv.keycode.state.option.KEY_PIP_SWAP = KEY_PIP_SWAP +channel-type.samsungtv.keycode.state.option.KEY_PLAY = KEY_PLAY +channel-type.samsungtv.keycode.state.option.KEY_PLUS100 = KEY_PLUS100 +channel-type.samsungtv.keycode.state.option.KEY_PMODE = KEY_PMODE +channel-type.samsungtv.keycode.state.option.KEY_POWER = KEY_POWER +channel-type.samsungtv.keycode.state.option.KEY_POWEROFF = KEY_POWEROFF +channel-type.samsungtv.keycode.state.option.KEY_POWERON = KEY_POWERON +channel-type.samsungtv.keycode.state.option.KEY_PRECH = KEY_PRECH +channel-type.samsungtv.keycode.state.option.KEY_PRINT = KEY_PRINT +channel-type.samsungtv.keycode.state.option.KEY_PROGRAM = KEY_PROGRAM +channel-type.samsungtv.keycode.state.option.KEY_QUICK_REPLAY = KEY_QUICK_REPLAY +channel-type.samsungtv.keycode.state.option.KEY_REC = KEY_REC +channel-type.samsungtv.keycode.state.option.KEY_RED = KEY_RED +channel-type.samsungtv.keycode.state.option.KEY_REPEAT = KEY_REPEAT +channel-type.samsungtv.keycode.state.option.KEY_RESERVED1 = KEY_RESERVED1 +channel-type.samsungtv.keycode.state.option.KEY_RETURN = KEY_RETURN +channel-type.samsungtv.keycode.state.option.KEY_REWIND = KEY_REWIND +channel-type.samsungtv.keycode.state.option.KEY_RIGHT = KEY_RIGHT +channel-type.samsungtv.keycode.state.option.KEY_RSS = KEY_RSS +channel-type.samsungtv.keycode.state.option.KEY_INTERNET = KEY_INTERNET +channel-type.samsungtv.keycode.state.option.KEY_RSURF = KEY_RSURF +channel-type.samsungtv.keycode.state.option.KEY_SCALE = KEY_SCALE +channel-type.samsungtv.keycode.state.option.KEY_SEFFECT = KEY_SEFFECT +channel-type.samsungtv.keycode.state.option.KEY_SETUP_CLOCK_TIMER = KEY_SETUP_CLOCK_TIMER +channel-type.samsungtv.keycode.state.option.KEY_SLEEP = KEY_SLEEP +channel-type.samsungtv.keycode.state.option.KEY_SOUND_MODE = KEY_SOUND_MODE +channel-type.samsungtv.keycode.state.option.KEY_SOURCE = KEY_SOURCE +channel-type.samsungtv.keycode.state.option.KEY_SRS = KEY_SRS +channel-type.samsungtv.keycode.state.option.KEY_STANDARD = KEY_STANDARD +channel-type.samsungtv.keycode.state.option.KEY_STB_MODE = KEY_STB_MODE +channel-type.samsungtv.keycode.state.option.KEY_STILL_PICTURE = KEY_STILL_PICTURE +channel-type.samsungtv.keycode.state.option.KEY_STOP = KEY_STOP +channel-type.samsungtv.keycode.state.option.KEY_SUB_TITLE = KEY_SUB_TITLE +channel-type.samsungtv.keycode.state.option.KEY_SVIDEO1 = KEY_SVIDEO1 +channel-type.samsungtv.keycode.state.option.KEY_SVIDEO2 = KEY_SVIDEO2 +channel-type.samsungtv.keycode.state.option.KEY_SVIDEO3 = KEY_SVIDEO3 +channel-type.samsungtv.keycode.state.option.KEY_TOOLS = KEY_TOOLS +channel-type.samsungtv.keycode.state.option.KEY_TOPMENU = KEY_TOPMENU +channel-type.samsungtv.keycode.state.option.KEY_TTX_MIX = KEY_TTX_MIX +channel-type.samsungtv.keycode.state.option.KEY_TTX_SUBFACE = KEY_TTX_SUBFACE +channel-type.samsungtv.keycode.state.option.KEY_TURBO = KEY_TURBO +channel-type.samsungtv.keycode.state.option.KEY_TV = KEY_TV +channel-type.samsungtv.keycode.state.option.KEY_TV_MODE = KEY_TV_MODE +channel-type.samsungtv.keycode.state.option.KEY_UP = KEY_UP +channel-type.samsungtv.keycode.state.option.KEY_VCHIP = KEY_VCHIP +channel-type.samsungtv.keycode.state.option.KEY_VCR_MODE = KEY_VCR_MODE +channel-type.samsungtv.keycode.state.option.KEY_VOLDOWN = KEY_VOLDOWN +channel-type.samsungtv.keycode.state.option.KEY_VOLUP = KEY_VOLUP +channel-type.samsungtv.keycode.state.option.KEY_WHEEL_LEFT = KEY_WHEEL_LEFT +channel-type.samsungtv.keycode.state.option.KEY_WHEEL_RIGHT = KEY_WHEEL_RIGHT +channel-type.samsungtv.keycode.state.option.KEY_W_LINK = KEY_W_LINK +channel-type.samsungtv.keycode.state.option.KEY_YELLOW = KEY_YELLOW +channel-type.samsungtv.keycode.state.option.KEY_ZOOM1 = KEY_ZOOM1 +channel-type.samsungtv.keycode.state.option.KEY_ZOOM2 = KEY_ZOOM2 +channel-type.samsungtv.keycode.state.option.KEY_ZOOM_IN = KEY_ZOOM_IN +channel-type.samsungtv.keycode.state.option.KEY_ZOOM_MOVE = KEY_ZOOM_MOVE +channel-type.samsungtv.keycode.state.option.KEY_ZOOM_OUT = KEY_ZOOM_OUT +channel-type.samsungtv.mute.label = Mute +channel-type.samsungtv.mute.description = Mute state of the TV. +channel-type.samsungtv.power.label = Power +channel-type.samsungtv.power.description = TV power. Some of the Samsung TV models doesn't allow to set Power ON remotely. +channel-type.samsungtv.programtitle.label = Program Title +channel-type.samsungtv.programtitle.description = Program title of the current channel. +channel-type.samsungtv.sharpness.label = Sharpness +channel-type.samsungtv.sharpness.description = Sharpness of the TV picture. +channel-type.samsungtv.sourceapp.label = Application +channel-type.samsungtv.sourceapp.description = Application currently running +channel-type.samsungtv.sourceid.label = Source ID +channel-type.samsungtv.sourceid.description = Id of the current source. +channel-type.samsungtv.sourcename.label = Source Name +channel-type.samsungtv.sourcename.description = Name of the current source. +channel-type.samsungtv.stopbrowser.label = Stop Browser +channel-type.samsungtv.stopbrowser.description = Stop TV's web browser and go back to TV mode. +channel-type.samsungtv.url.label = Browser URL +channel-type.samsungtv.url.description = Start TV web browser and go the given web page. +channel-type.samsungtv.volume.label = Volume +channel-type.samsungtv.volume.description = Volume level of the TV. diff --git a/bundles/org.openhab.binding.semsportal/src/main/resources/OH-INF/i18n/semsportal.properties b/bundles/org.openhab.binding.semsportal/src/main/resources/OH-INF/i18n/semsportal.properties new file mode 100644 index 0000000000000..ac8960156bf95 --- /dev/null +++ b/bundles/org.openhab.binding.semsportal/src/main/resources/OH-INF/i18n/semsportal.properties @@ -0,0 +1,37 @@ +# binding + +binding.semsportal.name = SEMSPortal Binding +binding.semsportal.description = This is the binding for SEMSPortal. The SEMS portal is where a GoodWE solar installation uploads it's data. The SEMS portal has a lot of data, only a few of them are currently mapped to a channel. You will need an account at semsportal.com and have your solar installation registered on that account. + +# thing types + +thing-type.semsportal.portal.label = SEMS Portal +thing-type.semsportal.portal.description = The SEMS Portal is where the data about powerstations is collected online. Configuration will only work if you have used this account at least once in the portal itsself. +thing-type.semsportal.station.label = Power Station +thing-type.semsportal.station.description = A Power Station is the GoodWe converter that is connected through the internet with the SEMSPortal. + +# thing types config + +thing-type.config.semsportal.portal.interval.label = Interval +thing-type.config.semsportal.portal.interval.description = Number of minutes between updates. Minimum is 1 minute, maximum is 60. The default is 5 minutes. +thing-type.config.semsportal.portal.password.label = Password +thing-type.config.semsportal.portal.password.description = Password of the SEMS Portal +thing-type.config.semsportal.portal.username.label = Username +thing-type.config.semsportal.portal.username.description = Username (email address) of the account at the SEMS portal + +# channel types + +channel-type.semsportal.currentOutput.label = Current Output +channel-type.semsportal.currentOutput.description = Current output in Watts +channel-type.semsportal.lastUpdate.label = Last Update +channel-type.semsportal.lastUpdate.description = Timestamp that the last information was received from the station. This is not the same as the last time that was checked: the station goes offline at night. +channel-type.semsportal.monthTotal.label = Current Month Total Output +channel-type.semsportal.monthTotal.description = The total output of this month in kWh +channel-type.semsportal.overallTotal.label = Overall Total Output +channel-type.semsportal.overallTotal.description = The total output from the start of the installation in kWh +channel-type.semsportal.todayIncome.label = Todays Income +channel-type.semsportal.todayIncome.description = Todays income. Only reports if you have set the tariffs in the SEMS portal. Unit is the currency that is set in these tariffs. +channel-type.semsportal.todayTotal.label = Todays Total Output +channel-type.semsportal.todayTotal.description = Todays total output in kWh +channel-type.semsportal.totalIncome.label = Total Income +channel-type.semsportal.totalIncome.description = Total income since installation. Only reports if you have set the tariffs in the SEMS portal. Unit is the currency that is set in these tariffs. diff --git a/bundles/org.openhab.binding.senechome/src/main/resources/OH-INF/i18n/senechome.properties b/bundles/org.openhab.binding.senechome/src/main/resources/OH-INF/i18n/senechome.properties new file mode 100644 index 0000000000000..20da0aa9602ce --- /dev/null +++ b/bundles/org.openhab.binding.senechome/src/main/resources/OH-INF/i18n/senechome.properties @@ -0,0 +1,99 @@ +# binding + +binding.senechome.name = SenecHome Binding +binding.senechome.description = This is the binding for SenecHome. + +# thing types + +thing-type.senechome.senechome.label = Senec Home +thing-type.senechome.senechome.description = Senec Home + +# thing types config + +thing-type.config.senechome.senechome.hostname.label = Hostname/IP Address +thing-type.config.senechome.senechome.hostname.description = Enter the hostname or ip address of your Senec Home device +thing-type.config.senechome.senechome.limitationDuration.label = Limitation Duration +thing-type.config.senechome.senechome.limitationDuration.description = Duration of stable values until state is changed, defined in seconds +thing-type.config.senechome.senechome.limitationTresholdValue.label = Limitation Treshold +thing-type.config.senechome.senechome.limitationTresholdValue.description = Treshold in percent, defines when limitation state is enabled +thing-type.config.senechome.senechome.refreshInterval.label = Refresh Interval +thing-type.config.senechome.senechome.refreshInterval.description = Rate of refreshing details (in s) + +# channel types + +channel-type.senechome.batteryCurrent.label = Battery Current +channel-type.senechome.batteryFuelCharge.label = Battery Fuel +channel-type.senechome.batteryPower.label = Battery Power +channel-type.senechome.batteryTemperature.label = Battery Temperature +channel-type.senechome.batteryVoltage.label = Battery Voltage +channel-type.senechome.caseTemperature.label = Case Temperature +channel-type.senechome.chargedEnergyPack1.label = Total charged energy battery pack 1 +channel-type.senechome.chargedEnergyPack2.label = Total charged energy battery pack 2 +channel-type.senechome.chargedEnergyPack3.label = Total charged energy battery pack 3 +channel-type.senechome.chargedEnergyPack4.label = Total charged energy battery pack 4 +channel-type.senechome.currentMpp1.label = Current MPP1 +channel-type.senechome.currentMpp2.label = Current MPP2 +channel-type.senechome.currentMpp3.label = Current MPP3 +channel-type.senechome.currentPack1.label = Current battery pack 1 +channel-type.senechome.currentPack2.label = Current battery pack 2 +channel-type.senechome.currentPack3.label = Current battery pack 3 +channel-type.senechome.currentPack4.label = Current battery pack 4 +channel-type.senechome.cyclesPack1.label = Cycles battery pack 1 +channel-type.senechome.cyclesPack2.label = Cycles battery pack 2 +channel-type.senechome.cyclesPack3.label = Cycles battery pack 3 +channel-type.senechome.cyclesPack4.label = Cycles battery pack 4 +channel-type.senechome.dischargedEnergyPack1.label = Total discharged energy battery pack 1 +channel-type.senechome.dischargedEnergyPack2.label = Total discharged energy battery pack 2 +channel-type.senechome.dischargedEnergyPack3.label = Total discharged energy battery pack 3 +channel-type.senechome.dischargedEnergyPack4.label = Total discharged energy battery pack 4 +channel-type.senechome.energyProduction.label = Solar Production +channel-type.senechome.gridCurrentPhase1.label = Grid Current Phase 1 +channel-type.senechome.gridCurrentPhase2.label = Grid Current Phase 2 +channel-type.senechome.gridCurrentPhase3.label = Grid Current Phase 3 +channel-type.senechome.gridFrequency.label = Grid Frequency +channel-type.senechome.gridPower.label = Grid Power +channel-type.senechome.gridPowerDraw.label = Grid Draw +channel-type.senechome.gridPowerPhase1.label = Grid Power Phase 1 +channel-type.senechome.gridPowerPhase2.label = Grid Power Phase 2 +channel-type.senechome.gridPowerPhase3.label = Grid Power Phase 3 +channel-type.senechome.gridPowerSupply.label = Grid Supply +channel-type.senechome.gridVoltagePhase1.label = Grid Voltage Phase 1 +channel-type.senechome.gridVoltagePhase2.label = Grid Voltage Phase 2 +channel-type.senechome.gridVoltagePhase3.label = Grid Voltage Phase 3 +channel-type.senechome.houseConsumption.label = House Power Consumption +channel-type.senechome.liveBatCharge.label = Live Bat Charge +channel-type.senechome.liveBatDischarge.label = Live Bat Discharge +channel-type.senechome.liveEnergyWallbox1.label = Live Wallbox 1 charged Energy +channel-type.senechome.liveGridExport.label = Live Grid Export +channel-type.senechome.liveGridImport.label = Live Grid Import +channel-type.senechome.liveHouseConsumption.label = Live House Consumption +channel-type.senechome.livePowerGenerator.label = Live Power Generator +channel-type.senechome.maxCellVoltagePack1.label = Maximum cell voltage battery pack 1 +channel-type.senechome.maxCellVoltagePack2.label = Maximum cell voltage battery pack 2 +channel-type.senechome.maxCellVoltagePack3.label = Maximum cell voltage battery pack 3 +channel-type.senechome.maxCellVoltagePack4.label = Maximum cell voltage battery pack 4 +channel-type.senechome.mcuTemperature.label = MCU Temperature +channel-type.senechome.minCellVoltagePack1.label = Minimum cell voltage battery pack 1 +channel-type.senechome.minCellVoltagePack2.label = Minimum cell voltage battery pack 2 +channel-type.senechome.minCellVoltagePack3.label = Minimum cell voltage battery pack 3 +channel-type.senechome.minCellVoltagePack4.label = Minimum cell voltage battery pack 4 +channel-type.senechome.powerLimitation.label = Power Limitation +channel-type.senechome.powerLimitationState.label = Limitation State +channel-type.senechome.powerMpp1.label = Power MPP1 +channel-type.senechome.powerMpp2.label = Power MPP2 +channel-type.senechome.powerMpp3.label = Power MPP3 +channel-type.senechome.systemState.label = System State +channel-type.senechome.systemStateValue.label = System State Value +channel-type.senechome.voltageMpp1.label = Voltage MPP1 +channel-type.senechome.voltageMpp2.label = Voltage MPP2 +channel-type.senechome.voltageMpp3.label = Voltage MPP3 +channel-type.senechome.voltagePack1.label = Voltage battery pack 1 +channel-type.senechome.voltagePack2.label = Voltage battery pack 2 +channel-type.senechome.voltagePack3.label = Voltage battery pack 3 +channel-type.senechome.voltagePack4.label = Voltage battery pack 4 +channel-type.senechome.wallbox1ChargingCurrentPhase1.label = Wallbox 1 charging Current Phase 1 +channel-type.senechome.wallbox1ChargingCurrentPhase2.label = Wallbox 1 charging Current Phase 2 +channel-type.senechome.wallbox1ChargingCurrentPhase3.label = Wallbox 1 charging Current Phase 3 +channel-type.senechome.wallbox1ChargingPower.label = Wallbox 1 charging Power +channel-type.senechome.wallbox1State.label = Wallbox 1 State +channel-type.senechome.wallbox1StateValue.label = Wallbox 1 State Value diff --git a/bundles/org.openhab.binding.seneye/src/main/resources/OH-INF/i18n/seneye.properties b/bundles/org.openhab.binding.seneye/src/main/resources/OH-INF/i18n/seneye.properties new file mode 100644 index 0000000000000..bb2e83d24383a --- /dev/null +++ b/bundles/org.openhab.binding.seneye/src/main/resources/OH-INF/i18n/seneye.properties @@ -0,0 +1,51 @@ +# binding + +binding.seneye.name = Seneye Binding +binding.seneye.description = The seneye binding polls the seneye API for your aquarium readings. + +# thing types + +thing-type.seneye.monitor.label = Seneye Monitor +thing-type.seneye.monitor.description = Seneye Monitor + +# thing types config + +thing-type.config.seneye.monitor.aquarium_name.label = Aquarium Name +thing-type.config.seneye.monitor.aquarium_name.description = The name of your aquarium +thing-type.config.seneye.monitor.password.label = Password +thing-type.config.seneye.monitor.password.description = The password of My Seneye +thing-type.config.seneye.monitor.poll_time.label = Polling Time +thing-type.config.seneye.monitor.poll_time.description = How often (in minutes) does the seneye needs to be checked ? +thing-type.config.seneye.monitor.username.label = Username +thing-type.config.seneye.monitor.username.description = The email address used to login to My Seneye + +# channel types + +channel-type.seneye.disconnected.label = Disconnected +channel-type.seneye.disconnected.description = No readings have been uploaded for a while, check connection +channel-type.seneye.kelvin.label = Kelvin +channel-type.seneye.kelvin.description = The Kelvin Light Level +channel-type.seneye.lastreading.label = Last Reading +channel-type.seneye.lastreading.description = The last time your seneye is checked +channel-type.seneye.lux.label = LUX +channel-type.seneye.lux.description = The LUX Light Level +channel-type.seneye.nh3.label = NH3 +channel-type.seneye.nh3.description = The NH3 Level +channel-type.seneye.nh4.label = NH4 +channel-type.seneye.nh4.description = The NH4 Level +channel-type.seneye.o2.label = O2 +channel-type.seneye.o2.description = The O2 Level +channel-type.seneye.outofwater.label = Out of Water +channel-type.seneye.outofwater.description = The Sensor is reporting being out of the water +channel-type.seneye.par.label = PAR +channel-type.seneye.par.description = The PAR Light Level +channel-type.seneye.ph.label = PH +channel-type.seneye.ph.description = The PH Level +channel-type.seneye.slideexpires.label = Slide Expiration +channel-type.seneye.slideexpires.description = The time your slide expires +channel-type.seneye.slideserial.label = Slide Serial Number +channel-type.seneye.slideserial.description = The serial Number of the currently installed slide +channel-type.seneye.temperature.label = Temperature +channel-type.seneye.temperature.description = The water temperature +channel-type.seneye.wrongslide.label = Wrong Slide +channel-type.seneye.wrongslide.description = The Wrong Slide is in use (becomes 1 when the slide has expired) diff --git a/bundles/org.openhab.binding.sensebox/src/main/resources/OH-INF/i18n/sensebox.properties b/bundles/org.openhab.binding.sensebox/src/main/resources/OH-INF/i18n/sensebox.properties new file mode 100644 index 0000000000000..effe01100796b --- /dev/null +++ b/bundles/org.openhab.binding.sensebox/src/main/resources/OH-INF/i18n/sensebox.properties @@ -0,0 +1,50 @@ +# binding + +binding.sensebox.name = senseBox Binding +binding.sensebox.description = The senseBox binding imports data from the senseBox Citizen Science project. + +# thing types + +thing-type.sensebox.box.label = senseBox +thing-type.sensebox.box.description = This is a senseBox sensor. + +# thing types config + +thing-type.config.sensebox.config.refreshInterval.label = Refresh Interval +thing-type.config.sensebox.config.refreshInterval.description = Refresh interval for senseBox data. +thing-type.config.sensebox.config.senseBoxId.label = Box ID +thing-type.config.sensebox.config.senseBoxId.description = Id of the box, can be found on the map details. + +# channel group types + +channel-group-type.sensebox.descriptors.label = Descriptors +channel-group-type.sensebox.descriptors.description = Box descriptors like Location, description, etc. +channel-group-type.sensebox.lastReported.label = Last Reported +channel-group-type.sensebox.lastReported.description = Timestamps when a measurement was last reported. +channel-group-type.sensebox.measurements.label = Measurements +channel-group-type.sensebox.measurements.description = Measurements as fetched from the API. + +# channel types + +channel-type.sensebox.humidityLastReported.label = Humidity Measurement Time +channel-type.sensebox.humidityLastReported.description = Timestamp when data was measured. +channel-type.sensebox.illuminance.label = Illuminance +channel-type.sensebox.illuminance.description = Current illuminance. +channel-type.sensebox.illuminanceLastReported.label = Illuminance Measurement Time +channel-type.sensebox.illuminanceLastReported.description = Timestamp when data was measured. +channel-type.sensebox.particulateMatter10.label = Particulate Matter - PM10 +channel-type.sensebox.particulateMatter10.description = Current density of particles less than 10 µm in diameter. +channel-type.sensebox.particulateMatter10LastReported.label = Particulate Matter 10 Measurement Time +channel-type.sensebox.particulateMatter10LastReported.description = Timestamp when data was measured. +channel-type.sensebox.particulateMatter2dot5.label = Particulate Matter - PM2.5 +channel-type.sensebox.particulateMatter2dot5.description = Current density of particles less than 2.5 µm in diameter. +channel-type.sensebox.particulateMatter2dot5LastReported.label = Particulate Matter 2.5 Measurement Time +channel-type.sensebox.particulateMatter2dot5LastReported.description = Timestamp when data was measured. +channel-type.sensebox.pressureLastReported.label = Pressure Measurement Time +channel-type.sensebox.pressureLastReported.description = Timestamp when data was measured. +channel-type.sensebox.temperatureLastReported.label = Temperature Measurement Time +channel-type.sensebox.temperatureLastReported.description = Timestamp when data was measured. +channel-type.sensebox.uvIntensity.label = UV Intensity +channel-type.sensebox.uvIntensity.description = Current UV intensity. +channel-type.sensebox.uvIntensityLastReported.label = UV Intensity Measurement Time +channel-type.sensebox.uvIntensityLastReported.description = Timestamp when data was measured. diff --git a/bundles/org.openhab.binding.sensibo/src/main/resources/OH-INF/i18n/sensibo.properties b/bundles/org.openhab.binding.sensibo/src/main/resources/OH-INF/i18n/sensibo.properties new file mode 100644 index 0000000000000..05d554bdd2cfc --- /dev/null +++ b/bundles/org.openhab.binding.sensibo/src/main/resources/OH-INF/i18n/sensibo.properties @@ -0,0 +1,27 @@ +# binding + +binding.sensibo.name = Sensibo Binding +binding.sensibo.description = This is the binding for Sensibo products + +# thing types + +thing-type.sensibo.account.label = Sensibo API +thing-type.sensibo.account.description = This bridge represents the gateway to Sensibo API +thing-type.sensibo.sensibosky.label = HVAC controller + +# thing types config + +thing-type.config.sensibo.account.apiKey.label = API Key +thing-type.config.sensibo.account.apiKey.description = Your Sensibo app API key +thing-type.config.sensibo.account.refreshInterval.label = Refresh Interval +thing-type.config.sensibo.account.refreshInterval.description = How often to fetch updates from Sensibo service (polling interval) +thing-type.config.sensibo.sensibosky.macAddress.label = MAC Address +thing-type.config.sensibo.sensibosky.macAddress.description = With or without colons + +# channel types + +channel-type.sensibo.currentHumidity.label = Current Humidity +channel-type.sensibo.currentTemperature.label = Current Temperature +channel-type.sensibo.masterSwitch.label = Master Switch +channel-type.sensibo.timer.label = Off Timer +channel-type.sensibo.timer.description = Number of seconds until turning off diff --git a/bundles/org.openhab.binding.serial/src/main/resources/OH-INF/i18n/serial.properties b/bundles/org.openhab.binding.serial/src/main/resources/OH-INF/i18n/serial.properties new file mode 100644 index 0000000000000..ddaaebd32d1cb --- /dev/null +++ b/bundles/org.openhab.binding.serial/src/main/resources/OH-INF/i18n/serial.properties @@ -0,0 +1,112 @@ +# binding + +binding.serial.name = Serial Binding +binding.serial.description = This binding supports sending/receiving data to/from a serial port + +# thing types + +thing-type.serial.serialBridge.label = Serial Bridge +thing-type.serial.serialBridge.description = Serial port which can send and receive data +thing-type.serial.serialDevice.label = Serial Device +thing-type.serial.serialDevice.description = Represents a device + +# thing types config + +thing-type.config.serial.serialBridge.baudRate.label = Baud Rate +thing-type.config.serial.serialBridge.baudRate.description = Set the baud rate +thing-type.config.serial.serialBridge.baudRate.option.4800 = 4800 +thing-type.config.serial.serialBridge.baudRate.option.9600 = 9600 +thing-type.config.serial.serialBridge.baudRate.option.19200 = 19200 +thing-type.config.serial.serialBridge.baudRate.option.38400 = 38400 +thing-type.config.serial.serialBridge.baudRate.option.57600 = 57600 +thing-type.config.serial.serialBridge.baudRate.option.115200 = 115200 +thing-type.config.serial.serialBridge.charset.label = Charset +thing-type.config.serial.serialBridge.charset.description = The charset to use for converting between bytes and string (e.g. UTF-8, ISO-8859-1) +thing-type.config.serial.serialBridge.dataBits.label = Data Bits +thing-type.config.serial.serialBridge.dataBits.description = Set the data bits +thing-type.config.serial.serialBridge.dataBits.option.5 = 5 +thing-type.config.serial.serialBridge.dataBits.option.6 = 6 +thing-type.config.serial.serialBridge.dataBits.option.7 = 7 +thing-type.config.serial.serialBridge.dataBits.option.8 = 8 +thing-type.config.serial.serialBridge.parity.label = Parity +thing-type.config.serial.serialBridge.parity.description = Set the parity +thing-type.config.serial.serialBridge.parity.option.N = N(one) +thing-type.config.serial.serialBridge.parity.option.O = O(dd) +thing-type.config.serial.serialBridge.parity.option.E = E(even) +thing-type.config.serial.serialBridge.parity.option.M = M(ark) +thing-type.config.serial.serialBridge.parity.option.S = S(pace) +thing-type.config.serial.serialBridge.serialPort.label = Serial Port +thing-type.config.serial.serialBridge.serialPort.description = The serial port to use (e.g. Linux: /dev/ttyUSB0, Windows: COM1) +thing-type.config.serial.serialBridge.stopBits.label = Stop Bits +thing-type.config.serial.serialBridge.stopBits.description = Set the stop bits +thing-type.config.serial.serialBridge.stopBits.option.1 = 1 +thing-type.config.serial.serialBridge.stopBits.option.1.5 = 1.5 +thing-type.config.serial.serialBridge.stopBits.option.2 = 2 +thing-type.config.serial.serialDevice.patternMatch.label = Patern Match +thing-type.config.serial.serialDevice.patternMatch.description = Regular expression used to identify device from received data (must match the whole line) + +# channel types + +channel-type.serial.binaryData.label = Binary Data +channel-type.serial.binaryData.description = Channel for sending/receiving data encoded as Base64 to/from the serial port +channel-type.serial.dimmer.label = Dimmer +channel-type.serial.dimmer.description = Channel to receive commands from a Dimmer +channel-type.serial.number.label = Number +channel-type.serial.number.description = Channel to receive commands as a number +channel-type.serial.rollershutter.label = Rollershutter +channel-type.serial.rollershutter.description = Channel to receive commands from a Rollershutter +channel-type.serial.string.label = String +channel-type.serial.string.description = Channel to receive commands as a string +channel-type.serial.stringData.label = String Data +channel-type.serial.stringData.description = Channel for sending/receiving data as a string to/from the serial port +channel-type.serial.switch.label = Switch +channel-type.serial.switch.description = Channel to receive commands from a Switch + +# channel types config + +channel-type.config.serial.dimmer.commandFormat.label = Percent Format +channel-type.config.serial.dimmer.commandFormat.description = Format string applied to the percent command, e.g. ID=671;VAL=%d +channel-type.config.serial.dimmer.commandTransformation.label = Command Transformation +channel-type.config.serial.dimmer.commandTransformation.description = Transform used to convert command to device data, e.g. JS:device.js +channel-type.config.serial.dimmer.decreaseValue.label = Decrease Value +channel-type.config.serial.dimmer.decreaseValue.description = Send this value when receiving a DECREASE command +channel-type.config.serial.dimmer.increaseValue.label = Increase Value +channel-type.config.serial.dimmer.increaseValue.description = Send this value when receiving an INCREASE command +channel-type.config.serial.dimmer.offValue.label = Off Value +channel-type.config.serial.dimmer.offValue.description = Send this value when receiving an OFF command +channel-type.config.serial.dimmer.onValue.label = On Value +channel-type.config.serial.dimmer.onValue.description = Send this value when receiving an ON command +channel-type.config.serial.dimmer.stateTransformation.label = State Transformation +channel-type.config.serial.dimmer.stateTransformation.description = Transform used to convert device data to channel state, e.g. REGEX:.*?STATE=(.*?);.* +channel-type.config.serial.number.commandFormat.label = Number Format +channel-type.config.serial.number.commandFormat.description = Format string applied to the command, e.g. ID=671;VAL=%f +channel-type.config.serial.number.commandTransformation.label = Command Transformation +channel-type.config.serial.number.commandTransformation.description = Transform used to convert command to device data, e.g. JS:device.js +channel-type.config.serial.number.stateTransformation.label = State Transformation +channel-type.config.serial.number.stateTransformation.description = Transform used to convert device data to channel state, e.g. REGEX:.*?STATE=(.*?);.* +channel-type.config.serial.rollershutter.commandFormat.label = Percent Format +channel-type.config.serial.rollershutter.commandFormat.description = Format string applied to the percent command, e.g. ID=671;VAL=%d +channel-type.config.serial.rollershutter.commandTransformation.label = Command Transformation +channel-type.config.serial.rollershutter.commandTransformation.description = Transform used to convert command to device data, e.g. JS:device.js +channel-type.config.serial.rollershutter.downValue.label = Down Value +channel-type.config.serial.rollershutter.downValue.description = Send this value when receiving a DOWN command +channel-type.config.serial.rollershutter.stateTransformation.label = State Transformation +channel-type.config.serial.rollershutter.stateTransformation.description = Transform used to convert device data to channel state, e.g. REGEX:.*?STATE=(.*?);.* +channel-type.config.serial.rollershutter.stopValue.label = Stop Value +channel-type.config.serial.rollershutter.stopValue.description = Send this value when receiving a STOP command +channel-type.config.serial.rollershutter.upValue.label = Up Value +channel-type.config.serial.rollershutter.upValue.description = Send this value when receiving an UP command +channel-type.config.serial.string.commandFormat.label = String Format +channel-type.config.serial.string.commandFormat.description = Format string applied to the command, e.g. ID=671;COMMAND=%s +channel-type.config.serial.string.commandTransformation.label = Command Transformation +channel-type.config.serial.string.commandTransformation.description = Transform used to convert command to device data, e.g. JS:device.js +channel-type.config.serial.string.stateTransformation.label = State Transformation +channel-type.config.serial.string.stateTransformation.description = Transform used to convert device data to channel state, e.g. REGEX:.*?STATE=(.*?);.* +channel-type.config.serial.switch.commandTransformation.label = Command Transformation +channel-type.config.serial.switch.commandTransformation.description = Transform used to convert command to device data, e.g. JS:device.js +channel-type.config.serial.switch.offValue.label = Off Value +channel-type.config.serial.switch.offValue.description = Send this value when receiving an OFF command +channel-type.config.serial.switch.onValue.label = On Value +channel-type.config.serial.switch.onValue.description = Send this value when receiving an ON command +channel-type.config.serial.switch.stateTransformation.label = State Transformation +channel-type.config.serial.switch.stateTransformation.description = Transform used to convert device data to channel state, e.g. REGEX:.*?STATE=(.*?);.* diff --git a/bundles/org.openhab.binding.serialbutton/src/main/resources/OH-INF/i18n/serialbutton.properties b/bundles/org.openhab.binding.serialbutton/src/main/resources/OH-INF/i18n/serialbutton.properties new file mode 100644 index 0000000000000..90e1706c39a64 --- /dev/null +++ b/bundles/org.openhab.binding.serialbutton/src/main/resources/OH-INF/i18n/serialbutton.properties @@ -0,0 +1,14 @@ +# binding + +binding.serialbutton.name = Serial Button Binding +binding.serialbutton.description = This binding supports physical push buttons connected to a serial port. + +# thing types + +thing-type.serialbutton.button.label = Push Button +thing-type.serialbutton.button.description = A simple push button + +# thing types config + +thing-type.config.serialbutton.button.port.label = Serial Port +thing-type.config.serialbutton.button.port.description = The serial port that the button is connected to diff --git a/bundles/org.openhab.binding.siemensrds/src/main/resources/OH-INF/i18n/siemensrds.properties b/bundles/org.openhab.binding.siemensrds/src/main/resources/OH-INF/i18n/siemensrds.properties new file mode 100644 index 0000000000000..0594a45a040c5 --- /dev/null +++ b/bundles/org.openhab.binding.siemensrds/src/main/resources/OH-INF/i18n/siemensrds.properties @@ -0,0 +1,69 @@ +# binding + +binding.siemensrds.name = Siemens RDS Binding +binding.siemensrds.description = This is the binding for Siemens RDS smart thermostats + +# thing types + +thing-type.siemensrds.climatixic.label = Siemens Climatix IC Account +thing-type.siemensrds.climatixic.description = The Siemens Climatix IC cloud server account for accessing RDS Smart Thermostats +thing-type.siemensrds.rds.label = RDS Thermostat +thing-type.siemensrds.rds.description = Siemens RDS Smart Thermostat +thing-type.siemensrds.rds.channel.energySavingsLevel.label = Energy Savings Level +thing-type.siemensrds.rds.channel.energySavingsLevel.description = Energy savings level (Green Leaf) +thing-type.siemensrds.rds.channel.hotWaterAutoMode.label = Hotwater Auto Mode +thing-type.siemensrds.rds.channel.hotWaterAutoMode.description = The domestic water heating is in Automatic Mode (Off = Manual Mode) +thing-type.siemensrds.rds.channel.hotWaterOutputState.label = Hotwater Output State +thing-type.siemensrds.rds.channel.hotWaterOutputState.description = The On/Off state of the domestic water heating +thing-type.siemensrds.rds.channel.occupancyModePresent.label = Occupancy Mode Present +thing-type.siemensrds.rds.channel.occupancyModePresent.description = The thermostat is in Present Occupancy Mode (Off = Away Mode) +thing-type.siemensrds.rds.channel.outsideTemperature.label = Outside Temperature +thing-type.siemensrds.rds.channel.outsideTemperature.description = Actual outside temperature +thing-type.siemensrds.rds.channel.roomAirQuality.label = Room Air Quality +thing-type.siemensrds.rds.channel.roomAirQuality.description = Actual room air quality +thing-type.siemensrds.rds.channel.roomHumidity.label = Room Humidity +thing-type.siemensrds.rds.channel.roomHumidity.description = Actual room humidity +thing-type.siemensrds.rds.channel.roomTemperature.label = Room Temperature +thing-type.siemensrds.rds.channel.roomTemperature.description = Actual room temperature +thing-type.siemensrds.rds.channel.targetTemperature.label = Target Temperature +thing-type.siemensrds.rds.channel.targetTemperature.description = Target temperature setting for the room +thing-type.siemensrds.rds.channel.thermostatAutoMode.label = Thermostat Auto Mode +thing-type.siemensrds.rds.channel.thermostatAutoMode.description = The thermostat is in Automatic Mode (Off = Manual Mode) +thing-type.siemensrds.rds.channel.thermostatOutputState.label = Thermostat Output State +thing-type.siemensrds.rds.channel.thermostatOutputState.description = The output state of the the thermostat (Heating, Cooling) + +# thing types config + +thing-type.config.siemensrds.climatixic.apiKey.label = Climatix IC API Key +thing-type.config.siemensrds.climatixic.apiKey.description = The key needed to access the Siemens Climatix IC cloud server +thing-type.config.siemensrds.climatixic.pollingInterval.label = Polling Interval +thing-type.config.siemensrds.climatixic.pollingInterval.description = Time (seconds) between polling requests (min=8, max/default=60) +thing-type.config.siemensrds.climatixic.userEmail.label = User E-mail Address +thing-type.config.siemensrds.climatixic.userEmail.description = The e-mail address that was used to register the smart thermostats +thing-type.config.siemensrds.climatixic.userPassword.label = User Password +thing-type.config.siemensrds.climatixic.userPassword.description = The password that was used to register the smart thermostats +thing-type.config.siemensrds.rds.plantId.label = Plant Id +thing-type.config.siemensrds.rds.plantId.description = The Plant Id of the thermostat in the Siemens Climatix IC cloud account + +# channel types + +channel-type.siemensrds.energySavingsLevel.label = Energy Savings Level +channel-type.siemensrds.energySavingsLevel.description = Energy savings level (Green Leaf) +channel-type.siemensrds.hotWaterAutoMode.label = Hotwater Auto Mode +channel-type.siemensrds.hotWaterAutoMode.description = The domestic water heating is in Automatic Mode (Off = Manual Mode) +channel-type.siemensrds.hotWaterOutputState.label = Hotwater Output State +channel-type.siemensrds.hotWaterOutputState.description = The On/Off state of the domestic water heating +channel-type.siemensrds.occupancyModePresent.label = Occupancy Mode Present +channel-type.siemensrds.occupancyModePresent.description = The thermostat is in Present Occupancy Mode (Off = Away Mode) +channel-type.siemensrds.roomAirQuality.label = Air Quality +channel-type.siemensrds.roomAirQuality.description = Room Air Quality +channel-type.siemensrds.roomHumidity.label = Humidity +channel-type.siemensrds.roomHumidity.description = Measured humidity value +channel-type.siemensrds.targetTemperature.label = Target Temperature +channel-type.siemensrds.targetTemperature.description = Target temperature setting +channel-type.siemensrds.temperature.label = Temperature +channel-type.siemensrds.temperature.description = Measured temperature value +channel-type.siemensrds.thermostatAutoMode.label = Thermostat Auto Mode +channel-type.siemensrds.thermostatAutoMode.description = The thermostat is in Automatic Mode (Off = Manual Mode) +channel-type.siemensrds.thermostatOutputState.label = Thermostat Output State +channel-type.siemensrds.thermostatOutputState.description = The output state of the the thermostat (Heating, Cooling) diff --git a/bundles/org.openhab.binding.silvercrestwifisocket/src/main/resources/OH-INF/i18n/silvercrestwifisocket.properties b/bundles/org.openhab.binding.silvercrestwifisocket/src/main/resources/OH-INF/i18n/silvercrestwifisocket.properties new file mode 100644 index 0000000000000..e3eb3ade934e1 --- /dev/null +++ b/bundles/org.openhab.binding.silvercrestwifisocket/src/main/resources/OH-INF/i18n/silvercrestwifisocket.properties @@ -0,0 +1,27 @@ +# binding + +binding.silvercrestwifisocket.name = Silvercrest Wifi Socket Binding +binding.silvercrestwifisocket.description = This is the binding for Silvercrest Wifi Socket sold by Lidl. + +# thing types + +thing-type.silvercrestwifisocket.wifiSocket.label = Silvercrest Wifi Socket +thing-type.silvercrestwifisocket.wifiSocket.description = Supports Silvercrest Wifi Socket SWS-A1. + +# thing types config + +thing-type.config.silvercrestwifisocket.wifiSocket.hostAddress.label = Host Address +thing-type.config.silvercrestwifisocket.wifiSocket.hostAddress.description = The socket Host address. The binding is able to discover the host address. +thing-type.config.silvercrestwifisocket.wifiSocket.macAddress.label = MAC Address +thing-type.config.silvercrestwifisocket.wifiSocket.macAddress.description = The socket MAC address. +thing-type.config.silvercrestwifisocket.wifiSocket.updateInterval.label = Update Interval +thing-type.config.silvercrestwifisocket.wifiSocket.updateInterval.description = Update time interval in seconds to request the status of the socket. +thing-type.config.silvercrestwifisocket.wifiSocket.vendor.label = Vendor +thing-type.config.silvercrestwifisocket.wifiSocket.vendor.description = The vendor selling the WiFi socket. +thing-type.config.silvercrestwifisocket.wifiSocket.vendor.option.LIDL_SILVERCREST = Lidl (Silvercrest) +thing-type.config.silvercrestwifisocket.wifiSocket.vendor.option.ALDI_EASYHOME = Aldi (EasyHome) + +# channel types + +channel-type.silvercrestwifisocket.switch.label = Socket Switch +channel-type.silvercrestwifisocket.switch.description = Silvercrest Wifi Socket Switch to turn on or off. diff --git a/bundles/org.openhab.binding.smaenergymeter/src/main/resources/OH-INF/i18n/smaenergymeter.properties b/bundles/org.openhab.binding.smaenergymeter/src/main/resources/OH-INF/i18n/smaenergymeter.properties new file mode 100644 index 0000000000000..6ad87025079e7 --- /dev/null +++ b/bundles/org.openhab.binding.smaenergymeter/src/main/resources/OH-INF/i18n/smaenergymeter.properties @@ -0,0 +1,36 @@ +# binding + +binding.smaenergymeter.name = SMA Energy Meter Binding +binding.smaenergymeter.description = Binding for a SMA Energy Meter. + +# thing types + +thing-type.smaenergymeter.energymeter.label = SMA Energy Meter + +# thing types config + +thing-type.config.smaenergymeter.energymeter.mcastGroup.label = Multicast Group +thing-type.config.smaenergymeter.energymeter.mcastGroup.description = IP address of the multicast group +thing-type.config.smaenergymeter.energymeter.pollingPeriod.label = Polling Period +thing-type.config.smaenergymeter.energymeter.pollingPeriod.description = Polling period for refreshing the data in s +thing-type.config.smaenergymeter.energymeter.port.label = Port +thing-type.config.smaenergymeter.energymeter.port.description = Port of the multicast group + +# channel types + +channel-type.smaenergymeter.energyInType.label = Purchased Energy +channel-type.smaenergymeter.energyInTypeL1.label = Purchased Energy L1 +channel-type.smaenergymeter.energyInTypeL2.label = Purchased Energy L2 +channel-type.smaenergymeter.energyInTypeL3.label = Purchased Energy L3 +channel-type.smaenergymeter.energyOutType.label = Grid Feed-in Energy +channel-type.smaenergymeter.energyOutTypeL1.label = Grid Feed-in Energy L1 +channel-type.smaenergymeter.energyOutTypeL2.label = Grid Feed-in Energy L2 +channel-type.smaenergymeter.energyOutTypeL3.label = Grid Feed-in Energy L3 +channel-type.smaenergymeter.powerInType.label = Purchased Power +channel-type.smaenergymeter.powerInTypeL1.label = Purchased Power L1 +channel-type.smaenergymeter.powerInTypeL2.label = Purchased Power L2 +channel-type.smaenergymeter.powerInTypeL3.label = Purchased Power L3 +channel-type.smaenergymeter.powerOutType.label = Grid Feed-in Power +channel-type.smaenergymeter.powerOutTypeL1.label = Grid Feed-in Power L1 +channel-type.smaenergymeter.powerOutTypeL2.label = Grid Feed-in Power L2 +channel-type.smaenergymeter.powerOutTypeL3.label = Grid Feed-in Power L3 diff --git a/bundles/org.openhab.binding.smartmeter/src/main/resources/OH-INF/i18n/smartmeter.properties b/bundles/org.openhab.binding.smartmeter/src/main/resources/OH-INF/i18n/smartmeter.properties new file mode 100644 index 0000000000000..b257c733d6fce --- /dev/null +++ b/bundles/org.openhab.binding.smartmeter/src/main/resources/OH-INF/i18n/smartmeter.properties @@ -0,0 +1,24 @@ +# binding + +binding.smartmeter.name = Smartmeter Binding +binding.smartmeter.description = The Smartmeter binding is able to read SML messages (PUSH) and supports IEC 62056-21 modes A,B,C (PULL) and D (PUSH). + +# thing types + +thing-type.smartmeter.meter.label = Smart Meter +thing-type.smartmeter.meter.description = The meter device to read the SML or IEC 62056-21 messages from + +# thing types config + +thing-type.config.smartmeter.meter.baudrate.label = Baudrate +thing-type.config.smartmeter.meter.baudrate.description = The baudrate of the serial port. If set to 'AUTO', it is dependent on the selected mode. The default is 300 baud for modes A, B, and C and 2400 baud for mode D, and 9600 baud for SML. +thing-type.config.smartmeter.meter.baudrateChangeDelay.label = Delay of Baudrate Change +thing-type.config.smartmeter.meter.baudrateChangeDelay.description = USB to serial converters often require a delay of up to 250ms after the ACK before changing baudrate +thing-type.config.smartmeter.meter.conformity.label = Conform to Specific Standard Semantics +thing-type.config.smartmeter.meter.conformity.description = Reserved to conform to special semantics specified in specific standards. EDL_FNN: Currently applies the energy direction to WATT channels (which are absolute values) (see fnn lastenheft edl) +thing-type.config.smartmeter.meter.mode.label = The Protocol Mode to Use +thing-type.config.smartmeter.meter.mode.description = Can be SML (PUSH mode), Mode A,B,C (PULL)or D (PUSH) +thing-type.config.smartmeter.meter.port.label = Serial Port +thing-type.config.smartmeter.meter.port.description = The device serial port (e.g. /dev/tty0 or COM1) +thing-type.config.smartmeter.meter.refresh.label = Refresh Rate +thing-type.config.smartmeter.meter.refresh.description = Refresh rate in seconds diff --git a/bundles/org.openhab.binding.smhi/src/main/resources/OH-INF/i18n/smhi.properties b/bundles/org.openhab.binding.smhi/src/main/resources/OH-INF/i18n/smhi.properties new file mode 100644 index 0000000000000..31439a690af92 --- /dev/null +++ b/bundles/org.openhab.binding.smhi/src/main/resources/OH-INF/i18n/smhi.properties @@ -0,0 +1,217 @@ +# binding + +binding.smhi.name = SMHI Binding +binding.smhi.description = Binding for getting weather forecasts from the Swedish Meteorological and Hydrological Institute (SMHI) + +# thing types + +thing-type.smhi.forecast.label = SMHI Weather Forecast +thing-type.smhi.forecast.description = Gets weather forecasts from SMHI +thing-type.smhi.forecast.group.day_0.label = Today +thing-type.smhi.forecast.group.day_0.description = Forecast for today +thing-type.smhi.forecast.group.day_1.label = Tomorrow +thing-type.smhi.forecast.group.day_1.description = Forecast for tomorrow +thing-type.smhi.forecast.group.day_2.label = 2 Days from Now +thing-type.smhi.forecast.group.day_2.description = Forecast for 2 days from now +thing-type.smhi.forecast.group.day_3.label = 3 Days from Now +thing-type.smhi.forecast.group.day_3.description = Forecast for 3 days from now +thing-type.smhi.forecast.group.day_4.label = 4 Days from Now +thing-type.smhi.forecast.group.day_4.description = Forecast for 4 days from now +thing-type.smhi.forecast.group.day_5.label = 5 Days from Now +thing-type.smhi.forecast.group.day_5.description = Forecast for 5 days from now +thing-type.smhi.forecast.group.day_6.label = 6 Days from Now +thing-type.smhi.forecast.group.day_6.description = Forecast for 6 days from now +thing-type.smhi.forecast.group.day_7.label = 7 Days from Now +thing-type.smhi.forecast.group.day_7.description = Forecast for 7 days from now +thing-type.smhi.forecast.group.day_8.label = 8 Days from Now +thing-type.smhi.forecast.group.day_8.description = Forecast for 8 days from now +thing-type.smhi.forecast.group.day_9.label = 9 Days from Now +thing-type.smhi.forecast.group.day_9.description = Forecast for 9 days from now +thing-type.smhi.forecast.group.hour_0.label = Current Hour +thing-type.smhi.forecast.group.hour_0.description = Forecast for the current hour +thing-type.smhi.forecast.group.hour_1.label = Next Hour +thing-type.smhi.forecast.group.hour_1.description = Forecast for the next hour +thing-type.smhi.forecast.group.hour_10.label = 10 Hours from Now +thing-type.smhi.forecast.group.hour_10.description = Forecast for 10 hours from now +thing-type.smhi.forecast.group.hour_11.label = 11 Hours from Now +thing-type.smhi.forecast.group.hour_11.description = Forecast for 11 hours from now +thing-type.smhi.forecast.group.hour_12.label = 12 Hours from Now +thing-type.smhi.forecast.group.hour_12.description = Forecast for 12 hours from now +thing-type.smhi.forecast.group.hour_13.label = 13 Hours from Now +thing-type.smhi.forecast.group.hour_13.description = Forecast for 13 hours from now +thing-type.smhi.forecast.group.hour_14.label = 14 Hours from Now +thing-type.smhi.forecast.group.hour_14.description = Forecast for 14 hours from now +thing-type.smhi.forecast.group.hour_15.label = 15 Hours from Now +thing-type.smhi.forecast.group.hour_15.description = Forecast for 15 hours from now +thing-type.smhi.forecast.group.hour_16.label = 16 Hours from Now +thing-type.smhi.forecast.group.hour_16.description = Forecast for 16 hours from now +thing-type.smhi.forecast.group.hour_17.label = 17 Hours from Now +thing-type.smhi.forecast.group.hour_17.description = Forecast for 17 hours from now +thing-type.smhi.forecast.group.hour_18.label = 18 Hours from Now +thing-type.smhi.forecast.group.hour_18.description = Forecast for 18 hours from now +thing-type.smhi.forecast.group.hour_19.label = 19 Hours from Now +thing-type.smhi.forecast.group.hour_19.description = Forecast for 19 hours from now +thing-type.smhi.forecast.group.hour_2.label = 2 Hours from Now +thing-type.smhi.forecast.group.hour_2.description = Forecast for 2 hours from now +thing-type.smhi.forecast.group.hour_20.label = 20 Hours from Now +thing-type.smhi.forecast.group.hour_20.description = Forecast for 20 hours from now +thing-type.smhi.forecast.group.hour_21.label = 21 Hours from Now +thing-type.smhi.forecast.group.hour_21.description = Forecast for 21 hours from now +thing-type.smhi.forecast.group.hour_22.label = 22 Hours from Now +thing-type.smhi.forecast.group.hour_22.description = Forecast for 22 hours from now +thing-type.smhi.forecast.group.hour_23.label = 23 Hours from Now +thing-type.smhi.forecast.group.hour_23.description = Forecast for 23 hours from now +thing-type.smhi.forecast.group.hour_24.label = 24 Hours from Now +thing-type.smhi.forecast.group.hour_24.description = Forecast for 24 hours from now +thing-type.smhi.forecast.group.hour_3.label = 3 Hours from Now +thing-type.smhi.forecast.group.hour_3.description = Forecast for 3 hours from now +thing-type.smhi.forecast.group.hour_4.label = 4 Hours from Now +thing-type.smhi.forecast.group.hour_4.description = Forecast for 4 hours from now +thing-type.smhi.forecast.group.hour_5.label = 5 Hours from Now +thing-type.smhi.forecast.group.hour_5.description = Forecast for 5 hours from now +thing-type.smhi.forecast.group.hour_6.label = 6 Hours from Now +thing-type.smhi.forecast.group.hour_6.description = Forecast for 6 hours from now +thing-type.smhi.forecast.group.hour_7.label = 7 Hours from Now +thing-type.smhi.forecast.group.hour_7.description = Forecast for 7 hours from now +thing-type.smhi.forecast.group.hour_8.label = 8 Hours from Now +thing-type.smhi.forecast.group.hour_8.description = Forecast for 8 hours from now +thing-type.smhi.forecast.group.hour_9.label = 9 Hours from Now +thing-type.smhi.forecast.group.hour_9.description = Forecast for 9 hours from now + +# thing types config + +thing-type.config.smhi.forecast.dailyForecasts.label = Daily Forecasts +thing-type.config.smhi.forecast.dailyForecasts.description = The daily forecasts to display +thing-type.config.smhi.forecast.dailyForecasts.option.0 = Today +thing-type.config.smhi.forecast.dailyForecasts.option.1 = Tomorrow +thing-type.config.smhi.forecast.dailyForecasts.option.2 = 2 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.3 = 3 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.4 = 4 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.5 = 5 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.6 = 6 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.7 = 7 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.8 = 8 days from now +thing-type.config.smhi.forecast.dailyForecasts.option.9 = 9 days from now +thing-type.config.smhi.forecast.hourlyForecasts.label = Hourly Forecasts +thing-type.config.smhi.forecast.hourlyForecasts.description = The hourly forecasts to display +thing-type.config.smhi.forecast.hourlyForecasts.option.0 = Current hour +thing-type.config.smhi.forecast.hourlyForecasts.option.1 = Next hour +thing-type.config.smhi.forecast.hourlyForecasts.option.2 = 2 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.3 = 3 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.4 = 4 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.5 = 5 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.6 = 6 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.7 = 7 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.8 = 8 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.9 = 9 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.10 = 10 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.11 = 11 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.12 = 12 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.13 = 13 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.14 = 14 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.15 = 15 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.16 = 16 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.17 = 17 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.18 = 18 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.19 = 19 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.20 = 20 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.21 = 21 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.22 = 22 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.23 = 23 hours from now +thing-type.config.smhi.forecast.hourlyForecasts.option.24 = 24 hours from now +thing-type.config.smhi.forecast.latitude.label = Latitude +thing-type.config.smhi.forecast.latitude.description = Latitude for the forecast +thing-type.config.smhi.forecast.longitude.label = Longitude +thing-type.config.smhi.forecast.longitude.description = Longitude for the forecast + +# channel group types + +channel-group-type.smhi.dailyForecast.label = Daily Forecast +channel-group-type.smhi.dailyForecast.description = Forecast at noon for the specified offset +channel-group-type.smhi.hourlyForecast.label = Hourly Forecast +channel-group-type.smhi.hourlyForecast.description = Hourly forecast for the specified offset + +# channel types + +channel-type.smhi.gust.label = Wind Gust Speed +channel-type.smhi.gust.description = Wind gust speed +channel-type.smhi.hcc_mean.label = High Level Cloud Cover +channel-type.smhi.hcc_mean.description = Mean value of high level cloud cover (> 6000 m) in percent +channel-type.smhi.lcc_mean.label = Low Level Cloud Cover +channel-type.smhi.lcc_mean.description = Mean value of low level cloud cover (0-2500 m) in percent +channel-type.smhi.mcc_mean.label = Medium Level Cloud Cover +channel-type.smhi.mcc_mean.description = Mean value of medium level cloud cover (2500-6000 m) in percent +channel-type.smhi.msl.label = Air Pressure +channel-type.smhi.msl.description = Air pressure in hPa +channel-type.smhi.pcat.label = Precipitation Category +channel-type.smhi.pcat.description = Type of precipitation +channel-type.smhi.pcat.state.option.0 = No precipitation +channel-type.smhi.pcat.state.option.1 = Snow +channel-type.smhi.pcat.state.option.2 = Snow and rain +channel-type.smhi.pcat.state.option.3 = Rain +channel-type.smhi.pcat.state.option.4 = Drizzle +channel-type.smhi.pcat.state.option.5 = Freezing rain +channel-type.smhi.pcat.state.option.6 = Freezing drizzle +channel-type.smhi.pmax.label = Maximum Precipitation +channel-type.smhi.pmax.description = Maximum precipitation intensity +channel-type.smhi.pmean.label = Mean Precipitation +channel-type.smhi.pmean.description = Mean precipitation intensity +channel-type.smhi.pmedian.label = Median Precipitation +channel-type.smhi.pmedian.description = Median precipitation intensity +channel-type.smhi.pmin.label = Minimum Precipitation +channel-type.smhi.pmin.description = Minimum precipitation intensity +channel-type.smhi.ptotal.label = Total Precipitation +channel-type.smhi.ptotal.description = Total amount of precipitation during the day +channel-type.smhi.r.label = Relative Humidity +channel-type.smhi.r.description = Relative humidity in percent +channel-type.smhi.spp.label = Frozen Precipitation +channel-type.smhi.spp.description = Percent of precipitation in frozen form +channel-type.smhi.t.label = Temperature +channel-type.smhi.t.description = Temperature +channel-type.smhi.tcc_mean.label = Total Cloud Cover +channel-type.smhi.tcc_mean.description = Mean value of total cloud cover in percent +channel-type.smhi.tmax.label = Max Temperature +channel-type.smhi.tmax.description = Highest temperature of the day +channel-type.smhi.tmin.label = Min Temperature +channel-type.smhi.tmin.description = Lowest temperature of the day +channel-type.smhi.tstm.label = Thunder Probability +channel-type.smhi.tstm.description = Probability of thunder in percent +channel-type.smhi.vis.label = Visibility +channel-type.smhi.vis.description = Horizontal visibility +channel-type.smhi.wd.label = Wind Direction +channel-type.smhi.wd.description = Wind direction +channel-type.smhi.ws.label = Wind Speed +channel-type.smhi.ws.description = Wind speed +channel-type.smhi.wsmax.label = Max Wind Speed +channel-type.smhi.wsmax.description = Highest wind speed of the day +channel-type.smhi.wsmin.label = Min Wind Speed +channel-type.smhi.wsmin.description = Lowest wind speed of the day +channel-type.smhi.wsymb2.label = Weather Condition +channel-type.smhi.wsymb2.description = Short description of the weather conditions +channel-type.smhi.wsymb2.state.option.1 = Clear sky +channel-type.smhi.wsymb2.state.option.2 = Nearly clear sky +channel-type.smhi.wsymb2.state.option.3 = Variable cloudiness +channel-type.smhi.wsymb2.state.option.4 = Halfclear sky +channel-type.smhi.wsymb2.state.option.5 = Cloudy sky +channel-type.smhi.wsymb2.state.option.6 = Overcast +channel-type.smhi.wsymb2.state.option.7 = Fog +channel-type.smhi.wsymb2.state.option.8 = Light rain showers +channel-type.smhi.wsymb2.state.option.9 = Moderate rain showers +channel-type.smhi.wsymb2.state.option.10 = Heavy rain showers +channel-type.smhi.wsymb2.state.option.11 = Thunderstorm +channel-type.smhi.wsymb2.state.option.12 = Light sleet showers +channel-type.smhi.wsymb2.state.option.13 = Moderate sleet showers +channel-type.smhi.wsymb2.state.option.14 = Heavy sleet showers +channel-type.smhi.wsymb2.state.option.15 = Light snow showers +channel-type.smhi.wsymb2.state.option.16 = Moderate snow showers +channel-type.smhi.wsymb2.state.option.17 = Heavy snow showers +channel-type.smhi.wsymb2.state.option.18 = Light rain +channel-type.smhi.wsymb2.state.option.19 = Moderate rain +channel-type.smhi.wsymb2.state.option.20 = Heavy rain +channel-type.smhi.wsymb2.state.option.21 = Thunder +channel-type.smhi.wsymb2.state.option.22 = Light sleet +channel-type.smhi.wsymb2.state.option.23 = Moderate sleet +channel-type.smhi.wsymb2.state.option.24 = Heavy sleet +channel-type.smhi.wsymb2.state.option.25 = Light snowfall +channel-type.smhi.wsymb2.state.option.26 = Moderate snowfall +channel-type.smhi.wsymb2.state.option.27 = Heavy snowfall diff --git a/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties new file mode 100644 index 0000000000000..41f2e8520e2dd --- /dev/null +++ b/bundles/org.openhab.binding.snmp/src/main/resources/OH-INF/i18n/snmp.properties @@ -0,0 +1,101 @@ +# binding + +binding.snmp.name = SNMP Binding +binding.snmp.description = This is the binding for SNMP. + +# binding config + +binding.config.snmp.port.label = Incoming SNMP Port +binding.config.snmp.port.description = Port for receiving traps, set to 0 to disable. + +# thing types + +thing-type.snmp.target.label = SNMP Target + +# thing types config + +thing-type.config.snmp.target.community.label = SNMP Community +thing-type.config.snmp.target.hostname.label = Target Host +thing-type.config.snmp.target.hostname.description = Hostname or IP address of target host +thing-type.config.snmp.target.port.label = Port +thing-type.config.snmp.target.protocol.label = SNMP Version +thing-type.config.snmp.target.protocol.option.v1 = V1 +thing-type.config.snmp.target.protocol.option.v2c = V2c +thing-type.config.snmp.target.refresh.label = Refresh Time +thing-type.config.snmp.target.refresh.description = Refresh time in s (default 60s) +thing-type.config.snmp.target.retries.label = Retries +thing-type.config.snmp.target.retries.description = Number of retries for an update request +thing-type.config.snmp.target.timeout.label = Timeout +thing-type.config.snmp.target.timeout.description = Timeout in ms for a single update request + +# channel types + +channel-type.snmp.number.label = Number +channel-type.snmp.string.label = String +channel-type.snmp.switch.label = Switch + +# channel types config + +channel-type.config.snmp.number.datatype.label = Datatype +channel-type.config.snmp.number.datatype.description = Content data type +channel-type.config.snmp.number.datatype.option.UINT32 = Unsigned Integer (32 bit) +channel-type.config.snmp.number.datatype.option.INT32 = Integer (32 bit) +channel-type.config.snmp.number.datatype.option.COUNTER64 = Counter (64 bit) +channel-type.config.snmp.number.datatype.option.FLOAT = Float +channel-type.config.snmp.number.doNotLogException.label = Don't Log Exception +channel-type.config.snmp.number.doNotLogException.description = If enabled, ignore faulty values/exceptions in this channel +channel-type.config.snmp.number.exceptionValue.label = Exception Value +channel-type.config.snmp.number.exceptionValue.description = Value to send if an SNMP exception occurs (default: UNDEF) +channel-type.config.snmp.number.mode.label = Mode +channel-type.config.snmp.number.mode.description = the mode of this channel +channel-type.config.snmp.number.mode.option.READ = Read +channel-type.config.snmp.number.mode.option.WRITE = Write +channel-type.config.snmp.number.mode.option.READ_WRITE = Read/Write +channel-type.config.snmp.number.mode.option.TRAP = Trap +channel-type.config.snmp.number.oid.label = OID +channel-type.config.snmp.number.oid.description = OID in dotted format (eg. .1.3.6.1.4.1.6574.3.1.1.3.0) +channel-type.config.snmp.number.unit.label = Unit Of Measurement +channel-type.config.snmp.number.unit.description = Unit of measurement (optional). The unit is used for representing the value in the GUI as well as for converting incoming values (like from '°F' to '°C'). Examples: "°C", "°F" +channel-type.config.snmp.string.datatype.label = Datatype +channel-type.config.snmp.string.datatype.description = Content data type +channel-type.config.snmp.string.datatype.option.STRING = String +channel-type.config.snmp.string.datatype.option.HEXSTRING = Hex-String +channel-type.config.snmp.string.datatype.option.IPADDRESS = IP Address +channel-type.config.snmp.string.doNotLogException.label = Don't Log Exception +channel-type.config.snmp.string.doNotLogException.description = If enabled, ignore faulty values/exceptions in this channel +channel-type.config.snmp.string.exceptionValue.label = Exception Value +channel-type.config.snmp.string.exceptionValue.description = Value to send if an SNMP exception occurs (default: UNDEF) +channel-type.config.snmp.string.mode.label = Mode +channel-type.config.snmp.string.mode.description = the mode of this channel +channel-type.config.snmp.string.mode.option.READ = Read +channel-type.config.snmp.string.mode.option.WRITE = Write +channel-type.config.snmp.string.mode.option.READ_WRITE = Read/Write +channel-type.config.snmp.string.mode.option.TRAP = Trap +channel-type.config.snmp.string.oid.label = OID +channel-type.config.snmp.string.oid.description = OID in dotted format (eg. .1.3.6.1.4.1.6574.3.1.1.3.0) +channel-type.config.snmp.switch.datatype.label = Datatype +channel-type.config.snmp.switch.datatype.description = Content data type +channel-type.config.snmp.switch.datatype.option.UINT32 = Unsigned Integer (32 bit) +channel-type.config.snmp.switch.datatype.option.INT32 = Integer (32 bit) +channel-type.config.snmp.switch.datatype.option.COUNTER64 = Counter (64 bit) +channel-type.config.snmp.switch.datatype.option.STRING = String +channel-type.config.snmp.switch.datatype.option.HEXSTRING = Hex-String +channel-type.config.snmp.switch.datatype.option.IPADDRESS = IP Address +channel-type.config.snmp.switch.doNotLogException.label = Don't Log Exception +channel-type.config.snmp.switch.doNotLogException.description = If enabled, faulty values/exceptions will not be logged in this channel +channel-type.config.snmp.switch.exceptionValue.label = Exception Value +channel-type.config.snmp.switch.exceptionValue.description = Value to send if an SNMP exception occurs (ON, OFF, default: UNDEF) +channel-type.config.snmp.switch.exceptionValue.option.ON = ON +channel-type.config.snmp.switch.exceptionValue.option.OFF = OFF +channel-type.config.snmp.switch.mode.label = Mode +channel-type.config.snmp.switch.mode.description = the mode of this channel +channel-type.config.snmp.switch.mode.option.READ = Read +channel-type.config.snmp.switch.mode.option.WRITE = Write +channel-type.config.snmp.switch.mode.option.READ_WRITE = Read/Write +channel-type.config.snmp.switch.mode.option.TRAP = Trap +channel-type.config.snmp.switch.offvalue.label = Off-Value +channel-type.config.snmp.switch.offvalue.description = Value that equals OFF +channel-type.config.snmp.switch.oid.label = OID +channel-type.config.snmp.switch.oid.description = OID in dotted format (eg. .1.3.6.1.4.1.6574.3.1.1.3.0) +channel-type.config.snmp.switch.onvalue.label = On-Value +channel-type.config.snmp.switch.onvalue.description = Value that equals ON diff --git a/bundles/org.openhab.binding.solaredge/src/main/resources/OH-INF/i18n/solaredge.properties b/bundles/org.openhab.binding.solaredge/src/main/resources/OH-INF/i18n/solaredge.properties new file mode 100644 index 0000000000000..889349b95abfa --- /dev/null +++ b/bundles/org.openhab.binding.solaredge/src/main/resources/OH-INF/i18n/solaredge.properties @@ -0,0 +1,131 @@ +# binding + +binding.solaredge.name = SolarEdge Binding +binding.solaredge.description = This is the binding for SolarEdge. + +# thing types + +thing-type.solaredge.generic.label = SolarEdge +thing-type.solaredge.generic.description = data retrieved from SolarEdge web interface + +# thing types config + +thing-type.config.solaredge.web.aggregateDataPollingInterval.label = Polling Interval +thing-type.config.solaredge.web.aggregateDataPollingInterval.description = Interval in which aggregate data is polled from SolarEdge (in minutes). If not using private API this must not be less than 60 minutes. +thing-type.config.solaredge.web.group.authentication.label = Authentication +thing-type.config.solaredge.web.group.authentication.description = Authentication settings. +thing-type.config.solaredge.web.group.connection.label = Connection +thing-type.config.solaredge.web.group.connection.description = Connection settings. +thing-type.config.solaredge.web.group.general.label = General +thing-type.config.solaredge.web.group.general.description = General settings. +thing-type.config.solaredge.web.liveDataPollingInterval.label = Polling Interval +thing-type.config.solaredge.web.liveDataPollingInterval.description = Interval in which live data is polled from SolarEdge (in minutes). If not using private API this should not be less than 10 minutes. +thing-type.config.solaredge.web.meterInstalled.label = Meter Installed +thing-type.config.solaredge.web.meterInstalled.description = If your setup contains a modbus meter, please activate this, to get more detailed data. +thing-type.config.solaredge.web.solarId.label = Solar ID +thing-type.config.solaredge.web.solarId.description = The ID to identify the solarplant at SolarEdge. +thing-type.config.solaredge.web.tokenOrApiKey.label = Token or API Key +thing-type.config.solaredge.web.tokenOrApiKey.description = API Key to access the official solaredge API. If using Private API this must be fills with Spring Security Token (Check Browser Cookies when logged into website) +thing-type.config.solaredge.web.usePrivateApi.label = Private API +thing-type.config.solaredge.web.usePrivateApi.description = Private API allows to avoid the limit of 300 API calls per day but is less documented and therefore less stable. If no meter is available you cannot use the private API, it does not provide live data for this kind of setup. + +# channel group types + +channel-group-type.solaredge.genericweb-aggregate-day.label = Aggregate Day Data +channel-group-type.solaredge.genericweb-aggregate-day.description = Aggregate data (by day) +channel-group-type.solaredge.genericweb-aggregate-day.channel.batterySelfConsumption.label = Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-day.channel.batterySelfConsumption.description = Aggregate Day Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-day.channel.consumption.label = Consumption +channel-group-type.solaredge.genericweb-aggregate-day.channel.consumption.description = Aggregate Day Consumption +channel-group-type.solaredge.genericweb-aggregate-day.channel.export.label = Export +channel-group-type.solaredge.genericweb-aggregate-day.channel.export.description = Aggregate Day Export +channel-group-type.solaredge.genericweb-aggregate-day.channel.import.label = Import +channel-group-type.solaredge.genericweb-aggregate-day.channel.import.description = Aggregate Day Import +channel-group-type.solaredge.genericweb-aggregate-day.channel.production.label = Production +channel-group-type.solaredge.genericweb-aggregate-day.channel.production.description = Aggregate Day Production +channel-group-type.solaredge.genericweb-aggregate-day.channel.selfConsumptionCoverage.label = Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-day.channel.selfConsumptionCoverage.description = Aggregate Day Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-day.channel.selfConsumptionForConsumption.label = Self Consumption +channel-group-type.solaredge.genericweb-aggregate-day.channel.selfConsumptionForConsumption.description = Aggregate Day Self Consumption +channel-group-type.solaredge.genericweb-aggregate-month.label = Aggregate Month Data +channel-group-type.solaredge.genericweb-aggregate-month.description = Aggregate data (by month) +channel-group-type.solaredge.genericweb-aggregate-month.channel.batterySelfConsumption.label = Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-month.channel.batterySelfConsumption.description = Aggregate Month Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-month.channel.consumption.label = Consumption +channel-group-type.solaredge.genericweb-aggregate-month.channel.consumption.description = Aggregate Month Consumption +channel-group-type.solaredge.genericweb-aggregate-month.channel.export.label = Export +channel-group-type.solaredge.genericweb-aggregate-month.channel.export.description = Aggregate Month Export +channel-group-type.solaredge.genericweb-aggregate-month.channel.import.label = Import +channel-group-type.solaredge.genericweb-aggregate-month.channel.import.description = Aggregate Month Import +channel-group-type.solaredge.genericweb-aggregate-month.channel.production.label = Production +channel-group-type.solaredge.genericweb-aggregate-month.channel.production.description = Aggregate Month Production +channel-group-type.solaredge.genericweb-aggregate-month.channel.selfConsumptionCoverage.label = Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-month.channel.selfConsumptionCoverage.description = Aggregate Month Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-month.channel.selfConsumptionForConsumption.label = Self Consumption +channel-group-type.solaredge.genericweb-aggregate-month.channel.selfConsumptionForConsumption.description = Aggregate Month Self Consumption +channel-group-type.solaredge.genericweb-aggregate-week.label = Aggregate Week Data +channel-group-type.solaredge.genericweb-aggregate-week.description = Aggregate data (by week) +channel-group-type.solaredge.genericweb-aggregate-week.channel.batterySelfConsumption.label = Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-week.channel.batterySelfConsumption.description = Aggregate Week Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-week.channel.consumption.label = Consumption +channel-group-type.solaredge.genericweb-aggregate-week.channel.consumption.description = Aggregate Week Consumption +channel-group-type.solaredge.genericweb-aggregate-week.channel.export.label = Export +channel-group-type.solaredge.genericweb-aggregate-week.channel.export.description = Aggregate Week Export +channel-group-type.solaredge.genericweb-aggregate-week.channel.import.label = Import +channel-group-type.solaredge.genericweb-aggregate-week.channel.import.description = Aggregate Week Import +channel-group-type.solaredge.genericweb-aggregate-week.channel.production.label = Production +channel-group-type.solaredge.genericweb-aggregate-week.channel.production.description = Aggregate Week Production +channel-group-type.solaredge.genericweb-aggregate-week.channel.selfConsumptionCoverage.label = Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-week.channel.selfConsumptionCoverage.description = Aggregate Week Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-week.channel.selfConsumptionForConsumption.label = Self Consumption +channel-group-type.solaredge.genericweb-aggregate-week.channel.selfConsumptionForConsumption.description = Aggregate Week Self Consumption +channel-group-type.solaredge.genericweb-aggregate-year.label = Aggregate Year Data +channel-group-type.solaredge.genericweb-aggregate-year.description = Aggregate data (by year) +channel-group-type.solaredge.genericweb-aggregate-year.channel.batterySelfConsumption.label = Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-year.channel.batterySelfConsumption.description = Aggregate Year Battery Self Consumption +channel-group-type.solaredge.genericweb-aggregate-year.channel.consumption.label = Consumption +channel-group-type.solaredge.genericweb-aggregate-year.channel.consumption.description = Aggregate Year Consumption +channel-group-type.solaredge.genericweb-aggregate-year.channel.export.label = Export +channel-group-type.solaredge.genericweb-aggregate-year.channel.export.description = Aggregate Year Export +channel-group-type.solaredge.genericweb-aggregate-year.channel.import.label = Import +channel-group-type.solaredge.genericweb-aggregate-year.channel.import.description = Aggregate Year Import +channel-group-type.solaredge.genericweb-aggregate-year.channel.production.label = Production +channel-group-type.solaredge.genericweb-aggregate-year.channel.production.description = Aggregate Year Production +channel-group-type.solaredge.genericweb-aggregate-year.channel.selfConsumptionCoverage.label = Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-year.channel.selfConsumptionCoverage.description = Aggregate Year Self Consumption Coverage +channel-group-type.solaredge.genericweb-aggregate-year.channel.selfConsumptionForConsumption.label = Self Consumption +channel-group-type.solaredge.genericweb-aggregate-year.channel.selfConsumptionForConsumption.description = Aggregate Year Self Consumption +channel-group-type.solaredge.genericweb-live.label = Live Data +channel-group-type.solaredge.genericweb-live.channel.battery_charge.label = Battery Charge +channel-group-type.solaredge.genericweb-live.channel.battery_charge.description = Current Charge Rate +channel-group-type.solaredge.genericweb-live.channel.battery_charge_discharge.label = Battery Charge/Discharge +channel-group-type.solaredge.genericweb-live.channel.battery_charge_discharge.description = Current Charge/Discharge Rate +channel-group-type.solaredge.genericweb-live.channel.battery_critical.label = Battery Critical +channel-group-type.solaredge.genericweb-live.channel.battery_critical.description = Battery Critical +channel-group-type.solaredge.genericweb-live.channel.battery_discharge.label = Battery Discharge +channel-group-type.solaredge.genericweb-live.channel.battery_discharge.description = Current Discharge Rate +channel-group-type.solaredge.genericweb-live.channel.battery_level.label = Battery Level +channel-group-type.solaredge.genericweb-live.channel.battery_level.description = Current Charge Level +channel-group-type.solaredge.genericweb-live.channel.battery_status.label = Battery Status +channel-group-type.solaredge.genericweb-live.channel.battery_status.description = Current Battery Status +channel-group-type.solaredge.genericweb-live.channel.consumption.label = Consumption +channel-group-type.solaredge.genericweb-live.channel.consumption.description = Current Consumption +channel-group-type.solaredge.genericweb-live.channel.export.label = Export +channel-group-type.solaredge.genericweb-live.channel.export.description = Current Export to Grid +channel-group-type.solaredge.genericweb-live.channel.grid_status.label = Grid Status +channel-group-type.solaredge.genericweb-live.channel.grid_status.description = Current Grid Status +channel-group-type.solaredge.genericweb-live.channel.import.label = Import +channel-group-type.solaredge.genericweb-live.channel.import.description = Current Import from Grid +channel-group-type.solaredge.genericweb-live.channel.load_status.label = Load Status +channel-group-type.solaredge.genericweb-live.channel.load_status.description = Current Load Status +channel-group-type.solaredge.genericweb-live.channel.production.label = Production +channel-group-type.solaredge.genericweb-live.channel.production.description = Current Production +channel-group-type.solaredge.genericweb-live.channel.pv_status.label = PV Status +channel-group-type.solaredge.genericweb-live.channel.pv_status.description = Current PV Status + +# channel types + +channel-type.solaredge.type-energy.label = Energy +channel-type.solaredge.type-percent.label = Percent +channel-type.solaredge.type-power.label = Power +channel-type.solaredge.type-status.label = Status Text diff --git a/bundles/org.openhab.binding.solarlog/src/main/resources/OH-INF/i18n/solarlog.properties b/bundles/org.openhab.binding.solarlog/src/main/resources/OH-INF/i18n/solarlog.properties new file mode 100644 index 0000000000000..7c36f792b76d7 --- /dev/null +++ b/bundles/org.openhab.binding.solarlog/src/main/resources/OH-INF/i18n/solarlog.properties @@ -0,0 +1,53 @@ +# binding + +binding.solarlog.name = Solar-Log Binding +binding.solarlog.description = This is the binding for the Solar-Log product range developed and sold by Solare Datensysteme GmbH. The Solar-Log devices allow monitoring of Photovoltaic (PV) installations and provide a JSON API to extract data. This includes information about current energy production and use, and other vital parameters of a PV installation. This binding makes this data accessible to openHAB from where it can be persistently stored, used to trigger actions or be displayed for information. + +# thing types + +thing-type.solarlog.meter.label = Solar-Log Meter +thing-type.solarlog.meter.description = Basic thing for the Solar-Log Binding + +# thing types config + +thing-type.config.solarlog.meter.refreshInterval.label = Refresh Interval +thing-type.config.solarlog.meter.refreshInterval.description = States how often a refresh shall occur (in s). +thing-type.config.solarlog.meter.url.label = URL +thing-type.config.solarlog.meter.url.description = URL of the Solar-Log web interface (e.g. http://solar-log) + +# channel types + +channel-type.solarlog.conspac.label = Consumption PAC +channel-type.solarlog.conspac.description = Current total consumption PAC from all of the consumption meters (W) +channel-type.solarlog.consyieldday.label = Consumption Today +channel-type.solarlog.consyieldday.description = Total consumption from all of the consumption meters +channel-type.solarlog.consyieldmonth.label = Consumption Month +channel-type.solarlog.consyieldmonth.description = Total consumption for the month; all of the consumption meters +channel-type.solarlog.consyieldtotal.label = Consumption Total +channel-type.solarlog.consyieldtotal.description = Accumulated total consumption, all Consumption meter +channel-type.solarlog.consyieldyear.label = Consumption Year +channel-type.solarlog.consyieldyear.description = Total consumption for the year; all of the consumption meters +channel-type.solarlog.consyieldyesterday.label = Consumption Yesterday +channel-type.solarlog.consyieldyesterday.description = Total consumption for the previous day; all of the consumption meters +channel-type.solarlog.lastupdate.label = Last Update +channel-type.solarlog.lastupdate.description = Last Update Time +channel-type.solarlog.pac.label = PAC +channel-type.solarlog.pac.description = Total output PAC from all of the inverters +channel-type.solarlog.pdc.label = PDC +channel-type.solarlog.pdc.description = Total output PDC from all of the inverters +channel-type.solarlog.totalpower.label = Total Power +channel-type.solarlog.totalpower.description = Installed generator power (Wp) +channel-type.solarlog.uac.label = UAC +channel-type.solarlog.uac.description = Average voltage UAC from the inverter +channel-type.solarlog.udc.label = UDC +channel-type.solarlog.udc.description = Average voltage UDC from the inverter +channel-type.solarlog.yieldday.label = Yield Day +channel-type.solarlog.yieldday.description = Total yield for the day from all of the inverters +channel-type.solarlog.yieldmonth.label = Yield Month +channel-type.solarlog.yieldmonth.description = Total yield for the month from all of the inverters +channel-type.solarlog.yieldtotal.label = Yield Total +channel-type.solarlog.yieldtotal.description = Total yield from all of the inverters +channel-type.solarlog.yieldyear.label = Yield Year +channel-type.solarlog.yieldyear.description = Total yield for the year from all of the inverters +channel-type.solarlog.yieldyesterday.label = Yield Yesterday +channel-type.solarlog.yieldyesterday.description = Total yield for the previous day from all of the inverters diff --git a/bundles/org.openhab.binding.solarwatt/src/main/resources/OH-INF/i18n/solarwatt.properties b/bundles/org.openhab.binding.solarwatt/src/main/resources/OH-INF/i18n/solarwatt.properties new file mode 100644 index 0000000000000..530b2a1063f28 --- /dev/null +++ b/bundles/org.openhab.binding.solarwatt/src/main/resources/OH-INF/i18n/solarwatt.properties @@ -0,0 +1,34 @@ +# binding + +binding.solarwatt.name = Solarwatt Binding +binding.solarwatt.description = This is the binding for Solarwatt Energymanager. + +# thing types + +thing-type.solarwatt.batteryconverter.label = Battery Converter +thing-type.solarwatt.batteryconverter.description = Battery converter to supply AC from battery storage. +thing-type.solarwatt.energymanager.label = Solarwatt Energymanager +thing-type.solarwatt.energymanager.description = Solarwatt Energymanager is the bridge to all things attached to the PV production system. +thing-type.solarwatt.evstation.label = EV Station +thing-type.solarwatt.evstation.description = Electric vehicle charger station +thing-type.solarwatt.gridflow.label = Gridflow +thing-type.solarwatt.gridflow.description = Gridflow regulates interaction with the external power grid. +thing-type.solarwatt.inverter.label = Inverter +thing-type.solarwatt.inverter.description = Inverter supplying AC from DC. +thing-type.solarwatt.location.label = Location +thing-type.solarwatt.location.description = Location aggregates all things taking part in the production process. +thing-type.solarwatt.powermeter.label = Power Meter +thing-type.solarwatt.powermeter.description = Power meter for produced or consumed energy +thing-type.solarwatt.pvplant.label = PV Plant +thing-type.solarwatt.pvplant.description = Photovoltaic plant generating DC from solar energy. + +# thing types config + +thing-type.config.solarwatt.device.guid.label = Guid of Device +thing-type.config.solarwatt.device.guid.description = Guid of the device as used by the solarwatt energymanager. +thing-type.config.solarwatt.energymanager.hostname.label = Host Name +thing-type.config.solarwatt.energymanager.hostname.description = The host name/ip address of the solarwatt energymanager. +thing-type.config.solarwatt.energymanager.refresh.label = Refresh Data Period +thing-type.config.solarwatt.energymanager.refresh.description = Period between updates to the devices data in seconds. +thing-type.config.solarwatt.energymanager.rescan.label = Redetect Devices Period +thing-type.config.solarwatt.energymanager.rescan.description = Period between updates to the detected devices in minutes. diff --git a/bundles/org.openhab.binding.somfymylink/src/main/resources/OH-INF/i18n/somfymylink.properties b/bundles/org.openhab.binding.somfymylink/src/main/resources/OH-INF/i18n/somfymylink.properties new file mode 100644 index 0000000000000..7970e75d17f1f --- /dev/null +++ b/bundles/org.openhab.binding.somfymylink/src/main/resources/OH-INF/i18n/somfymylink.properties @@ -0,0 +1,33 @@ +# binding + +binding.somfymylink.name = Somfy MyLink Binding +binding.somfymylink.description = This is the binding for Somfy MyLink. + +# thing types + +thing-type.somfymylink.mylink.label = Somfy MyLink +thing-type.somfymylink.mylink.description = Somfy MyLink bridge enabling communication with Somfy devices +thing-type.somfymylink.scene.label = Somfy Scene +thing-type.somfymylink.scene.description = Scene control +thing-type.somfymylink.shade.label = Somfy Shade +thing-type.somfymylink.shade.description = Controls shades + +# thing types config + +thing-type.config.somfymylink.mylink.ipAddress.label = IP or Hostname +thing-type.config.somfymylink.mylink.ipAddress.description = The IP or hostname of the Somfy MyLink +thing-type.config.somfymylink.mylink.systemId.label = System Id +thing-type.config.somfymylink.mylink.systemId.description = The system id of the My Link bridge. This can be found in the integration settings on your My Link app +thing-type.config.somfymylink.scene.sceneId.label = Scene ID +thing-type.config.somfymylink.scene.sceneId.description = Address of scene in the Somfy system +thing-type.config.somfymylink.shade.targetId.label = Target ID +thing-type.config.somfymylink.shade.targetId.description = Address of shade in the Somfy system + +# channel types + +channel-type.somfymylink.button.label = Scene button +channel-type.somfymylink.button.description = Button to trigger a scene or rule +channel-type.somfymylink.scenelist.label = Scene List +channel-type.somfymylink.scenelist.description = Comma-separated list of scenes of form sceneId=sceneName +channel-type.somfymylink.shadeControl.label = Control +channel-type.somfymylink.shadeControl.description = Device control (UP, DOWN, MY/STOP, closure 0-100%) diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/i18n/somfytahoma.properties b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/i18n/somfytahoma.properties new file mode 100644 index 0000000000000..32311fbcadf6a --- /dev/null +++ b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/i18n/somfytahoma.properties @@ -0,0 +1,226 @@ +# binding + +binding.somfytahoma.name = SomfyTahoma Binding +binding.somfytahoma.description = This is the binding for Somfy Tahoma and Somfy Connexoon home automation systems and for any other system based on the OverKiz API. + +# thing types + +thing-type.somfytahoma.actiongroup.label = Somfy Action Group +thing-type.somfytahoma.adjustableslatsrollershutter.label = Somfy AS Roller Shutter +thing-type.somfytahoma.adjustableslatsrollershutter.description = Somfy Adjustable Slats Roller Shutter +thing-type.somfytahoma.awning.label = Somfy Awning +thing-type.somfytahoma.bioclimaticpergola.label = Somfy Bioclimatic Pergola +thing-type.somfytahoma.bridge.label = Bridge +thing-type.somfytahoma.bridge.description = Bridge enabling communication with devices through a cloud portal +thing-type.somfytahoma.contactsensor.label = Somfy Contact Sensor +thing-type.somfytahoma.curtain.label = Somfy Curtain +thing-type.somfytahoma.dimmerlight.label = Somfy Dimmer Light +thing-type.somfytahoma.dock.label = Somfy Dock +thing-type.somfytahoma.doorlock.label = Somfy Door Lock +thing-type.somfytahoma.electricitysensor.label = Somfy Electricity Sensor +thing-type.somfytahoma.exteriorheatingsystem.label = Somfy Light Switch +thing-type.somfytahoma.exteriorscreen.label = Somfy Exterior Screen +thing-type.somfytahoma.exteriorvenetianblind.label = Somfy Exterior Venetian Blind +thing-type.somfytahoma.externalalarm.label = Somfy External Alarm +thing-type.somfytahoma.garagedoor.label = Somfy Garage Door +thing-type.somfytahoma.gate.label = Somfy Heating System with On/Off +thing-type.somfytahoma.gateway.label = Somfy Tahoma Gateway +thing-type.somfytahoma.heatingsystem.label = Z-Wave Heating System +thing-type.somfytahoma.humiditysensor.label = Somfy Humidity Sensor +thing-type.somfytahoma.internalalarm.label = Somfy Internal Alarm +thing-type.somfytahoma.light.label = Somfy Light Switch +thing-type.somfytahoma.lightsensor.label = Somfy Light Sensor +thing-type.somfytahoma.myfoxalarm.label = Somfy Myfox Alarm +thing-type.somfytahoma.myfoxcamera.label = Somfy Myfox Camera +thing-type.somfytahoma.occupancysensor.label = Somfy Occupancy Sensor +thing-type.somfytahoma.onoff.label = Somfy On/Off Switch +thing-type.somfytahoma.onoffheatingsystem.label = Somfy Heating System with On/Off +thing-type.somfytahoma.pergola.label = Somfy Pergola +thing-type.somfytahoma.pod.label = Somfy Pod +thing-type.somfytahoma.rollershutter.label = Somfy Roller Shutter +thing-type.somfytahoma.rollershutter_silent.label = Somfy Silent Roller Shutter +thing-type.somfytahoma.rollershutter_uno.label = Somfy Roller Shutter Uno +thing-type.somfytahoma.screen.label = Somfy Screen +thing-type.somfytahoma.siren.label = Somfy Siren +thing-type.somfytahoma.smokesensor.label = Somfy Smoke Sensor +thing-type.somfytahoma.temperaturesensor.label = Somfy Temperature Sensor +thing-type.somfytahoma.thermostat.label = Somfy Thermostat +thing-type.somfytahoma.valveheatingsystem.label = Somfy Thermostatic Valve +thing-type.somfytahoma.venetianblind.label = Somfy Venetian Blind +thing-type.somfytahoma.watersensor.label = Somfy Water Sensor +thing-type.somfytahoma.window.label = Somfy Window +thing-type.somfytahoma.windowhandle.label = Somfy Window Handle + +# thing types config + +bridge-type.config.somfytahoma.bridge.cloudPortal.label = Cloud Portal +bridge-type.config.somfytahoma.bridge.cloudPortal.description = Cloud portal to connect to +bridge-type.config.somfytahoma.bridge.cloudPortal.option.www.tahomalink.com = Somfy TaHoma / Somfy Connexoon IO / Somfy (Europe) +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha201-1.overkiz.com = Somfy Connexoon RTS / Somfy (Australia) +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha401-1.overkiz.com = Somfy (North America) +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha110-1.overkiz.com = Cozytouch +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha101-1.overkiz.com = eedomus +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha117-1.overkiz.com = Hi Kumo +bridge-type.config.somfytahoma.bridge.cloudPortal.option.ha112-1.overkiz.com = Rexel Energeasy Connect +bridge-type.config.somfytahoma.bridge.email.label = Email Address +bridge-type.config.somfytahoma.bridge.email.description = Email address for the portal +bridge-type.config.somfytahoma.bridge.password.label = Password +bridge-type.config.somfytahoma.bridge.password.description = Password for the portal +bridge-type.config.somfytahoma.bridge.refresh.label = Refresh +bridge-type.config.somfytahoma.bridge.refresh.description = Specifies the refresh time in seconds for polling events from the cloud +bridge-type.config.somfytahoma.bridge.retries.label = Retries +bridge-type.config.somfytahoma.bridge.retries.description = Specifies the number of retries when command execution +bridge-type.config.somfytahoma.bridge.retryDelay.label = Retry delay +bridge-type.config.somfytahoma.bridge.retryDelay.description = Specifies the delay in milliseconds between subsequent retries after a command failure +bridge-type.config.somfytahoma.bridge.statusTimeout.label = Status Timeout +bridge-type.config.somfytahoma.bridge.statusTimeout.description = Specifies the timeout in seconds after which the status is got from the cloud +thing-type.config.somfytahoma.device.url.label = Somfy Tahoma Device URL +thing-type.config.somfytahoma.device.url.description = The identifier of this Somfy device +thing-type.config.somfytahoma.gateway.id.label = Somfy Tahoma Gateway ID +thing-type.config.somfytahoma.gateway.id.description = The identifier of this Somfy gateway + +# channel types + +channel-type.somfytahoma.active_zones_state.label = Active Zones State +channel-type.somfytahoma.active_zones_state.description = Active Zones State +channel-type.somfytahoma.alarm_check.label = Alarm Check Trigger +channel-type.somfytahoma.alarm_check.description = A channel for triggering the smoke sensor's check +channel-type.somfytahoma.alarm_check.command.option.SHORT = Short check +channel-type.somfytahoma.alarm_check.command.option.LONG = Long check +channel-type.somfytahoma.alarm_command.label = Command +channel-type.somfytahoma.alarm_command.description = A channel used for sending commands to Somfy Alarm device +channel-type.somfytahoma.alarm_command.state.option.on = ARM +channel-type.somfytahoma.alarm_command.state.option.off = DISARM +channel-type.somfytahoma.alarm_command.state.option.alarmPartial1 = ARM_PARTIAL_1 +channel-type.somfytahoma.alarm_command.state.option.alarmPartial2 = ARM_PARTIAL_2 +channel-type.somfytahoma.alarm_state.label = Alarm State +channel-type.somfytahoma.alarm_state.description = A state of the Somfy Alarm +channel-type.somfytahoma.battery.label = Battery State +channel-type.somfytahoma.battery.description = Battery Condition State (full, low, normal, verylow) +channel-type.somfytahoma.battery_status.label = Battery Status State +channel-type.somfytahoma.battery_status.description = Battery Status State +channel-type.somfytahoma.closure_orientation.label = Set Closure And Orientation +channel-type.somfytahoma.closure_orientation.description = A channel for setting closure and orientation of the blind +channel-type.somfytahoma.cloud_status.label = Cloud Status State +channel-type.somfytahoma.cloud_status.description = Cloud status state of the camera +channel-type.somfytahoma.contact.label = Contact +channel-type.somfytahoma.contact.description = A contact having OPEN/CLOSE state +channel-type.somfytahoma.control.label = Control +channel-type.somfytahoma.control.description = Device control (UP, DOWN, MY/STOP, closure 0-100%) +channel-type.somfytahoma.control_silent.label = Control (silent) +channel-type.somfytahoma.control_silent.description = Device control (UP, DOWN, MY/STOP, closure 0-100%) (only for IO devices) +channel-type.somfytahoma.current_heating_mode.label = Current Heating Mode +channel-type.somfytahoma.current_heating_mode.description = Current heating mode of the Somfy thermostatic valve +channel-type.somfytahoma.current_state.label = Heating System Current State +channel-type.somfytahoma.current_state.description = A channel used for getting the heating state +channel-type.somfytahoma.current_temperature.label = Current Temperature +channel-type.somfytahoma.current_temperature.description = The current temperature of the heating system +channel-type.somfytahoma.cyclic_button.label = Cyclic Button State +channel-type.somfytahoma.cyclic_button.description = Cyclic Button State +channel-type.somfytahoma.derogation_activation.label = Derogation Activation State +channel-type.somfytahoma.derogation_activation.description = Derogation activation state of the Somfy thermostat +channel-type.somfytahoma.derogation_heating_mode.label = Derogation Heating Mode +channel-type.somfytahoma.derogation_heating_mode.description = Derogation heating mode of the Somfy thermostat/valve +channel-type.somfytahoma.derogation_heating_mode.command.option.auto = Program +channel-type.somfytahoma.derogation_heating_mode.command.option.away = Away +channel-type.somfytahoma.derogation_heating_mode.command.option.comfort = Home +channel-type.somfytahoma.derogation_heating_mode.command.option.frost protection = Frost protection +channel-type.somfytahoma.derogation_heating_mode.command.option.manual = Manual +channel-type.somfytahoma.derogation_heating_mode.command.option.eco = Night +channel-type.somfytahoma.energy_consumption.label = Energy Consumption +channel-type.somfytahoma.energy_consumption.description = The energy consumption reported by the sensor +channel-type.somfytahoma.execute_action.label = Somfy Action Group Trigger +channel-type.somfytahoma.execute_action.description = Trigger of the action group +channel-type.somfytahoma.gate_command.label = Gate Command +channel-type.somfytahoma.gate_command.description = A channel used for getting/setting the gate position (open, close, pedestrian, stop) +channel-type.somfytahoma.gate_command.state.option.open = OPEN +channel-type.somfytahoma.gate_command.state.option.close = CLOSE +channel-type.somfytahoma.gate_command.state.option.pedestrian = PEDESTRIAN +channel-type.somfytahoma.gate_command.state.option.stop = STOP +channel-type.somfytahoma.gate_position.label = Position +channel-type.somfytahoma.gate_position.description = Position of the gate +channel-type.somfytahoma.gate_state.label = Gate Status +channel-type.somfytahoma.gate_state.description = A channel used for getting the gate state (open, closed, pedestrian) +channel-type.somfytahoma.handle_state.label = Handle State +channel-type.somfytahoma.handle_state.description = A state of the Somfy Window Handle +channel-type.somfytahoma.heating_level.label = Heating Level +channel-type.somfytahoma.heating_level.description = The level of the heating +channel-type.somfytahoma.heating_mode.label = Heating Mode +channel-type.somfytahoma.heating_mode.description = Heating mode of the Somfy thermostat +channel-type.somfytahoma.humidity.label = Relative Humidity +channel-type.somfytahoma.humidity.description = The current relative humidity +channel-type.somfytahoma.intrusion_control.label = Intrusion Control +channel-type.somfytahoma.intrusion_control.description = A channel used for Alarm external intrusion controlling +channel-type.somfytahoma.intrusion_control.state.option.detected = DETECTED +channel-type.somfytahoma.intrusion_control.state.option.notDetected = NOT DETECTED +channel-type.somfytahoma.intrusion_control.state.option.pending = PENDING +channel-type.somfytahoma.intrusion_control.state.option.sos = SOS +channel-type.somfytahoma.intrusion_state.label = Alarm Intrusion State +channel-type.somfytahoma.intrusion_state.description = An intrusion state of the Somfy Alarm +channel-type.somfytahoma.light_intensity.label = Light Intensity +channel-type.somfytahoma.light_intensity.description = The intensity of the light +channel-type.somfytahoma.lighting_led_pod_mode.label = Lighting Led Pod Mod State +channel-type.somfytahoma.lighting_led_pod_mode.description = Lighting Led Pod Mod State +channel-type.somfytahoma.lock.label = Lock +channel-type.somfytahoma.lock.description = A lock having ON/OFF state (unlocked/locked) +channel-type.somfytahoma.long_beep.label = Dock Long Beep Test +channel-type.somfytahoma.long_beep.description = A channel for testing the dock's long beeping +channel-type.somfytahoma.luminance.label = Luminance +channel-type.somfytahoma.luminance.description = A light sensor luminance in lux +channel-type.somfytahoma.memorized_volume.label = Memorized Volume +channel-type.somfytahoma.memorized_volume.description = A channel used for controlling siren's volume state +channel-type.somfytahoma.memorized_volume.state.option.normal = NORMAL +channel-type.somfytahoma.memorized_volume.state.option.highest = HIGHEST +channel-type.somfytahoma.myfox_alarm_command.label = Command +channel-type.somfytahoma.myfox_alarm_command.description = A channel used for sending commands to Somfy Myfox Alarm device +channel-type.somfytahoma.myfox_alarm_command.state.option.arm = ARM +channel-type.somfytahoma.myfox_alarm_command.state.option.disarm = DISARM +channel-type.somfytahoma.myfox_alarm_command.state.option.partial = ARM_PARTIAL +channel-type.somfytahoma.open.label = Open/Close +channel-type.somfytahoma.open.description = A channel for controlling door OPEN/CLOSE state +channel-type.somfytahoma.open_closed_valve.label = Valve Open/Closed state +channel-type.somfytahoma.open_closed_valve.description = Current open/closed state of the Somfy thermostatic valve +channel-type.somfytahoma.operating_mode.label = Operating mode +channel-type.somfytahoma.operating_mode.description = Operating mode of the Somfy thermostatic valve +channel-type.somfytahoma.orientation.label = Orientation +channel-type.somfytahoma.orientation.description = Orientation of the device slats +channel-type.somfytahoma.pergola_command.label = Command +channel-type.somfytahoma.pergola_command.description = A channel used for sending commands to Somfy Bioclimatic Pergola device +channel-type.somfytahoma.pergola_command.state.option.closeSlats = Close slats +channel-type.somfytahoma.pergola_command.state.option.openSlats = Open slats +channel-type.somfytahoma.pergola_command.state.option.stop = Stop +channel-type.somfytahoma.radio_battery.label = Radio Part Battery State +channel-type.somfytahoma.radio_battery.description = State of the radio part of the Somfy sensor +channel-type.somfytahoma.rocker.label = Rocker Position +channel-type.somfytahoma.rocker.description = A channel for controlling the rocker position +channel-type.somfytahoma.rssi.label = RSSI +channel-type.somfytahoma.rssi.description = Relative received signal strength state +channel-type.somfytahoma.scenarios.label = Scenarios +channel-type.somfytahoma.scenarios.description = The scenarios defined in the cloud portal +channel-type.somfytahoma.sensor_battery.label = Sensor Part Battery State +channel-type.somfytahoma.sensor_battery.description = State of the sensor part of the Somfy sensor +channel-type.somfytahoma.sensor_defect.label = Sensor Defect State +channel-type.somfytahoma.sensor_defect.description = State of the Somfy sensor (dead, lowBattery, noDefect...) +channel-type.somfytahoma.short_beep.label = Dock Short Beep Test +channel-type.somfytahoma.short_beep.description = A channel for testing the dock's short beeping +channel-type.somfytahoma.shutter.label = Myfox Shutter +channel-type.somfytahoma.shutter.description = A channel for controlling the shutter +channel-type.somfytahoma.siren_status.label = Siren Status State +channel-type.somfytahoma.siren_status.description = A channel for controlling the dock's siren state +channel-type.somfytahoma.siren_status.state.option.on = ON +channel-type.somfytahoma.siren_status.state.option.off = OFF +channel-type.somfytahoma.siren_status.state.option.cyclic = CYCLIC +channel-type.somfytahoma.slats.label = Slats +channel-type.somfytahoma.slats.description = Slats having OPEN/CLOSED state +channel-type.somfytahoma.status.label = Status +channel-type.somfytahoma.status.description = Status for SomfyTahoma +channel-type.somfytahoma.target_heating_level.label = Target Heating Level +channel-type.somfytahoma.target_heating_level.description = A channel used for getting/setting the target heating level (on/off, frostprotection, confort, eco) +channel-type.somfytahoma.target_heating_level.state.option.frostprotection = FROSTPROTECTION +channel-type.somfytahoma.target_heating_level.state.option.comfort = COMFORT +channel-type.somfytahoma.target_heating_level.state.option.eco = ECO +channel-type.somfytahoma.target_heating_level.state.option.off = OFF +channel-type.somfytahoma.target_temperature.label = Target Temperature +channel-type.somfytahoma.target_temperature.description = The target temperature of the heating system +channel-type.somfytahoma.temperature.label = Temperature +channel-type.somfytahoma.temperature.description = The temperature value of the sensor diff --git a/bundles/org.openhab.binding.sonyaudio/src/main/resources/OH-INF/i18n/sonyaudio.properties b/bundles/org.openhab.binding.sonyaudio/src/main/resources/OH-INF/i18n/sonyaudio.properties new file mode 100644 index 0000000000000..1202a96cc7175 --- /dev/null +++ b/bundles/org.openhab.binding.sonyaudio/src/main/resources/OH-INF/i18n/sonyaudio.properties @@ -0,0 +1,194 @@ +# binding + +binding.sonyaudio.name = SonyAudio Binding +binding.sonyaudio.description = This is the binding for SonyAudio products (Receivers and wireless speakers). + +# thing types + +thing-type.sonyaudio.HT-CT800.label = SONY Soundbar HT-CT800 +thing-type.sonyaudio.HT-CT800.description = SONY Soundbar HT-CT800 +thing-type.sonyaudio.HT-MT500.label = SONY Soundbar HT-MT500 +thing-type.sonyaudio.HT-MT500.description = SONY Soundbar HT-MT500 +thing-type.sonyaudio.HT-ST5000.label = SONY Soundbar HT-ST5000 +thing-type.sonyaudio.HT-ST5000.description = SONY Soundbar HT-ST5000 +thing-type.sonyaudio.HT-Z9F.label = SONY Soundbar HT-Z9F +thing-type.sonyaudio.HT-Z9F.description = SONY Soundbar HT-Z9F +thing-type.sonyaudio.HT-ZF9.label = SONY Soundbar HT-ZF9 +thing-type.sonyaudio.HT-ZF9.description = SONY Soundbar HT-ZF9 +thing-type.sonyaudio.SRS-ZR5.label = SONY Wireless Speaker SRS-ZR5 +thing-type.sonyaudio.SRS-ZR5.description = SONY wireless Speaker SRS-ZR5 +thing-type.sonyaudio.STR-DN1080.label = SONY Receiver STR-DN1080 +thing-type.sonyaudio.STR-DN1080.description = SONY receiver STR-DN1080 + +# thing types config + +thing-type.config.sonyaudio.config.ipAddress.label = Network Address +thing-type.config.sonyaudio.config.ipAddress.description = The IP or host name of the SONY audio device +thing-type.config.sonyaudio.config.path.label = Base Path +thing-type.config.sonyaudio.config.path.description = The base path, "/sony" in most cases +thing-type.config.sonyaudio.config.port.label = Port +thing-type.config.sonyaudio.config.port.description = Port for the SONY audio device to control. Home Audio products usually use port 10000 and Personal Audio products usually use port 54480. +thing-type.config.sonyaudio.config.refreshInterval.label = Refresh Interval +thing-type.config.sonyaudio.config.refreshInterval.description = The refresh interval in seconds for polling the receiver (0=disable). Binding receive automatically updates from + +# channel group types + +channel-group-type.sonyaudio.masterControls.label = Master +channel-group-type.sonyaudio.radioControls.label = Radio +channel-group-type.sonyaudio.zone1Controls.label = Main Zone +channel-group-type.sonyaudio.zone2Controls.label = Zone 2 +channel-group-type.sonyaudio.zone4Controls.label = HDMI Zone + +# channel types + +channel-type.sonyaudio.input-ct800.label = Input Source +channel-type.sonyaudio.input-ct800.description = Select the input source of the receiver +channel-type.sonyaudio.input-ct800.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-ct800.state.option.tv = TV +channel-type.sonyaudio.input-ct800.state.option.hdmi1 = HDMI1 +channel-type.sonyaudio.input-ct800.state.option.hdmi2 = HDMI2 +channel-type.sonyaudio.input-ct800.state.option.hdmi3 = HDMI3 +channel-type.sonyaudio.input-ct800.state.option.analog = Analog +channel-type.sonyaudio.input-ct800.state.option.usb = USB +channel-type.sonyaudio.input-ct800.state.option.network = Home Network +channel-type.sonyaudio.input-ct800.state.option.cast = Chromecast +channel-type.sonyaudio.input-dn1080-zone1.label = Input Source +channel-type.sonyaudio.input-dn1080-zone1.description = Select the input source of the receiver +channel-type.sonyaudio.input-dn1080-zone1.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-dn1080-zone1.state.option.fm = FM +channel-type.sonyaudio.input-dn1080-zone1.state.option.usb = USB +channel-type.sonyaudio.input-dn1080-zone1.state.option.bd/dvd = BD/DVD +channel-type.sonyaudio.input-dn1080-zone1.state.option.game = GAME +channel-type.sonyaudio.input-dn1080-zone1.state.option.sat/catv = SAT/CATV +channel-type.sonyaudio.input-dn1080-zone1.state.option.video1 = VIDEO 1 +channel-type.sonyaudio.input-dn1080-zone1.state.option.video2 = VIDEO 2 +channel-type.sonyaudio.input-dn1080-zone1.state.option.tv = TV +channel-type.sonyaudio.input-dn1080-zone1.state.option.sa-cd/cd = SA-CD/CD +channel-type.sonyaudio.input-dn1080-zone1.state.option.network = Home Network +channel-type.sonyaudio.input-dn1080-zone1.state.option.cast = Chromecast +channel-type.sonyaudio.input-dn1080-zone2.label = Input Source +channel-type.sonyaudio.input-dn1080-zone2.description = Select the input source of the receiver +channel-type.sonyaudio.input-dn1080-zone2.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-dn1080-zone2.state.option.fm = FM +channel-type.sonyaudio.input-dn1080-zone2.state.option.usb = USB +channel-type.sonyaudio.input-dn1080-zone2.state.option.source = SOURCE +channel-type.sonyaudio.input-dn1080-zone2.state.option.sat/catv = SAT/CATV +channel-type.sonyaudio.input-dn1080-zone2.state.option.video1 = VIDEO 1 +channel-type.sonyaudio.input-dn1080-zone2.state.option.sa-cd/cd = SA-CD/CD +channel-type.sonyaudio.input-dn1080-zone2.state.option.network = Home Network +channel-type.sonyaudio.input-dn1080-zone4.label = Input Source +channel-type.sonyaudio.input-dn1080-zone4.description = Select the input source of the receiver +channel-type.sonyaudio.input-dn1080-zone4.state.option.bd/dvd = BD/DVD +channel-type.sonyaudio.input-dn1080-zone4.state.option.game = GAME +channel-type.sonyaudio.input-dn1080-zone4.state.option.sat/catv = SAT/CATV +channel-type.sonyaudio.input-dn1080-zone4.state.option.video2 = VIDEO 2 +channel-type.sonyaudio.input-dn1080-zone4.state.option.sa-cd/cd = SA-CD/CD +channel-type.sonyaudio.input-mt500.label = Input Source +channel-type.sonyaudio.input-mt500.description = Select the input source of the receiver +channel-type.sonyaudio.input-mt500.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-mt500.state.option.tv = TV +channel-type.sonyaudio.input-mt500.state.option.analog = Analog +channel-type.sonyaudio.input-mt500.state.option.usb = USB +channel-type.sonyaudio.input-mt500.state.option.network = Home Network +channel-type.sonyaudio.input-mt500.state.option.cast = Chromecast +channel-type.sonyaudio.input-st5000.label = Input Source +channel-type.sonyaudio.input-st5000.description = Select the input source of the receiver +channel-type.sonyaudio.input-st5000.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-st5000.state.option.tv = TV +channel-type.sonyaudio.input-st5000.state.option.hdmi1 = HDMI1 +channel-type.sonyaudio.input-st5000.state.option.hdmi2 = HDMI2 +channel-type.sonyaudio.input-st5000.state.option.hdmi3 = HDMI3 +channel-type.sonyaudio.input-st5000.state.option.analog = Analog +channel-type.sonyaudio.input-st5000.state.option.usb = USB +channel-type.sonyaudio.input-st5000.state.option.network = Home Network +channel-type.sonyaudio.input-st5000.state.option.cast = Chromecast +channel-type.sonyaudio.input-z9f-zf9.label = Input Source +channel-type.sonyaudio.input-z9f-zf9.description = Select the input source of the receiver +channel-type.sonyaudio.input-z9f-zf9.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-z9f-zf9.state.option.tv = TV +channel-type.sonyaudio.input-z9f-zf9.state.option.hdmi1 = HDMI1 +channel-type.sonyaudio.input-z9f-zf9.state.option.hdmi2 = HDMI2 +channel-type.sonyaudio.input-z9f-zf9.state.option.analog = Analog +channel-type.sonyaudio.input-z9f-zf9.state.option.usb = USB +channel-type.sonyaudio.input-z9f-zf9.state.option.network = Home Network +channel-type.sonyaudio.input-z9f-zf9.state.option.cast = Chromecast +channel-type.sonyaudio.input-zr5.label = Input Source +channel-type.sonyaudio.input-zr5.description = Select the input source of the speaker +channel-type.sonyaudio.input-zr5.state.option.btaudio = Bluetooth Audio +channel-type.sonyaudio.input-zr5.state.option.usb = USB +channel-type.sonyaudio.input-zr5.state.option.analog = Analog +channel-type.sonyaudio.input-zr5.state.option.hdmi1 = HDMI +channel-type.sonyaudio.input-zr5.state.option.network = Home Network +channel-type.sonyaudio.input-zr5.state.option.cast = Chromecast +channel-type.sonyaudio.mute.label = Mute +channel-type.sonyaudio.mute.description = Enable/Disable Mute on the AVR +channel-type.sonyaudio.nightMode.label = Night Mode +channel-type.sonyaudio.nightMode.description = Enable/Disable Night Mode +channel-type.sonyaudio.power.label = Power +channel-type.sonyaudio.power.description = Power on/off your device +channel-type.sonyaudio.radioBroadcastFreq.label = Broadcast Frequency +channel-type.sonyaudio.radioBroadcastFreq.description = The broadcast frequency +channel-type.sonyaudio.radioBroadcastStation.label = Broadcast Station +channel-type.sonyaudio.radioBroadcastStation.description = Select preset broadcast station +channel-type.sonyaudio.radioSeekBroadcastStation.label = Change Broadcast Station +channel-type.sonyaudio.radioSeekBroadcastStation.description = Change broadcast station +channel-type.sonyaudio.radioSeekBroadcastStation.state.option.fwdSeeking = Seek Forward +channel-type.sonyaudio.radioSeekBroadcastStation.state.option.bwdSeeking = Seek Backward +channel-type.sonyaudio.sound-field-ct800.label = Sound Field +channel-type.sonyaudio.sound-field-ct800.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-ct800.state.option.clearAudio = ClearAudio+ +channel-type.sonyaudio.sound-field-ct800.state.option.movie = Movie +channel-type.sonyaudio.sound-field-ct800.state.option.music = Music +channel-type.sonyaudio.sound-field-ct800.state.option.sports = Sports +channel-type.sonyaudio.sound-field-ct800.state.option.game = Game Studio +channel-type.sonyaudio.sound-field-ct800.state.option.standard = Standard +channel-type.sonyaudio.sound-field-dn1080.label = Sound Field +channel-type.sonyaudio.sound-field-dn1080.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-dn1080.state.option.pureDirect = Pure Direct +channel-type.sonyaudio.sound-field-dn1080.state.option.2chStereo = 2ch Stereo +channel-type.sonyaudio.sound-field-dn1080.state.option.multiChStereo = Multi Ch Stereo +channel-type.sonyaudio.sound-field-dn1080.state.option.direct = Direct +channel-type.sonyaudio.sound-field-dn1080.state.option.audioFormatDecoding = A.F.D. +channel-type.sonyaudio.sound-field-dn1080.state.option.dolbySurround = Dolby Surround +channel-type.sonyaudio.sound-field-dn1080.state.option.neuralX = Neural:X +channel-type.sonyaudio.sound-field-dn1080.state.option.frontSurround = Front Surround +channel-type.sonyaudio.sound-field-dn1080.state.option.audioEnhancer = Audio Enhancer +channel-type.sonyaudio.sound-field-mt500.label = Sound Field +channel-type.sonyaudio.sound-field-mt500.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-mt500.state.option.clearAudio = ClearAudio+ +channel-type.sonyaudio.sound-field-mt500.state.option.movie = Movie +channel-type.sonyaudio.sound-field-mt500.state.option.music = Music +channel-type.sonyaudio.sound-field-mt500.state.option.sports = Sports +channel-type.sonyaudio.sound-field-mt500.state.option.game = Game Studio +channel-type.sonyaudio.sound-field-mt500.state.option.standard = Standard +channel-type.sonyaudio.sound-field-st5000.label = Sound Field +channel-type.sonyaudio.sound-field-st5000.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-st5000.state.option.clearAudio = ClearAudio+ +channel-type.sonyaudio.sound-field-st5000.state.option.3dsurround = 3D Surround +channel-type.sonyaudio.sound-field-st5000.state.option.movie = Movie +channel-type.sonyaudio.sound-field-st5000.state.option.music = Music +channel-type.sonyaudio.sound-field-st5000.state.option.sports = Sports +channel-type.sonyaudio.sound-field-st5000.state.option.game = Game Studio +channel-type.sonyaudio.sound-field-st5000.state.option.standard = Standard +channel-type.sonyaudio.sound-field-z9f-zf9.label = Sound Field +channel-type.sonyaudio.sound-field-z9f-zf9.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.auto = Auto Sound +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.news = News +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.cinemaStudio = Cinema +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.music = Music +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.sports = Sports +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.game = Game Studio +channel-type.sonyaudio.sound-field-z9f-zf9.state.option.standard = Standard +channel-type.sonyaudio.sound-field-zr5.label = Sound Field +channel-type.sonyaudio.sound-field-zr5.description = Select the Sound Field for the receiver +channel-type.sonyaudio.sound-field-zr5.state.option.clearAudio = ClearAudio+ +channel-type.sonyaudio.sound-field-zr5.state.option.hiphop = R&B / HIP HOP +channel-type.sonyaudio.sound-field-zr5.state.option.standard = FLAT +channel-type.sonyaudio.sound-field-zr5.state.option.rock = ROCK +channel-type.sonyaudio.sound-field-zr5.state.option.pop = POP +channel-type.sonyaudio.sound-field-zr5.state.option.latin = LATIN +channel-type.sonyaudio.sound-field-zr5.state.option.jazz = JAZZ +channel-type.sonyaudio.sound-field-zr5.state.option.classic = CLASSIC +channel-type.sonyaudio.sound-field-zr5.state.option.custom = CUSTOM +channel-type.sonyaudio.volume.label = Volume +channel-type.sonyaudio.volume.description = Set the volume level diff --git a/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/i18n/souliss.properties b/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/i18n/souliss.properties new file mode 100644 index 0000000000000..e426cf86f84aa --- /dev/null +++ b/bundles/org.openhab.binding.souliss/src/main/resources/OH-INF/i18n/souliss.properties @@ -0,0 +1,327 @@ +# binding + +binding.souliss.name = Souliss Binding +binding.souliss.description = This is the binding for Souliss. The Arduino based SmartHome.. + +# thing types + +thing-type.souliss.gateway.label = Gateway +thing-type.souliss.gateway.description = Represents a Souliss Gateway. +thing-type.souliss.t11.label = T11 +thing-type.souliss.t11.description = Simple Light +thing-type.souliss.t12.label = T12 +thing-type.souliss.t12.description = Simple Light with Auto Mode +thing-type.souliss.t13.label = T13 +thing-type.souliss.t13.description = Digital Input +thing-type.souliss.t14.label = T14 +thing-type.souliss.t14.description = Pulse Digital Output +thing-type.souliss.t16.label = T16 +thing-type.souliss.t16.description = RGB LED Strip +thing-type.souliss.t18.label = T18 +thing-type.souliss.t18.description = Simple Light with feedback +thing-type.souliss.t19.label = T19 +thing-type.souliss.t19.description = Single Color LED Strip +thing-type.souliss.t1a.label = T1A +thing-type.souliss.t1a.description = Digital input pass through +thing-type.souliss.t1a.channel.eight.label = 8 +thing-type.souliss.t1a.channel.five.label = 5 +thing-type.souliss.t1a.channel.four.label = 4 +thing-type.souliss.t1a.channel.one.label = 1 +thing-type.souliss.t1a.channel.seven.label = 7 +thing-type.souliss.t1a.channel.six.label = 6 +thing-type.souliss.t1a.channel.three.label = 3 +thing-type.souliss.t1a.channel.two.label = 2 +thing-type.souliss.t21.label = T21 +thing-type.souliss.t21.description = Motorized devices with limit switches +thing-type.souliss.t22.label = T22 +thing-type.souliss.t22.description = Motorized devices with limit switches and middle position +thing-type.souliss.t31.label = T31 +thing-type.souliss.t31.description = Temperature control with cooling and heating mode +thing-type.souliss.t31.channel.fire.label = Fire +thing-type.souliss.t31.channel.mode.label = Mode +thing-type.souliss.t31.channel.setAsMeasured.label = As Measured +thing-type.souliss.t31.channel.system.label = System +thing-type.souliss.t41.label = T41 +thing-type.souliss.t41.description = Anti-theft integration (Main) +thing-type.souliss.t41.channel.onOffAlarm.label = Alarm ON/OFF +thing-type.souliss.t41.channel.rearmAlarm.label = Rearm +thing-type.souliss.t41.channel.statusAlarm.label = Alarm Status +thing-type.souliss.t42.label = T42 +thing-type.souliss.t42.description = Anti-theft integration (Peer) +thing-type.souliss.t42.channel.onOffAlarm.label = Alarm ON/OFF +thing-type.souliss.t42.channel.rearmAlarm.label = Rearm +thing-type.souliss.t42.channel.statusAlarm.label = Alarm Status +thing-type.souliss.t51.label = T51 +thing-type.souliss.t51.description = Floating Point Input +thing-type.souliss.t52.label = T52 +thing-type.souliss.t52.description = Temperature measure (-20, +50) °C +thing-type.souliss.t53.label = T53 +thing-type.souliss.t53.description = Humidity measure (0, 100) % +thing-type.souliss.t54.label = T54 +thing-type.souliss.t54.description = Light Sensor (0, 40) kLux +thing-type.souliss.t55.label = T55 +thing-type.souliss.t55.description = Voltage (0, 400) V +thing-type.souliss.t56.label = T56 +thing-type.souliss.t56.description = Current (0, 25) A +thing-type.souliss.t57.label = T57 +thing-type.souliss.t57.description = Power (0, 6500) W +thing-type.souliss.t58.label = T58 +thing-type.souliss.t58.description = Pressure measure (0, 1500) hPa +thing-type.souliss.t61.label = T61 +thing-type.souliss.t61.description = Analog setpoint +thing-type.souliss.t62.label = T62 +thing-type.souliss.t62.description = Temperature measure (-20, +50) °C +thing-type.souliss.t63.label = T63 +thing-type.souliss.t63.description = Humidity measure (0, 100) % +thing-type.souliss.t64.label = T64 +thing-type.souliss.t64.description = Light Sensor (0, 40) kLux +thing-type.souliss.t65.label = T65 +thing-type.souliss.t65.description = Voltage (0, 400) V +thing-type.souliss.t66.label = T66 +thing-type.souliss.t66.description = Current (0, 25) A +thing-type.souliss.t67.label = T67 +thing-type.souliss.t67.description = Power (0, 6500) W +thing-type.souliss.t68.label = T68 +thing-type.souliss.t68.description = Pressure measure (0, 1500) hPa +thing-type.souliss.topic.label = Action Message +thing-type.souliss.topic.description = Look at: Souliss Wiki, Peer 2 Peer Communication. These are messages published in broadcast from souliss nodes in channels defined by two value: number and variant. + +# thing types config + +thing-type.config.souliss.gateway.gatewayLanAddress.label = IPV4 Address +thing-type.config.souliss.gateway.gatewayLanAddress.description = LAN Ip address (mandatory) +thing-type.config.souliss.gateway.gatewayPortNumber.label = Gateway Port +thing-type.config.souliss.gateway.gatewayPortNumber.description = Default is 230 UDP. +thing-type.config.souliss.gateway.gatewayWanAddress.label = IPV4 WAN Address +thing-type.config.souliss.gateway.gatewayWanAddress.description = WAN Hostname or Ip in case of external network access +thing-type.config.souliss.gateway.healthyInterval.label = Healthy Interval +thing-type.config.souliss.gateway.healthyInterval.description = Interval in seconds to send nodes healthy. +thing-type.config.souliss.gateway.nodeIndex.label = Node Index +thing-type.config.souliss.gateway.nodeIndex.description = Node Index +thing-type.config.souliss.gateway.pingInterval.label = Ping Interval +thing-type.config.souliss.gateway.pingInterval.description = Interval in seconds to check for device presence. +thing-type.config.souliss.gateway.preferredLocalPortNumber.label = Local Port Number +thing-type.config.souliss.gateway.preferredLocalPortNumber.description = Default port is 23000 +thing-type.config.souliss.gateway.sendInterval.label = Send Interval +thing-type.config.souliss.gateway.sendInterval.description = Interval in milliseconds to get packet from binding queue and send it to Souliss. First packet is sent immediately. +thing-type.config.souliss.gateway.subscriptionInterval.label = Subscription Interval +thing-type.config.souliss.gateway.subscriptionInterval.description = Interval in seconds to subscribe Souliss Gateway. +thing-type.config.souliss.gateway.timeoutToRemovePacket.label = Timeout to Remove Packet +thing-type.config.souliss.gateway.timeoutToRemovePacket.description = Interval in milliseconds to remove packet from queue if not yet executed +thing-type.config.souliss.gateway.timeoutToRequeue.label = Timeout to Requeue +thing-type.config.souliss.gateway.timeoutToRequeue.description = Interval in milliseconds to requeue packet in queue if not yet executed +thing-type.config.souliss.gateway.userIndex.label = User Index +thing-type.config.souliss.gateway.userIndex.description = User Index +thing-type.config.souliss.t11.node.label = Node +thing-type.config.souliss.t11.node.description = Node +thing-type.config.souliss.t11.secureSend.label = Secure Send +thing-type.config.souliss.t11.secureSend.description = (conf.parameter: "secureSend") +thing-type.config.souliss.t11.sleep.label = Sleep +thing-type.config.souliss.t11.sleep.description = Set sleep timer in cycles (conf.parameter: "sleep") +thing-type.config.souliss.t11.slot.label = Slot +thing-type.config.souliss.t11.slot.description = Slot +thing-type.config.souliss.t12.node.label = Node +thing-type.config.souliss.t12.node.description = Node +thing-type.config.souliss.t12.secureSend.label = Secure Send +thing-type.config.souliss.t12.sleep.label = Sleep +thing-type.config.souliss.t12.sleep.description = Set sleep timer in cycles +thing-type.config.souliss.t12.slot.label = Slot +thing-type.config.souliss.t12.slot.description = Slot +thing-type.config.souliss.t13.node.label = Node +thing-type.config.souliss.t13.node.description = Node +thing-type.config.souliss.t13.slot.label = Slot +thing-type.config.souliss.t13.slot.description = Slot +thing-type.config.souliss.t14.node.label = Node +thing-type.config.souliss.t14.node.description = Node +thing-type.config.souliss.t14.slot.label = Slot +thing-type.config.souliss.t14.slot.description = Slot +thing-type.config.souliss.t16.node.label = Node +thing-type.config.souliss.t16.node.description = Node +thing-type.config.souliss.t16.secureSend.label = Secure Send +thing-type.config.souliss.t16.sleep.label = Sleep +thing-type.config.souliss.t16.sleep.description = Set sleep timer in cycles +thing-type.config.souliss.t16.slot.label = Slot +thing-type.config.souliss.t16.slot.description = Slot +thing-type.config.souliss.t18.node.label = Node +thing-type.config.souliss.t18.node.description = Node +thing-type.config.souliss.t18.secureSend.label = Secure Send +thing-type.config.souliss.t18.sleep.label = Sleep +thing-type.config.souliss.t18.sleep.description = Set sleep timer in cycles +thing-type.config.souliss.t18.slot.label = Slot +thing-type.config.souliss.t18.slot.description = Slot +thing-type.config.souliss.t19.node.label = Node +thing-type.config.souliss.t19.node.description = Node +thing-type.config.souliss.t19.sleep.label = Sleep +thing-type.config.souliss.t19.sleep.description = Set sleep timer in cycles +thing-type.config.souliss.t19.slot.label = Slot +thing-type.config.souliss.t19.slot.description = Slot +thing-type.config.souliss.t1a.node.label = Node +thing-type.config.souliss.t1a.node.description = Node +thing-type.config.souliss.t1a.slot.label = Slot +thing-type.config.souliss.t1a.slot.description = Slot +thing-type.config.souliss.t21.node.label = Node +thing-type.config.souliss.t21.node.description = Node +thing-type.config.souliss.t21.secureSend.label = Secure Send +thing-type.config.souliss.t21.slot.label = Slot +thing-type.config.souliss.t21.slot.description = Slot +thing-type.config.souliss.t22.node.label = Node +thing-type.config.souliss.t22.node.description = Node +thing-type.config.souliss.t22.secureSend.label = Secure Send +thing-type.config.souliss.t22.slot.label = Slot +thing-type.config.souliss.t22.slot.description = Slot +thing-type.config.souliss.t31.node.label = Node +thing-type.config.souliss.t31.node.description = Node +thing-type.config.souliss.t31.slot.label = Slot +thing-type.config.souliss.t31.slot.description = Slot +thing-type.config.souliss.t41.node.label = Node +thing-type.config.souliss.t41.node.description = Node +thing-type.config.souliss.t41.secureSend.label = Secure Send +thing-type.config.souliss.t41.slot.label = Slot +thing-type.config.souliss.t41.slot.description = Slot +thing-type.config.souliss.t42.node.label = Node +thing-type.config.souliss.t42.node.description = Node +thing-type.config.souliss.t42.secureSend.label = Secure Send +thing-type.config.souliss.t42.slot.label = Slot +thing-type.config.souliss.t42.slot.description = Slot +thing-type.config.souliss.t51.node.label = Node +thing-type.config.souliss.t51.node.description = Node +thing-type.config.souliss.t51.slot.label = Slot +thing-type.config.souliss.t51.slot.description = Slot +thing-type.config.souliss.t52.node.label = Node +thing-type.config.souliss.t52.node.description = Node +thing-type.config.souliss.t52.slot.label = Slot +thing-type.config.souliss.t52.slot.description = Slot +thing-type.config.souliss.t53.node.label = Node +thing-type.config.souliss.t53.node.description = Node +thing-type.config.souliss.t53.slot.label = Slot +thing-type.config.souliss.t53.slot.description = Slot +thing-type.config.souliss.t54.node.label = Node +thing-type.config.souliss.t54.node.description = Node +thing-type.config.souliss.t54.slot.label = Slot +thing-type.config.souliss.t54.slot.description = Slot +thing-type.config.souliss.t55.node.label = Node +thing-type.config.souliss.t55.node.description = Node +thing-type.config.souliss.t55.slot.label = Slot +thing-type.config.souliss.t55.slot.description = Slot +thing-type.config.souliss.t56.node.label = Node +thing-type.config.souliss.t56.node.description = Node +thing-type.config.souliss.t56.slot.label = Slot +thing-type.config.souliss.t56.slot.description = Slot +thing-type.config.souliss.t57.node.label = Node +thing-type.config.souliss.t57.node.description = Node +thing-type.config.souliss.t57.slot.label = Slot +thing-type.config.souliss.t57.slot.description = Slot +thing-type.config.souliss.t58.node.label = Node +thing-type.config.souliss.t58.node.description = Node +thing-type.config.souliss.t58.slot.label = Slot +thing-type.config.souliss.t58.slot.description = Slot +thing-type.config.souliss.t61.node.label = Node +thing-type.config.souliss.t61.node.description = Node +thing-type.config.souliss.t61.slot.label = Slot +thing-type.config.souliss.t61.slot.description = Slot +thing-type.config.souliss.t62.node.label = Node +thing-type.config.souliss.t62.node.description = Node +thing-type.config.souliss.t62.slot.label = Slot +thing-type.config.souliss.t62.slot.description = Slot +thing-type.config.souliss.t63.node.label = Node +thing-type.config.souliss.t63.node.description = Node +thing-type.config.souliss.t63.slot.label = Slot +thing-type.config.souliss.t63.slot.description = Slot +thing-type.config.souliss.t64.node.label = Node +thing-type.config.souliss.t64.node.description = Node +thing-type.config.souliss.t64.slot.label = Slot +thing-type.config.souliss.t64.slot.description = Slot +thing-type.config.souliss.t65.node.label = Node +thing-type.config.souliss.t65.node.description = Node +thing-type.config.souliss.t65.slot.label = Slot +thing-type.config.souliss.t65.slot.description = Slot +thing-type.config.souliss.t66.node.label = Node +thing-type.config.souliss.t66.node.description = Node +thing-type.config.souliss.t66.slot.label = Slot +thing-type.config.souliss.t66.slot.description = Slot +thing-type.config.souliss.t67.node.label = Node +thing-type.config.souliss.t67.node.description = Node +thing-type.config.souliss.t67.slot.label = Slot +thing-type.config.souliss.t67.slot.description = Slot +thing-type.config.souliss.t68.node.label = Node +thing-type.config.souliss.t68.node.description = Node +thing-type.config.souliss.t68.slot.label = Slot +thing-type.config.souliss.t68.slot.description = Slot +thing-type.config.souliss.topic.number.label = Number +thing-type.config.souliss.topic.number.description = Topic Number +thing-type.config.souliss.topic.variant.label = Variant +thing-type.config.souliss.topic.variant.description = Topic Variant + +# channel types + +channel-type.souliss.ampere.label = Current +channel-type.souliss.ampere.description = Current Ampere +channel-type.souliss.autoMode.label = On/Off Auto Mode +channel-type.souliss.autoMode.description = Switch on/off +channel-type.souliss.button.label = Button +channel-type.souliss.button.description = Button to trigger something +channel-type.souliss.buttonReadOnly.label = Button +channel-type.souliss.buttonReadOnly.description = Button to trigger something +channel-type.souliss.dimmerBrightness.label = Dimmer Brightness +channel-type.souliss.dimmerBrightness.description = The brightness can be set in 16 steps for RGBW/White leds and in 64 steps for RGBWW leds +channel-type.souliss.fan-channel.label = Fan +channel-type.souliss.fan-channel.state.option.AUTO = Auto +channel-type.souliss.fan-channel.state.option.HIGH = High +channel-type.souliss.fan-channel.state.option.MEDIUM = Medium +channel-type.souliss.fan-channel.state.option.LOW = Low +channel-type.souliss.fan-channel.state.option.FANOFF = Powered off +channel-type.souliss.float.label = Value +channel-type.souliss.float.description = Floating Point Input +channel-type.souliss.float6n.label = Setpoint +channel-type.souliss.float6n.description = Floating Point Input +channel-type.souliss.healthy.label = Healthy +channel-type.souliss.healthy.description = Souliss Healthy +channel-type.souliss.humidity.label = Humidity +channel-type.souliss.humidity.description = Current humidity in % +channel-type.souliss.lastMessage.label = Last Message +channel-type.souliss.lastMessage.description = Last Message emitted by the module +channel-type.souliss.lastStatusStored.label = Last Status Stored +channel-type.souliss.lastStatusStored.description = Last Status Store +channel-type.souliss.ledColor.label = Color +channel-type.souliss.ledColor.description = Color of the LED. Bound to a Dimmer to just set the brightness, bind to a Color chooser for the full control and bind to a Switch for turning the led on or off. +channel-type.souliss.lux.label = Illuminance +channel-type.souliss.lux.description = Lux +channel-type.souliss.mode-channel.label = Mode +channel-type.souliss.mode-channel.state.option.COOLING_MODE = Cool +channel-type.souliss.mode-channel.state.option.HEATING_MODE = Heat +channel-type.souliss.onoff.label = On/Off +channel-type.souliss.onoff.description = Switch on/off +channel-type.souliss.power.label = Power +channel-type.souliss.power.description = Current Power +channel-type.souliss.pressure.label = Pressure +channel-type.souliss.pressure.description = Pressure +channel-type.souliss.pulse.label = Pulse +channel-type.souliss.pulse.description = Set +channel-type.souliss.rollerBrightness.label = Roller Brightness +channel-type.souliss.rollerBrightness.description = Brightness Up/Down +channel-type.souliss.rollerShutter.label = Rollershutter +channel-type.souliss.rollerShutter.description = Rollershutter Up/Down +channel-type.souliss.rollerShutterState.label = State +channel-type.souliss.rollerShutterState.description = State of rollershutter/windows +channel-type.souliss.rollerShutterState.state.option.opening = Opening +channel-type.souliss.rollerShutterState.state.option.stop = Stop +channel-type.souliss.rollerShutterState.state.option.closing = Closing +channel-type.souliss.rollerShutterState.state.option.limSwitchOpen = Limit Switch Open +channel-type.souliss.rollerShutterState.state.option.limSwitchClose = Limit Switch Close +channel-type.souliss.rollerShutterState.state.option.stateOpen = Opened +channel-type.souliss.rollerShutterState.state.option.stateClose = Closed +channel-type.souliss.rollerShutterState.state.option.NoLimSwitch = No Limit Switch +channel-type.souliss.setpointTemperature.label = Setpoint Temperature +channel-type.souliss.setpointTemperature.description = Setpoint temperature +channel-type.souliss.sleep.label = Set Timer +channel-type.souliss.sleep.description = The output will be timed for nCYCLES of the Node associated timer +channel-type.souliss.stateOnOff.label = State On/Off +channel-type.souliss.stateOnOff.description = Light on/off +channel-type.souliss.stateOpenClose.label = State Open/Closed +channel-type.souliss.stateOpenClose.description = Contact Open/Closed +channel-type.souliss.temperature.label = Temperature +channel-type.souliss.temperature.description = Current temperature +channel-type.souliss.voltage.label = Voltage +channel-type.souliss.voltage.description = Current Voltage +channel-type.souliss.whiteMode.label = White Mode +channel-type.souliss.whiteMode.description = Switch lamp to white mode diff --git a/bundles/org.openhab.binding.squeezebox/src/main/resources/OH-INF/i18n/squeezebox.properties b/bundles/org.openhab.binding.squeezebox/src/main/resources/OH-INF/i18n/squeezebox.properties new file mode 100644 index 0000000000000..1ef09d716e741 --- /dev/null +++ b/bundles/org.openhab.binding.squeezebox/src/main/resources/OH-INF/i18n/squeezebox.properties @@ -0,0 +1,113 @@ +# binding + +binding.squeezebox.name = SqueezeBox Binding +binding.squeezebox.description = This is the binding for the Logitech Squeeze Server and Players. + +# binding config + +binding.config.squeezebox.callbackUrl.label = Callback URL +binding.config.squeezebox.callbackUrl.description = URL to use for playing notification sounds, e.g. http://192.168.0.2:8080 + +# thing types + +thing-type.squeezebox.squeezeboxplayer.label = SqueezeBox Player +thing-type.squeezebox.squeezeboxplayer.description = This is a SqueezeBox Player instance +thing-type.squeezebox.squeezeboxserver.label = SqueezeBox Server +thing-type.squeezebox.squeezeboxserver.description = This is a SqueezeBox Server instance. + +# thing types config + +thing-type.config.squeezebox.squeezeboxplayer.mac.label = MAC Address +thing-type.config.squeezebox.squeezeboxplayer.mac.description = SqueezeBox Players are identified by their MAC address +thing-type.config.squeezebox.squeezeboxplayer.notificationTimeout.label = Notification Timeout +thing-type.config.squeezebox.squeezeboxplayer.notificationTimeout.description = Maximum amount of time in seconds for which the notification will be played +thing-type.config.squeezebox.squeezeboxplayer.notificationVolume.label = Notification Sound Volume +thing-type.config.squeezebox.squeezeboxplayer.notificationVolume.description = Volume used for notifications. Leaving blank uses current player volume. +thing-type.config.squeezebox.squeezeboxserver.cliport.label = SqueezeServer CLI Port +thing-type.config.squeezebox.squeezeboxserver.cliport.description = Port of the CLI interface of the SqueezeServer +thing-type.config.squeezebox.squeezeboxserver.ipAddress.label = IP or Host Name +thing-type.config.squeezebox.squeezeboxserver.ipAddress.description = The IP or host name of the SqueezeServer +thing-type.config.squeezebox.squeezeboxserver.language.label = Language +thing-type.config.squeezebox.squeezeboxserver.language.description = Language to use when using Google speech +thing-type.config.squeezebox.squeezeboxserver.password.label = Password +thing-type.config.squeezebox.squeezeboxserver.password.description = Password used to login to Squeeze Server +thing-type.config.squeezebox.squeezeboxserver.userId.label = User Id +thing-type.config.squeezebox.squeezeboxserver.userId.description = User ID used to login to Squeeze Server +thing-type.config.squeezebox.squeezeboxserver.webport.label = SqueezeServer Web Port +thing-type.config.squeezebox.squeezeboxserver.webport.description = Webport interface of the SqueezeServer + +# channel types + +channel-type.squeezebox.album.label = Album +channel-type.squeezebox.album.description = Album name of the current song +channel-type.squeezebox.artist.label = Artist +channel-type.squeezebox.artist.description = Artist name of the current song +channel-type.squeezebox.control.label = Control +channel-type.squeezebox.control.description = Control the Zone Player, e.g. start/stop/next/previous/ffward/rewind +channel-type.squeezebox.coverartdata.label = Cover Art +channel-type.squeezebox.coverartdata.description = Image data of cover art of the current song +channel-type.squeezebox.currentPlayingTime.label = Current Playing Time +channel-type.squeezebox.currentPlayingTime.description = Current Playing Time +channel-type.squeezebox.currentPlaylistRepeat.label = Repeat Mode +channel-type.squeezebox.currentPlaylistRepeat.description = Current playlist repeat Mode +channel-type.squeezebox.currentPlaylistRepeat.state.option.0 = No Repeat +channel-type.squeezebox.currentPlaylistRepeat.state.option.1 = Repeat Song +channel-type.squeezebox.currentPlaylistRepeat.state.option.2 = Repeat Playlist +channel-type.squeezebox.currentPlaylistShuffle.label = Shuffle Mode +channel-type.squeezebox.currentPlaylistShuffle.description = Current playlist shuffle mode +channel-type.squeezebox.currentPlaylistShuffle.state.option.0 = No Shuffle +channel-type.squeezebox.currentPlaylistShuffle.state.option.1 = Shuffle Songs +channel-type.squeezebox.currentPlaylistShuffle.state.option.2 = Shuffle Albums +channel-type.squeezebox.duration.label = Track Duration +channel-type.squeezebox.duration.description = Duration of Current Track (in seconds) +channel-type.squeezebox.favoritesList.label = Favorites List +channel-type.squeezebox.favoritesList.description = Comma-separated list of favorites of form favoriteId=favoriteName +channel-type.squeezebox.genre.label = Genre +channel-type.squeezebox.genre.description = Genre name of the current song +channel-type.squeezebox.ircode.label = IR Code +channel-type.squeezebox.ircode.description = String of the cached IR code +channel-type.squeezebox.mute.label = Mute +channel-type.squeezebox.mute.description = Mute/unmute your device +channel-type.squeezebox.next.label = Next +channel-type.squeezebox.next.description = Send a next command to the player +channel-type.squeezebox.numberPlaylistTracks.label = Number of Playlist Tracks +channel-type.squeezebox.numberPlaylistTracks.description = Number of playlist tracks +channel-type.squeezebox.pause.label = Pause +channel-type.squeezebox.pause.description = Send a pause command to the player +channel-type.squeezebox.playFavorite.label = Play a Favorite +channel-type.squeezebox.playFavorite.description = Play favorite by sending command with favoriteId +channel-type.squeezebox.playListIndex.label = Playlist Index +channel-type.squeezebox.playListIndex.description = Playlist index +channel-type.squeezebox.playPause.label = Play/Pause +channel-type.squeezebox.playPause.description = Plays (on) or pauses (off) the player +channel-type.squeezebox.power.label = Power +channel-type.squeezebox.power.description = Power on/off your device +channel-type.squeezebox.prev.label = Previous +channel-type.squeezebox.prev.description = Send a previous command to the player +channel-type.squeezebox.rate.label = Like or Unlike Song +channel-type.squeezebox.rate.description = Likes or unlikes the current song (if the service supports it) +channel-type.squeezebox.remotetitle.label = Remote Title +channel-type.squeezebox.remotetitle.description = Remote Title (Radio) of the current song +channel-type.squeezebox.sleep.label = Sleep +channel-type.squeezebox.sleep.description = Power off player in specified number of minutes +channel-type.squeezebox.source.label = Source +channel-type.squeezebox.source.description = Shows the source of the currently playing playlist entry. +channel-type.squeezebox.stop.label = Stop +channel-type.squeezebox.stop.description = Stop the current title +channel-type.squeezebox.stream.label = Stream URL +channel-type.squeezebox.stream.description = Play the given HTTP or file stream (file:// or http://). +channel-type.squeezebox.sync.label = Sync Player +channel-type.squeezebox.sync.description = Add another player to your device for synchronized playback (other player mac address) +channel-type.squeezebox.title.label = Title +channel-type.squeezebox.title.description = Title of the current song +channel-type.squeezebox.unsync.label = UnSync Player +channel-type.squeezebox.unsync.description = Remove this device from synchronization +channel-type.squeezebox.volume.label = Volume +channel-type.squeezebox.volume.description = Volume of your device +channel-type.squeezebox.year.label = Year +channel-type.squeezebox.year.description = Release year of the current song + +# channel types config + +channel-type.config.squeezebox.favoritesList.quoteList.label = Quote Favorites +channel-type.config.squeezebox.favoritesList.quoteList.description = Wrap the right hand side of the favorites in quotes diff --git a/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties new file mode 100644 index 0000000000000..a46a9b2eb58c6 --- /dev/null +++ b/bundles/org.openhab.binding.systeminfo/src/main/resources/OH-INF/i18n/systeminfo.properties @@ -0,0 +1,151 @@ +# binding + +binding.systeminfo.name = Systeminfo Binding +binding.systeminfo.description = This binding provides information about the operating system and the hardware. + +# thing types + +thing-type.systeminfo.computer.label = Systeminfo +thing-type.systeminfo.computer.description = The computer operating system and hardware information + +# thing types config + +thing-type.config.systeminfo.computerConfig.interval_high.label = Interval for High Priority Tasks +thing-type.config.systeminfo.computerConfig.interval_high.description = Refresh interval in seconds. +thing-type.config.systeminfo.computerConfig.interval_medium.label = Interval for Medium Priority Tasks +thing-type.config.systeminfo.computerConfig.interval_medium.description = Refresh interval in seconds. + +# channel group types + +channel-group-type.systeminfo.batteryGroup.label = Battery +channel-group-type.systeminfo.batteryGroup.description = Battery parameters +channel-group-type.systeminfo.cpuGroup.label = CPU +channel-group-type.systeminfo.cpuGroup.description = CPU parameters +channel-group-type.systeminfo.displayGroup.label = Display +channel-group-type.systeminfo.displayGroup.description = Display parameters +channel-group-type.systeminfo.driveGroup.label = Drive +channel-group-type.systeminfo.driveGroup.description = Drive information +channel-group-type.systeminfo.memoryGroup.label = Physical Memory +channel-group-type.systeminfo.memoryGroup.description = Physical memory information +channel-group-type.systeminfo.networkGroup.label = Network +channel-group-type.systeminfo.networkGroup.description = Network parameters +channel-group-type.systeminfo.processGroup.label = Process +channel-group-type.systeminfo.processGroup.description = System process information +channel-group-type.systeminfo.sensorsGroup.label = Sensor +channel-group-type.systeminfo.sensorsGroup.description = Sensor parameters +channel-group-type.systeminfo.storageGroup.label = Storage +channel-group-type.systeminfo.storageGroup.description = Logical storage information +channel-group-type.systeminfo.swapGroup.label = Swap Memory +channel-group-type.systeminfo.swapGroup.description = Swap memory information + +# channel types + +channel-type.systeminfo.available.label = Available +channel-type.systeminfo.available.description = Available size in MB +channel-type.systeminfo.availableHeap.label = Available Heap +channel-type.systeminfo.availableHeap.description = How much data is available in the Java heap. +channel-type.systeminfo.availablePercent.label = Available (%) +channel-type.systeminfo.availablePercent.description = Available size in percent +channel-type.systeminfo.cpuTemp.label = CPU Temperature +channel-type.systeminfo.cpuTemp.description = CPU Temperature in Celsius degrees +channel-type.systeminfo.cpuVoltage.label = CPU Voltage +channel-type.systeminfo.cpuVoltage.description = CPU Voltage in V +channel-type.systeminfo.dataReceived.label = Data Received +channel-type.systeminfo.dataReceived.description = Data received in MB +channel-type.systeminfo.dataSent.label = Data Sent +channel-type.systeminfo.dataSent.description = Data sent in MB +channel-type.systeminfo.description.label = Description +channel-type.systeminfo.description.description = Description of the device +channel-type.systeminfo.fanSpeed.label = Fan Speed +channel-type.systeminfo.fanSpeed.description = Fan speed in rpm +channel-type.systeminfo.information.label = Display Information +channel-type.systeminfo.information.description = Product, manufacturer, SN, width and height of the display in cm +channel-type.systeminfo.ip.label = IP Address +channel-type.systeminfo.ip.description = Host IP address of the network +channel-type.systeminfo.loadAverage.label = Load Average +channel-type.systeminfo.loadAverage.description = Load as a number of processes for the last 1,5 or 15 minutes +channel-type.systeminfo.load_process.label = Load +channel-type.systeminfo.load_process.description = Load in percent +channel-type.systeminfo.mac.label = Mac Address +channel-type.systeminfo.mac.description = Mac address of the network +channel-type.systeminfo.model.label = Model +channel-type.systeminfo.model.description = The model of the device +channel-type.systeminfo.name.label = Name +channel-type.systeminfo.name.description = Name of the device (process) +channel-type.systeminfo.name_process.label = Name +channel-type.systeminfo.name_process.description = Name of the device (process) +channel-type.systeminfo.networkDisplayName.label = Network Display Name +channel-type.systeminfo.networkDisplayName.description = The display name of the network +channel-type.systeminfo.networkName.label = Network Name +channel-type.systeminfo.networkName.description = The name of the network. +channel-type.systeminfo.packetsReceived.label = Packets Received +channel-type.systeminfo.packetsReceived.description = Number of packets received +channel-type.systeminfo.packetsSent.label = Packets Sent +channel-type.systeminfo.packetsSent.description = Number of packets sent +channel-type.systeminfo.path_process.label = Path +channel-type.systeminfo.path_process.description = The full path +channel-type.systeminfo.remainingCapacity.label = Remaining Capacity +channel-type.systeminfo.remainingCapacity.description = Remaining capacity in percent +channel-type.systeminfo.remainingTime.label = Remaining Time +channel-type.systeminfo.remainingTime.description = Remaining time in minutes +channel-type.systeminfo.serial.label = Serial Number +channel-type.systeminfo.serial.description = The serial number of the device +channel-type.systeminfo.threads.label = Number of Threads +channel-type.systeminfo.threads.description = Number of threads currently running +channel-type.systeminfo.threads_process.label = Number of Threads +channel-type.systeminfo.threads_process.description = Number of threads currently running +channel-type.systeminfo.total.label = Total +channel-type.systeminfo.total.description = Total size in MB +channel-type.systeminfo.type.label = Type +channel-type.systeminfo.type.description = Storage type +channel-type.systeminfo.uptime.label = System Uptime +channel-type.systeminfo.uptime.description = System uptime (time after start) in minutes +channel-type.systeminfo.used.label = Used +channel-type.systeminfo.used.description = Used size in MB +channel-type.systeminfo.usedHeapPercent.label = Used Heap Percent +channel-type.systeminfo.usedHeapPercent.description = How much data in percent has been used from the max size the Java heap can grow to. +channel-type.systeminfo.usedPercent.label = Used (%) +channel-type.systeminfo.usedPercent.description = Used size in percent +channel-type.systeminfo.used_process.label = Used +channel-type.systeminfo.used_process.description = Used size in MB + +# channel types config + +channel-type.config.systeminfo.highpriority.priority.label = Interval +channel-type.config.systeminfo.highpriority.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.highpriority.priority.option.High = High +channel-type.config.systeminfo.highpriority.priority.option.Medium = Medium +channel-type.config.systeminfo.highpriority.priority.option.Low = Low +channel-type.config.systeminfo.highpriority_process.pid.label = PID +channel-type.config.systeminfo.highpriority_process.pid.description = The Process Identifier of the process. +channel-type.config.systeminfo.highpriority_process.priority.label = Interval +channel-type.config.systeminfo.highpriority_process.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.highpriority_process.priority.option.High = High +channel-type.config.systeminfo.highpriority_process.priority.option.Medium = Medium +channel-type.config.systeminfo.highpriority_process.priority.option.Low = Low +channel-type.config.systeminfo.lowpriority.group.priorityGroup.label = String +channel-type.config.systeminfo.lowpriority.group.priorityGroup.description = String +channel-type.config.systeminfo.lowpriority.priority.label = Interval +channel-type.config.systeminfo.lowpriority.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.lowpriority.priority.option.High = High +channel-type.config.systeminfo.lowpriority.priority.option.Medium = Medium +channel-type.config.systeminfo.lowpriority.priority.option.Low = Low +channel-type.config.systeminfo.lowpriority_process.pid.label = PID +channel-type.config.systeminfo.lowpriority_process.pid.description = The Process Identifier of the process. +channel-type.config.systeminfo.lowpriority_process.priority.label = Interval +channel-type.config.systeminfo.lowpriority_process.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.lowpriority_process.priority.option.High = High +channel-type.config.systeminfo.lowpriority_process.priority.option.Medium = Medium +channel-type.config.systeminfo.lowpriority_process.priority.option.Low = Low +channel-type.config.systeminfo.mediumpriority.priority.label = Interval +channel-type.config.systeminfo.mediumpriority.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.mediumpriority.priority.option.High = High +channel-type.config.systeminfo.mediumpriority.priority.option.Medium = Medium +channel-type.config.systeminfo.mediumpriority.priority.option.Low = Low +channel-type.config.systeminfo.mediumpriority_process.pid.label = PID +channel-type.config.systeminfo.mediumpriority_process.pid.description = The Process Identifier of the process. +channel-type.config.systeminfo.mediumpriority_process.priority.label = Interval +channel-type.config.systeminfo.mediumpriority_process.priority.description = Refresh interval in seconds. +channel-type.config.systeminfo.mediumpriority_process.priority.option.High = High +channel-type.config.systeminfo.mediumpriority_process.priority.option.Medium = Medium +channel-type.config.systeminfo.mediumpriority_process.priority.option.Low = Low diff --git a/bundles/org.openhab.binding.tacmi/src/main/resources/OH-INF/i18n/tacmi.properties b/bundles/org.openhab.binding.tacmi/src/main/resources/OH-INF/i18n/tacmi.properties new file mode 100644 index 0000000000000..fd0795389bf3f --- /dev/null +++ b/bundles/org.openhab.binding.tacmi/src/main/resources/OH-INF/i18n/tacmi.properties @@ -0,0 +1,93 @@ +# binding + +binding.tacmi.name = TA C.M.I. Binding +binding.tacmi.description = This is the binding for TA C.M.I. + +# thing types + +thing-type.tacmi.cmi.label = TA C.M.I. CoE Connection +thing-type.tacmi.cmi.description = CoE Communication to the "Technische Alternative C.M.I. Control and Monitoring Interface" +thing-type.tacmi.cmiSchema.label = TA C.M.I. Schema API Connection +thing-type.tacmi.cmiSchema.description = Communication to a special "API" schema page on a "Technische Alternative C.M.I. Control and Monitoring Interface" +thing-type.tacmi.coe-bridge.label = TA C.M.I. CoE Bridge +thing-type.tacmi.coe-bridge.description = This bridge opens the CoE-UDP Port 5441 on OpenHAB for communication with "Technische Alternative C.M.I." + +# thing types config + +thing-type.config.tacmi.cmi.host.label = C.M.I. IP Address +thing-type.config.tacmi.cmi.host.description = Host name of IP address of the CMI +thing-type.config.tacmi.cmi.node.label = Node +thing-type.config.tacmi.cmi.node.description = The CoE / CAN Node number openHAB should represent +thing-type.config.tacmi.cmiSchema.host.label = C.M.I. IP Address +thing-type.config.tacmi.cmiSchema.host.description = Host name or IP address of the C.M.I. +thing-type.config.tacmi.cmiSchema.password.label = Password +thing-type.config.tacmi.cmiSchema.password.description = Password for authentication on the C.M.I. +thing-type.config.tacmi.cmiSchema.pollInterval.label = Poll Interval +thing-type.config.tacmi.cmiSchema.pollInterval.description = Poll interval (in seconds) how often to poll the API Page +thing-type.config.tacmi.cmiSchema.schemaId.label = API Schema Id +thing-type.config.tacmi.cmiSchema.schemaId.description = ID of the schema API page +thing-type.config.tacmi.cmiSchema.username.label = Username +thing-type.config.tacmi.cmiSchema.username.description = Username for authentication on the C.M.I. + +# channel types + +channel-type.tacmi.coe-analog-in.label = Analog Input Channel (C.M.I. -> OH) +channel-type.tacmi.coe-analog-in.description = A Analog Channel received from the C.M.I. +channel-type.tacmi.coe-analog-out.label = Analog Output Channel (OH -> C.M.I.) +channel-type.tacmi.coe-analog-out.description = A Analog Channel sent to the C.M.I. +channel-type.tacmi.coe-digital-in.label = Digital Input (C.M.I. -> OH) +channel-type.tacmi.coe-digital-in.description = A digital channel sent from C.M.I. to openHAB +channel-type.tacmi.coe-digital-out.label = Digital Output (OH -> C.M.I.) +channel-type.tacmi.coe-digital-out.description = A digital channel sent from OpenHAB to C.M.I. +channel-type.tacmi.schema-numeric-ro.label = Value +channel-type.tacmi.schema-numeric-ro.description = A numeric value read from C.M.I. +channel-type.tacmi.schema-state-ro.label = Value +channel-type.tacmi.schema-state-ro.description = A state value read from C.M.I. +channel-type.tacmi.schema-switch-ro.label = Switch State (Read-Only) +channel-type.tacmi.schema-switch-ro.description = An On/Off state read from C.M.I. +channel-type.tacmi.schema-switch-rw.label = Switch State (Changeable) +channel-type.tacmi.schema-switch-rw.description = A modifiable On/Off state read from C.M.I. + +# channel types config + +channel-type.config.tacmi.coe-analog-in.output.label = Output +channel-type.config.tacmi.coe-analog-in.output.description = C.M.I. Network Output +channel-type.config.tacmi.coe-analog-out.initialValue.label = Initial Value +channel-type.config.tacmi.coe-analog-out.initialValue.description = Initial value to set after startup (optional, defaults to uninitialized) +channel-type.config.tacmi.coe-analog-out.output.label = Output +channel-type.config.tacmi.coe-analog-out.output.description = Network Output +channel-type.config.tacmi.coe-analog-out.type.label = Measurement Type +channel-type.config.tacmi.coe-analog-out.type.description = Measurement type for this channel +channel-type.config.tacmi.coe-analog-out.type.option.0 = None +channel-type.config.tacmi.coe-analog-out.type.option.1 = Temperature +channel-type.config.tacmi.coe-analog-out.type.option.2 = Unknown 2 +channel-type.config.tacmi.coe-analog-out.type.option.3 = Unknown 3 +channel-type.config.tacmi.coe-analog-out.type.option.4 = Seconds +channel-type.config.tacmi.coe-analog-out.type.option.5 = Unknown 5 +channel-type.config.tacmi.coe-analog-out.type.option.6 = Unknown 6 +channel-type.config.tacmi.coe-analog-out.type.option.7 = Unknown 7 +channel-type.config.tacmi.coe-analog-out.type.option.8 = Unknown 8 +channel-type.config.tacmi.coe-analog-out.type.option.9 = Unknown 9 +channel-type.config.tacmi.coe-analog-out.type.option.10 = kW (Kilowatt) +channel-type.config.tacmi.coe-analog-out.type.option.11 = kWh (Kilowatt hours) +channel-type.config.tacmi.coe-analog-out.type.option.12 = MWh (Megawatt hours) +channel-type.config.tacmi.coe-analog-out.type.option.13 = Unknown 13 +channel-type.config.tacmi.coe-analog-out.type.option.14 = Unknown 14 +channel-type.config.tacmi.coe-analog-out.type.option.15 = Unknown 15 +channel-type.config.tacmi.coe-analog-out.type.option.16 = Unknown 16 +channel-type.config.tacmi.coe-analog-out.type.option.17 = Unknown 17 +channel-type.config.tacmi.coe-analog-out.type.option.18 = Unknown 18 +channel-type.config.tacmi.coe-analog-out.type.option.19 = Unknown 19 +channel-type.config.tacmi.coe-analog-out.type.option.20 = Unknown 20 +channel-type.config.tacmi.coe-analog-out.type.option.21 = Unknown 21 +channel-type.config.tacmi.coe-digital-in.output.label = Output +channel-type.config.tacmi.coe-digital-in.output.description = C.M.I. Network Output +channel-type.config.tacmi.coe-digital-out.initialValue.label = Initial Value +channel-type.config.tacmi.coe-digital-out.initialValue.description = Initial value to set after startup (optional, defaults to uninitialized) +channel-type.config.tacmi.coe-digital-out.output.label = Output +channel-type.config.tacmi.coe-digital-out.output.description = Network Output +channel-type.config.tacmi.schemaApiDefaults.updatePolicy.label = Update Policy +channel-type.config.tacmi.schemaApiDefaults.updatePolicy.description = Update policy for this channel. Default means "On-Change" for channels that can be modified and "On-Fetch" for read-only channels. +channel-type.config.tacmi.schemaApiDefaults.updatePolicy.option.0 = Default +channel-type.config.tacmi.schemaApiDefaults.updatePolicy.option.1 = On-Fetch +channel-type.config.tacmi.schemaApiDefaults.updatePolicy.option.2 = On-Update diff --git a/bundles/org.openhab.binding.tado/src/main/resources/OH-INF/i18n/tado.properties b/bundles/org.openhab.binding.tado/src/main/resources/OH-INF/i18n/tado.properties new file mode 100644 index 0000000000000..887555f05a7ea --- /dev/null +++ b/bundles/org.openhab.binding.tado/src/main/resources/OH-INF/i18n/tado.properties @@ -0,0 +1,80 @@ +# binding + +binding.tado.name = tado° Binding +binding.tado.description = Binding for tado° devices + +# thing types + +thing-type.tado.home.label = Tado Home +thing-type.tado.home.description = The user's tado home +thing-type.tado.mobiledevice.label = Mobile Device +thing-type.tado.mobiledevice.description = Mobile device of a home +thing-type.tado.zone.label = Zone +thing-type.tado.zone.description = A zone of a home +thing-type.tado.zone.channel.batteryLowAlarm.label = Battery Low Alarm +thing-type.tado.zone.channel.batteryLowAlarm.description = ON if one or more devices in the zone have a low battery + +# thing types config + +thing-type.config.tado.home.password.label = Password +thing-type.config.tado.home.password.description = Password of tado login used for API access +thing-type.config.tado.home.username.label = User Name +thing-type.config.tado.home.username.description = User name of tado login used for API access +thing-type.config.tado.mobiledevice.id.label = Mobile Device Id +thing-type.config.tado.mobiledevice.id.description = Id of the mobile device +thing-type.config.tado.mobiledevice.refreshInterval.label = Refresh Interval +thing-type.config.tado.mobiledevice.refreshInterval.description = Refresh interval of location state +thing-type.config.tado.zone.fallbackTimerDuration.label = Fallback Timer Duration +thing-type.config.tado.zone.fallbackTimerDuration.description = Timer duration used if no other duration can be determined +thing-type.config.tado.zone.hvacChangeDebounce.label = HVAC Change Debounce Delay +thing-type.config.tado.zone.hvacChangeDebounce.description = Duration in seconds to combine multiple HVAC changes into one. +thing-type.config.tado.zone.id.label = Zone Id +thing-type.config.tado.zone.id.description = Id of the zone +thing-type.config.tado.zone.refreshInterval.label = Refresh Interval +thing-type.config.tado.zone.refreshInterval.description = Refresh interval of home data + +# channel types + +channel-type.tado.acPower.label = AirCon Power State +channel-type.tado.acPower.description = Indicates if the air-conditioning is Off or On +channel-type.tado.atHome.label = At Home +channel-type.tado.atHome.description = ON if at home, OFF if away +channel-type.tado.currentTemperature.label = Temperature +channel-type.tado.currentTemperature.description = Current temperature +channel-type.tado.fanspeed.label = Fan Speed +channel-type.tado.fanspeed.description = AC fan speed (only if supported by AC) +channel-type.tado.fanspeed.state.option.LOW = Low +channel-type.tado.fanspeed.state.option.MIDDLE = Middle +channel-type.tado.fanspeed.state.option.HIGH = High +channel-type.tado.fanspeed.state.option.AUTO = Auto +channel-type.tado.heatingPower.label = Heating Power +channel-type.tado.heatingPower.description = Current heating power +channel-type.tado.homePresence.label = At Home +channel-type.tado.homePresence.description = ON if at home, OFF if away +channel-type.tado.humidity.label = Humidity +channel-type.tado.humidity.description = Current humidity in % +channel-type.tado.hvacMode.label = HVAC Mode +channel-type.tado.hvacMode.description = Mode of the device (OFF, HEAT, COOL, DRY, FAN, AUTO - if supported) +channel-type.tado.hvacMode.state.option.OFF = Off +channel-type.tado.hvacMode.state.option.HEAT = Heat +channel-type.tado.hvacMode.state.option.COOL = Cool +channel-type.tado.hvacMode.state.option.DRY = Dry +channel-type.tado.hvacMode.state.option.FAN = Fan +channel-type.tado.hvacMode.state.option.AUTO = Auto +channel-type.tado.openWindowDetected.label = Open Window Detected +channel-type.tado.openWindowDetected.description = Indicates if an open window has been detected +channel-type.tado.operationMode.label = Zone Operation Mode +channel-type.tado.operationMode.description = Active operation mode (schedule, manual, timer or until next change) +channel-type.tado.operationMode.state.option.SCHEDULE = Schedule +channel-type.tado.operationMode.state.option.MANUAL = Manual +channel-type.tado.operationMode.state.option.UNTIL_CHANGE = Until change +channel-type.tado.operationMode.state.option.TIMER = Timer +channel-type.tado.overlayExpiry.label = Overlay End Time +channel-type.tado.overlayExpiry.description = Time until when the overlay is active. Null if no overlay is set or overlay type is manual. +channel-type.tado.overlayExpiry.state.pattern = %1$tF %1$tR +channel-type.tado.swing.label = Swing +channel-type.tado.swing.description = State of AC swing (only if supported by AC) +channel-type.tado.targetTemperature.label = Target Temperature +channel-type.tado.targetTemperature.description = Thermostat temperature setpoint +channel-type.tado.timerDuration.label = Timer Duration +channel-type.tado.timerDuration.description = Total duration of a timer diff --git a/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig.properties b/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig.properties new file mode 100644 index 0000000000000..466dd001dd4f8 --- /dev/null +++ b/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig.properties @@ -0,0 +1,35 @@ +# binding + +binding.tankerkoenig.name = Tankerkönig Binding +binding.tankerkoenig.description = The Tankerkönig Binding allows to poll fuel prices of German gas stations by using the Tankerkoenig.de API. + +# thing types + +thing-type.tankerkoenig.station.label = Gas-Station +thing-type.tankerkoenig.station.description = Provides the prices of gas types E5-, E10- and Diesel of that station and if that station reports as opened. +thing-type.tankerkoenig.webservice.label = Tankerkönig Webservice +thing-type.tankerkoenig.webservice.description = The Tankerkönig Webservice can handle 1 to 10 gas stations. + +# thing types config + +thing-type.config.tankerkoenig.station.locationid.label = Gas-Station-ID +thing-type.config.tankerkoenig.station.locationid.description = Fuel-Station-ID. You can get the required ID for your Gas-Station via the Tankerkönig website. +thing-type.config.tankerkoenig.webservice.apikey.label = API-Key +thing-type.config.tankerkoenig.webservice.apikey.description = API-Key. Necessary registration on the Tankerkönig website. +thing-type.config.tankerkoenig.webservice.modeOpeningTime.label = Opening Time +thing-type.config.tankerkoenig.webservice.modeOpeningTime.description = In mode Opening Time only those gas stations are polled that are actually open. +thing-type.config.tankerkoenig.webservice.refresh.label = Refresh Time +thing-type.config.tankerkoenig.webservice.refresh.description = Sets the refresh time. Minimum is 5 minutes. + +# channel types + +channel-type.tankerkoenig.diesel.label = Diesel +channel-type.tankerkoenig.diesel.description = price for diesel +channel-type.tankerkoenig.e10.label = E10 +channel-type.tankerkoenig.e10.description = price for E10 +channel-type.tankerkoenig.e5.label = E5 +channel-type.tankerkoenig.e5.description = price for E5 +channel-type.tankerkoenig.holiday.label = Holiday +channel-type.tankerkoenig.holiday.description = ON if today is a holiday. +channel-type.tankerkoenig.station_open.label = Opening State +channel-type.tankerkoenig.station_open.description = The reported opening-state of that Station. diff --git a/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties new file mode 100644 index 0000000000000..57d88f6eda97c --- /dev/null +++ b/bundles/org.openhab.binding.tapocontrol/src/main/resources/OH-INF/i18n/tapocontrol.properties @@ -0,0 +1,75 @@ +# binding + +binding.tapocontrol.name = TapoControl Binding +binding.tapocontrol.description = Control your TAPO-SmartHome Devices + +# thing types + +thing-type.tapocontrol.L510_Series.label = L510 Series White-Bulb +thing-type.tapocontrol.L510_Series.description = Tapo Smart dimmable White-Light-Bulb +thing-type.tapocontrol.L530_Series.label = L530 Series Color-Bulb +thing-type.tapocontrol.L530_Series.description = Tapo Smart Multicolor Light-Bulb +thing-type.tapocontrol.L900.label = L900 LightStrip +thing-type.tapocontrol.L900.description = Tapo Smart Multicolor Light-Lightstrip +thing-type.tapocontrol.P100.label = P100 SmartPlug +thing-type.tapocontrol.P100.description = Tapo Smart Wifi Plug +thing-type.tapocontrol.P105.label = P105 SmartPlug +thing-type.tapocontrol.P105.description = Tapo Mini Smart Wifi Plug +thing-type.tapocontrol.bridge.label = Cloud-Login +thing-type.tapocontrol.bridge.description = Cloud Connector. Acts as device-bridge + +# thing types config + +bridge-type.config.tapo.bridge.cloudDiscovery.label = Cloud Discovery +bridge-type.config.tapo.bridge.cloudDiscovery.description = Use Cloud Discovery-Service +bridge-type.config.tapo.bridge.discoveryInterval.label = Background Discovery Interval +bridge-type.config.tapo.bridge.discoveryInterval.description = Interval background discovery in minutes (default 60) +bridge-type.config.tapo.bridge.password.label = Password +bridge-type.config.tapo.bridge.password.description = Tapo-Cloud Login Password +bridge-type.config.tapo.bridge.username.label = Username +bridge-type.config.tapo.bridge.username.description = Tapo-Cloud Login User (e-Mail) +thing-type.config.tapo.device.ipAddress.label = IP Address +thing-type.config.tapo.device.pollingInterval.label = Refresh Interval +thing-type.config.tapo.device.pollingInterval.description = Refresh interval for refreshing the data in seconds. (0=disabled) + +# channel group types + +channel-group-type.tapocontrol.colorBulb.label = Color Light Bulb +channel-group-type.tapocontrol.colorBulb.description = Tapo Multicolor Smart Light Bulb +channel-group-type.tapocontrol.deviceState.label = Device State +channel-group-type.tapocontrol.deviceState.description = Information about the device +channel-group-type.tapocontrol.lightBulb.label = Light Bulb +channel-group-type.tapocontrol.lightBulb.description = Tapo Smart Light Bulb +channel-group-type.tapocontrol.lightEffect.label = Lightning Effect +channel-group-type.tapocontrol.lightEffect.description = Tapo Lightning Effects +channel-group-type.tapocontrol.lightStrip.label = Color Light Strip +channel-group-type.tapocontrol.lightStrip.description = Tapo Multicolor Smart Light Strip +channel-group-type.tapocontrol.smartPlug.label = SmartPlug +channel-group-type.tapocontrol.smartPlug.description = Tapo Smart Plug Power Outlet + +# channel types + +channel-type.tapocontrol.colorChannel.label = Color +channel-type.tapocontrol.colorChannel.description = Color +channel-type.tapocontrol.colorTemperature.label = Color Temperature +channel-type.tapocontrol.colorTemperature.description = This channel supports adjusting the color temperature from 2700K to 6500K. +channel-type.tapocontrol.customEffect.label = Custom Effect +channel-type.tapocontrol.customEffect.description = Use custom lightning effect +channel-type.tapocontrol.dimmerChannel.label = Brightness +channel-type.tapocontrol.dimmerChannel.description = Brightness +channel-type.tapocontrol.effectName.label = Effect Name +channel-type.tapocontrol.effectName.description = Name of LightningEffect +channel-type.tapocontrol.effectOn.label = Lightning Effect Enable +channel-type.tapocontrol.effectOn.description = Switches the lightning effect on/off +channel-type.tapocontrol.fade.label = Fade Light +channel-type.tapocontrol.fade.description = Make the light darker or lighter slowly +channel-type.tapocontrol.led.label = Switch Led +channel-type.tapocontrol.led.description = Switch the Smart Home device led on or off. +channel-type.tapocontrol.lightOn.label = Light On +channel-type.tapocontrol.lightOn.description = Switches the light on/off +channel-type.tapocontrol.ontime.label = On-Time +channel-type.tapocontrol.ontime.description = Number of seconds since the device was powered on +channel-type.tapocontrol.outputChannel.label = Output Switch +channel-type.tapocontrol.outputChannel.description = Switches the power state on/off +channel-type.tapocontrol.overheated.label = Device Overheated +channel-type.tapocontrol.overheated.description = ON if device is overheated diff --git a/bundles/org.openhab.binding.telegram/src/main/resources/OH-INF/i18n/telegram.properties b/bundles/org.openhab.binding.telegram/src/main/resources/OH-INF/i18n/telegram.properties new file mode 100644 index 0000000000000..f4146f2ba11b0 --- /dev/null +++ b/bundles/org.openhab.binding.telegram/src/main/resources/OH-INF/i18n/telegram.properties @@ -0,0 +1,56 @@ +# binding + +binding.telegram.name = Telegram Binding +binding.telegram.description = This is the binding for Telegram. It allows to send and receive messages. + +# thing types + +thing-type.telegram.telegramBot.label = Telegram Bot +thing-type.telegram.telegramBot.description = Thing to receive the latest message send to a Telegram Bot. + +# thing types config + +thing-type.config.telegram.telegramBot.botToken.label = Bot Token +thing-type.config.telegram.telegramBot.botToken.description = Enter the bot token you received from the "BotFather". +thing-type.config.telegram.telegramBot.chatIds.label = Chat Id(s) +thing-type.config.telegram.telegramBot.chatIds.description = One or more chat id(s). Access modifiers ("<" for inbound only, ">" for outbound only) can be used as prefix (optional). +thing-type.config.telegram.telegramBot.longPollingTime.label = Long Polling Time +thing-type.config.telegram.telegramBot.longPollingTime.description = Enter the long polling time in seconds. +thing-type.config.telegram.telegramBot.parseMode.label = Parse Mode +thing-type.config.telegram.telegramBot.parseMode.description = Support for formatted messages, values: Markdown or HTML. Default: no formatting is used. +thing-type.config.telegram.telegramBot.parseMode.option. = No Formatting +thing-type.config.telegram.telegramBot.parseMode.option.HTML = HTML +thing-type.config.telegram.telegramBot.parseMode.option.Markdown = Markdown +thing-type.config.telegram.telegramBot.proxyHost.label = Proxy Host +thing-type.config.telegram.telegramBot.proxyHost.description = Enter your proxy host. It will be used for telegram binding only and doesn't affect entire system. +thing-type.config.telegram.telegramBot.proxyPort.label = Proxy Port +thing-type.config.telegram.telegramBot.proxyPort.description = Enter your proxy port. +thing-type.config.telegram.telegramBot.proxyType.label = Proxy Type +thing-type.config.telegram.telegramBot.proxyType.description = Enter your proxy type. Default: SOCKS5 +thing-type.config.telegram.telegramBot.proxyType.option.SOCKS5 = SOCKS5 +thing-type.config.telegram.telegramBot.proxyType.option.HTTP = HTTP + +# channel types + +channel-type.telegram.callbackEvent.label = Query Callback Received +channel-type.telegram.callbackEvent.description = Callback Query response encoded as JSON.
Event payload could contain the following, but `null` values will not be present:
  • Long `message_id` - Unique message ID of the original Query message
  • String `from` - First and/or last name of sender
  • Long `chat_id` - Unique chat ID
  • String `callback_id` - Unique callback ID to send receipt confirmation to
  • String `reply_id` - Plain text name of original Query
  • String `text` - Selected response text from options give in original Query
+channel-type.telegram.callbackRawEvent.label = Raw Callback Query Received +channel-type.telegram.callbackRawEvent.description = Raw Callback Query response from the Telegram library encoded as JSON. +channel-type.telegram.chatId.label = Chat Id +channel-type.telegram.chatId.description = Contains the id of chat from where the message was received. +channel-type.telegram.lastMessageDate.label = Last Message Date +channel-type.telegram.lastMessageDate.description = Contains the latest message date as a DateTime +channel-type.telegram.lastMessageName.label = Last Message Name +channel-type.telegram.lastMessageName.description = Contains the latest message senders name as a string +channel-type.telegram.lastMessageText.label = Last Message Text +channel-type.telegram.lastMessageText.description = Contains the latest message text as a string +channel-type.telegram.lastMessageURL.label = Last Message URL +channel-type.telegram.lastMessageURL.description = Contains the URL of the latest message +channel-type.telegram.lastMessageUsername.label = Last Message Username +channel-type.telegram.lastMessageUsername.description = Contains the latest message senders username as a string +channel-type.telegram.messageEvent.label = Message Received +channel-type.telegram.messageEvent.description = Message encoded as JSON.
Event payload could contain the following, but `null` values will not be present:
  • Long `message_id` - Unique message ID in this chat
  • String `from` - First and/or last name of sender
  • Long `chat_id` - Unique chat ID
  • String `text` - Message text
  • String `animation_url` - URL to download animation from
  • String `audio_url` - URL to download audio from
  • String `document_url` - URL to download file from
  • Array `photo_url` - Array of URLs to download photos from
  • String `sticker_url` - URL to download sticker from
  • String `video_url` - URL to download video from
  • String `video_note_url` - URL to download video note from
  • String `voice_url` - URL to download voice clip from
+channel-type.telegram.messageRawEvent.label = Raw Message Received +channel-type.telegram.messageRawEvent.description = Raw Message from the Telegram library as JSON. +channel-type.telegram.replyId.label = Reply Id +channel-type.telegram.replyId.description = Contains the id of the reply which was passed to sendTelegram() as replyId. This id can be used to have an unambiguous assignment of the user reply to the message which was sent by the bot. diff --git a/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/teleinfo.properties b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/teleinfo.properties new file mode 100644 index 0000000000000..11cf16fdfe5e2 --- /dev/null +++ b/bundles/org.openhab.binding.teleinfo/src/main/resources/OH-INF/i18n/teleinfo.properties @@ -0,0 +1,151 @@ +# binding + +binding.teleinfo.name = Teleinfo Binding +binding.teleinfo.description = The Teleinfo binding decodes the electrical statistics from an ENEDIS/ERDF Electricity Meter + +# thing types + +thing-type.teleinfo.cbemm_base_electricitymeter.label = CBEMM BASE +thing-type.teleinfo.cbemm_base_electricitymeter.description = Single-phase Electricity meter with BASE option - CBEMM (aka "Compteur Bleu Electronique Monophasé Multitarif") +thing-type.teleinfo.cbemm_ejp_electricitymeter.label = CBEMM EJP +thing-type.teleinfo.cbemm_ejp_electricitymeter.description = Single-phase Electricity meter with EJP option - CBEMM (aka "Compteur Bleu Electronique Monophasé Multitarif") +thing-type.teleinfo.cbemm_evolution_icc_base_electricitymeter.label = CBEMM ICC BASE +thing-type.teleinfo.cbemm_evolution_icc_base_electricitymeter.description = Single-phase Electricity meter with BASE option - CBEMM Evolution ICC (aka "Compteur Bleu Electronique Monophasé Multitarif Evolution ICC") +thing-type.teleinfo.cbemm_evolution_icc_ejp_electricitymeter.label = CBEMM EJP +thing-type.teleinfo.cbemm_evolution_icc_ejp_electricitymeter.description = Single-phase Electricity meter with EJP option - CBEMM (aka "Compteur Bleu Electronique Monophasé Multitarif") +thing-type.teleinfo.cbemm_evolution_icc_hc_electricitymeter.label = CBEMM ICC HC/HP +thing-type.teleinfo.cbemm_evolution_icc_hc_electricitymeter.description = Single-phase Electricity meter with HC/HP option - CBEMM Evolution ICC (aka "Compteur Bleu Electronique Monophasé Multitarif Evolution ICC") +thing-type.teleinfo.cbemm_evolution_icc_tempo_electricitymeter.label = CBEMM ICC TEMPO +thing-type.teleinfo.cbemm_evolution_icc_tempo_electricitymeter.description = Single-phase Electricity meter with TEMPO option - CBEMM Evolution ICC (aka "Compteur Bleu Electronique Monophasé Multitarif Evolution ICC") +thing-type.teleinfo.cbemm_hc_electricitymeter.label = CBEMM HC/HP +thing-type.teleinfo.cbemm_hc_electricitymeter.description = Single-phase Electricity meter with HC/HP option - CBEMM (aka "Compteur Bleu Electronique Monophasé Multitarif") +thing-type.teleinfo.cbemm_tempo_electricitymeter.label = CBEMM TEMPO +thing-type.teleinfo.cbemm_tempo_electricitymeter.description = Single-phase Electricity meter with TEMPO option - CBEMM (aka "Compteur Bleu Electronique Monophasé Multitarif") +thing-type.teleinfo.cbetm_base_electricitymeter.label = CBETM BASE +thing-type.teleinfo.cbetm_base_electricitymeter.description = Three-phase Electricity meter with BASE option - CBETM (aka "Compteur Bleu Electronique Triphasé Multitarif") +thing-type.teleinfo.cbetm_ejp_electricitymeter.label = CBETM EJP +thing-type.teleinfo.cbetm_ejp_electricitymeter.description = Three-phase Electricity meter with EJP option - CBETM (aka "Compteur Bleu Electronique Triphasé Multitarif") +thing-type.teleinfo.cbetm_hc_electricitymeter.label = CBETM HC/HP +thing-type.teleinfo.cbetm_hc_electricitymeter.description = Three-phase Electricity meter with HC option - CBETM (aka "Compteur Bleu Electronique Triphasé Multitarif") +thing-type.teleinfo.cbetm_tempo_electricitymeter.label = CBETM TEMPO +thing-type.teleinfo.cbetm_tempo_electricitymeter.description = Three-phase Electricity meter with TEMPO option - CBETM (aka "Compteur Bleu Electronique Triphasé Multitarif") +thing-type.teleinfo.serialcontroller.label = Teleinfo Serial Controller +thing-type.teleinfo.serialcontroller.description = Teleinfo USB Stick with Serial Interface + +# thing types config + +thing-type.config.teleinfo.adco.adco.label = ADCO +thing-type.config.teleinfo.adco.adco.description = Electricity meter identifier (format: 12 characters / e.g: '031528042289') +thing-type.config.teleinfo.serialcontroller.autoRepairInvalidADPSgroupLine.label = Auto Repair Malformed ADPS Data +thing-type.config.teleinfo.serialcontroller.autoRepairInvalidADPSgroupLine.description = Try to auto repair malformed ADPS data from hardware issues (e.g: "ADPS032" instead of "ADPS 032" expected/well-formed data) +thing-type.config.teleinfo.serialcontroller.serialport.label = Serial Port +thing-type.config.teleinfo.serialcontroller.serialport.description = Serial port of Teleinfo device (e.g.: /dev/ttyUSB0 on Linux, COM1 on Windows) + +# channel types + +channel-type.teleinfo.adir1Type.label = ADIR1 +channel-type.teleinfo.adir1Type.description = Excess electric current on phase 1 warning +channel-type.teleinfo.adir2Type.label = ADIR2 +channel-type.teleinfo.adir2Type.description = Excess electric current on phase 2 warning +channel-type.teleinfo.adir3Type.label = ADIR3 +channel-type.teleinfo.adir3Type.description = Excess electric current on phase 3 warning +channel-type.teleinfo.adpsType.label = ADPS +channel-type.teleinfo.adpsType.description = Excess electric current warning +channel-type.teleinfo.baseType.label = BASE +channel-type.teleinfo.baseType.description = Total consumed energy +channel-type.teleinfo.bbrhcjbType.label = BBRHCJB +channel-type.teleinfo.bbrhcjbType.description = Total consumed energy at low rate pricing on blue days +channel-type.teleinfo.bbrhcjrType.label = BBRHCJR +channel-type.teleinfo.bbrhcjrType.description = Total consumed energy at low rate pricing on red days +channel-type.teleinfo.bbrhcjwType.label = BBRHCJW +channel-type.teleinfo.bbrhcjwType.description = Total consumed energy at low rate pricing on white days +channel-type.teleinfo.bbrhpjbType.label = BBRHPJB +channel-type.teleinfo.bbrhpjbType.description = Total consumed energy at high rate pricing on blue days +channel-type.teleinfo.bbrhpjrType.label = BBRHPJR +channel-type.teleinfo.bbrhpjrType.description = Total consumed energy at high rate pricing on red days +channel-type.teleinfo.bbrhpjwType.label = BBRHPJW +channel-type.teleinfo.bbrhpjwType.description = Total consumed energy at high rate pricing on white days +channel-type.teleinfo.couleurDemainType.label = DEMAIN +channel-type.teleinfo.couleurDemainType.description = Following day color +channel-type.teleinfo.couleurDemainType.state.option.Bleu = Bleu +channel-type.teleinfo.couleurDemainType.state.option.Blanc = Blanc +channel-type.teleinfo.couleurDemainType.state.option.Rouge = Rouge +channel-type.teleinfo.ejphnType.label = EJPHN +channel-type.teleinfo.ejphnType.description = Total consumed energy at low rate pricing +channel-type.teleinfo.ejphpmType.label = EJPHPM +channel-type.teleinfo.ejphpmType.description = Total consumed energy at high rate pricing +channel-type.teleinfo.frameTypeType.label = frameType +channel-type.teleinfo.frameTypeType.description = frameType +channel-type.teleinfo.frameTypeType.state.option.Long = Long +channel-type.teleinfo.frameTypeType.state.option.Short = Short +channel-type.teleinfo.hchcType.label = HCHC +channel-type.teleinfo.hchcType.description = Total consumed energy at low rate pricing +channel-type.teleinfo.hchpType.label = HCHP +channel-type.teleinfo.hchpType.description = Total consumed energy at high rate pricing +channel-type.teleinfo.hhphcType.label = HHPHC +channel-type.teleinfo.hhphcType.description = Pricing schedule group +channel-type.teleinfo.hhphcType.state.option.A = A +channel-type.teleinfo.hhphcType.state.option.C = C +channel-type.teleinfo.hhphcType.state.option.D = D +channel-type.teleinfo.hhphcType.state.option.E = E +channel-type.teleinfo.hhphcType.state.option.Y = Y +channel-type.teleinfo.iinst1Type.label = IINST1 +channel-type.teleinfo.iinst1Type.description = Instantaneous electric current on phase 1 +channel-type.teleinfo.iinst2Type.label = IINST2 +channel-type.teleinfo.iinst2Type.description = Instantaneous electric current on phase 2 +channel-type.teleinfo.iinst3Type.label = IINST3 +channel-type.teleinfo.iinst3Type.description = Instantaneous electric current on phase 3 +channel-type.teleinfo.iinstType.label = IINST +channel-type.teleinfo.iinstType.description = Instantaneous electric current +channel-type.teleinfo.imax1Type.label = IMAX1 +channel-type.teleinfo.imax1Type.description = Maximum consumed electric current on phase 1 +channel-type.teleinfo.imax2Type.label = IMAX2 +channel-type.teleinfo.imax2Type.description = Maximum consumed electric current on phase 2 +channel-type.teleinfo.imax3Type.label = IMAX3 +channel-type.teleinfo.imax3Type.description = Maximum consumed electric current on phase 3 +channel-type.teleinfo.imaxType.label = IMAX +channel-type.teleinfo.imaxType.description = Maximum consumed electric current +channel-type.teleinfo.invalidFrameCounterType.label = Frames Corrupted +channel-type.teleinfo.invalidFrameCounterType.description = Counter tracking the number of frames invalid/corrupted (checksum) +channel-type.teleinfo.isouscType.label = ISOUSC +channel-type.teleinfo.isouscType.description = Subscribed electric current +channel-type.teleinfo.lastUpdateType.label = Last Update +channel-type.teleinfo.lastUpdateType.description = Timestamp of last received Teleinfo frame +channel-type.teleinfo.pappType.label = PAPP +channel-type.teleinfo.pappType.description = Instantaneous apparent power +channel-type.teleinfo.pappType.label = PAPP +channel-type.teleinfo.pappType.description = Instantaneous apparent power +channel-type.teleinfo.pejpType.label = PEJP +channel-type.teleinfo.pejpType.description = Prior notice to EJP start +channel-type.teleinfo.pmaxType.label = PMAX +channel-type.teleinfo.pmaxType.description = Maximum consumed electric power on all phases +channel-type.teleinfo.ppotType.label = PPOT +channel-type.teleinfo.ppotType.description = Electrical potential presence +channel-type.teleinfo.programmeCircuit1Type.label = ProgrammeCircuit1 +channel-type.teleinfo.programmeCircuit1Type.description = Circuit 1 program +channel-type.teleinfo.programmeCircuit1Type.state.option.A = A +channel-type.teleinfo.programmeCircuit1Type.state.option.B = B +channel-type.teleinfo.programmeCircuit1Type.state.option.C = C +channel-type.teleinfo.programmeCircuit2Type.label = ProgrammeCircuit2 +channel-type.teleinfo.programmeCircuit2Type.description = Circuit 2 program +channel-type.teleinfo.programmeCircuit2Type.state.option.P0 = P0 +channel-type.teleinfo.programmeCircuit2Type.state.option.P1 = P1 +channel-type.teleinfo.programmeCircuit2Type.state.option.P2 = P2 +channel-type.teleinfo.programmeCircuit2Type.state.option.P3 = P3 +channel-type.teleinfo.programmeCircuit2Type.state.option.P4 = P4 +channel-type.teleinfo.programmeCircuit2Type.state.option.P5 = P5 +channel-type.teleinfo.programmeCircuit2Type.state.option.P6 = P6 +channel-type.teleinfo.programmeCircuit2Type.state.option.P7 = P7 +channel-type.teleinfo.ptecType.label = PTEC +channel-type.teleinfo.ptecType.description = Current pricing period +channel-type.teleinfo.ptecType.state.option.TH = TH +channel-type.teleinfo.ptecType.state.option.HC = HC +channel-type.teleinfo.ptecType.state.option.HP = HP +channel-type.teleinfo.ptecType.state.option.HN = HN +channel-type.teleinfo.ptecType.state.option.PM = PM +channel-type.teleinfo.ptecType.state.option.HCJB = HCJB +channel-type.teleinfo.ptecType.state.option.HCJW = HCJW +channel-type.teleinfo.ptecType.state.option.HCJR = HCJR +channel-type.teleinfo.ptecType.state.option.HPJB = HPJB +channel-type.teleinfo.ptecType.state.option.HPJW = HPJW +channel-type.teleinfo.ptecType.state.option.HPJR = HPJR diff --git a/bundles/org.openhab.binding.tellstick/src/main/resources/OH-INF/i18n/tellstick.properties b/bundles/org.openhab.binding.tellstick/src/main/resources/OH-INF/i18n/tellstick.properties new file mode 100644 index 0000000000000..05c082f81a0b9 --- /dev/null +++ b/bundles/org.openhab.binding.tellstick/src/main/resources/OH-INF/i18n/tellstick.properties @@ -0,0 +1,107 @@ +# binding + +binding.tellstick.name = Tellstick Binding +binding.tellstick.description = This is the binding for Telldus Tellstick Basic, Duo, .Net and Z-Net Lite. + +# thing types + +thing-type.tellstick.dimmer.label = Dimmable Device +thing-type.tellstick.dimmer.description = This is a Dimmable device +thing-type.tellstick.powersensor.label = PowerSensor +thing-type.tellstick.powersensor.description = This Thing defines a Power Sensor +thing-type.tellstick.rainsensor.label = RainSensor +thing-type.tellstick.rainsensor.description = This Thing defines a Rain Sensor +thing-type.tellstick.sensor.label = Sensor +thing-type.tellstick.sensor.description = This Thing defines a Sensor +thing-type.tellstick.switch.label = On/Off Device +thing-type.tellstick.switch.description = This Thing defines a Switch Device +thing-type.tellstick.telldus-core.label = Telldus Core Gateway +thing-type.tellstick.telldus-core.description = This bridge represents the Telldus center on a local computer. +thing-type.tellstick.telldus-live.label = Telldus Live Gateway +thing-type.tellstick.telldus-live.description = This bridge represents the Telldus live cloud service. +thing-type.tellstick.telldus-local.label = Telldus Local API +thing-type.tellstick.telldus-local.description = This bridge represents the Telldus local API. +thing-type.tellstick.windsensor.label = WindSensor +thing-type.tellstick.windsensor.description = This Thing defines a Wind Sensor + +# thing types config + +thing-type.config.tellstick.dimmer.deviceId.label = DeviceID +thing-type.config.tellstick.dimmer.deviceId.description = This is the unique id of a device. +thing-type.config.tellstick.dimmer.model.label = Model +thing-type.config.tellstick.dimmer.model.description = The model used by a specific device. +thing-type.config.tellstick.dimmer.name.label = Name +thing-type.config.tellstick.dimmer.name.description = The name of the device +thing-type.config.tellstick.dimmer.protocol.label = Protocol +thing-type.config.tellstick.dimmer.protocol.description = The protocol used by a specific device. +thing-type.config.tellstick.dimmer.repeat.label = Repeat +thing-type.config.tellstick.dimmer.repeat.description = The number of times to resend. +thing-type.config.tellstick.sensor-config.deviceId.label = DeviceID +thing-type.config.tellstick.sensor-config.deviceId.description = This function returns the unique id of a device with a specific index. +thing-type.config.tellstick.sensor-config.model.label = Model +thing-type.config.tellstick.sensor-config.model.description = The model used by a specific device. +thing-type.config.tellstick.sensor-config.name.label = Name +thing-type.config.tellstick.sensor-config.name.description = The name of the device (manually entered) +thing-type.config.tellstick.sensor-config.protocol.label = Protocol +thing-type.config.tellstick.sensor-config.protocol.description = The protocol used by a specific device. +thing-type.config.tellstick.switch.deviceId.label = DeviceID +thing-type.config.tellstick.switch.deviceId.description = This is the unique id of a device. +thing-type.config.tellstick.switch.dimmer.label = Dimmer +thing-type.config.tellstick.switch.dimmer.description = Is this a dimmer without absolute setting (e.g. you press on to start dim and then on again to stop it). +thing-type.config.tellstick.switch.name.label = Name +thing-type.config.tellstick.switch.name.description = The name of the device +thing-type.config.tellstick.switch.protocol.label = Protocol +thing-type.config.tellstick.switch.protocol.description = The protocol used by a specific device. +thing-type.config.tellstick.switch.repeat.label = Repeat +thing-type.config.tellstick.switch.repeat.description = The number of times to resend. +thing-type.config.tellstick.telldus-core.libraryPath.label = The Location of Telldus Core DLL/SO +thing-type.config.tellstick.telldus-core.libraryPath.description = The location of Telldus Core DLL/SO +thing-type.config.tellstick.telldus-core.resendInterval.label = ResendInterval +thing-type.config.tellstick.telldus-core.resendInterval.description = The interval between resend. +thing-type.config.tellstick.telldus-live.privateKey.label = Private Key +thing-type.config.tellstick.telldus-live.privateKey.description = The private key from telldus +thing-type.config.tellstick.telldus-live.publicKey.label = Public Key +thing-type.config.tellstick.telldus-live.publicKey.description = The public key from telldus +thing-type.config.tellstick.telldus-live.refreshInterval.label = Refresh Interval +thing-type.config.tellstick.telldus-live.refreshInterval.description = The refresh interval in ms which is used to poll Telldus Live. +thing-type.config.tellstick.telldus-live.token.label = Access Token +thing-type.config.tellstick.telldus-live.token.description = The openauth token. +thing-type.config.tellstick.telldus-live.tokenSecret.label = Token Secret +thing-type.config.tellstick.telldus-live.tokenSecret.description = The openauth token secret. +thing-type.config.tellstick.telldus-local.accessToken.label = Access Token +thing-type.config.tellstick.telldus-local.accessToken.description = The access token. +thing-type.config.tellstick.telldus-local.ipAddress.label = Local IP Address +thing-type.config.tellstick.telldus-local.ipAddress.description = The local IP address of the Tellstick. +thing-type.config.tellstick.telldus-local.refreshInterval.label = Refresh Interval +thing-type.config.tellstick.telldus-local.refreshInterval.description = The refresh interval in ms which is used to poll Telldus local API. + +# channel types + +channel-type.tellstick.ampere.label = Ampere +channel-type.tellstick.ampere.description = Current ampere +channel-type.tellstick.dimmer.label = Dimmer Value +channel-type.tellstick.dimmer.description = The channel to control the dimmer +channel-type.tellstick.humidity.label = Humidity +channel-type.tellstick.humidity.description = Actual measured room Humidity +channel-type.tellstick.lux.label = Lux +channel-type.tellstick.lux.description = Current lumination +channel-type.tellstick.rainrate.label = Rainrate +channel-type.tellstick.rainrate.description = The current rain rate +channel-type.tellstick.raintotal.label = Total Rain +channel-type.tellstick.raintotal.description = Total rain +channel-type.tellstick.state.label = Switch +channel-type.tellstick.state.description = Turns the power on or off +channel-type.tellstick.temperature.label = Temperature +channel-type.tellstick.temperature.description = Actual measured room temperature +channel-type.tellstick.timestamp.label = Last Device Update +channel-type.tellstick.timestamp.description = Last device update +channel-type.tellstick.timestamp.label = Last Device Update +channel-type.tellstick.timestamp.description = Last device update +channel-type.tellstick.watt.label = Power +channel-type.tellstick.watt.description = Current power +channel-type.tellstick.windaverage.label = Wind Average +channel-type.tellstick.windaverage.description = Current average wind +channel-type.tellstick.winddirection.label = Wind Direction +channel-type.tellstick.winddirection.description = Current wind direction +channel-type.tellstick.windgust.label = Wind Gust +channel-type.tellstick.windgust.description = Current wind gust diff --git a/bundles/org.openhab.binding.tesla/src/main/resources/OH-INF/i18n/tesla.properties b/bundles/org.openhab.binding.tesla/src/main/resources/OH-INF/i18n/tesla.properties new file mode 100644 index 0000000000000..8baf292ac5b3b --- /dev/null +++ b/bundles/org.openhab.binding.tesla/src/main/resources/OH-INF/i18n/tesla.properties @@ -0,0 +1,273 @@ +# binding + +binding.tesla.name = Tesla Binding +binding.tesla.description = This is the binding for Tesla Electric Vehicles. + +# thing types + +thing-type.tesla.account.label = Tesla Account +thing-type.tesla.account.description = Tesla Owner Account +thing-type.tesla.model3.label = Tesla Model 3 +thing-type.tesla.model3.description = A Tesla Model 3 Vehicle +thing-type.tesla.models.label = Tesla Model S +thing-type.tesla.models.description = A Tesla Model S Vehicle +thing-type.tesla.modelx.label = Tesla Model X +thing-type.tesla.modelx.description = A Tesla Model X Vehicle +thing-type.tesla.modely.label = Tesla Model Y +thing-type.tesla.modely.description = A Tesla Model Y Vehicle + +# thing types config + +thing-type.config.tesla.account.password.label = Password +thing-type.config.tesla.account.password.description = Password for the Tesla Remote Service +thing-type.config.tesla.account.refreshToken.label = Refresh Token +thing-type.config.tesla.account.refreshToken.description = Refresh token for account authentication. Use "smarthome:tesla" to retrieve it. +thing-type.config.tesla.account.username.label = Username +thing-type.config.tesla.account.username.description = Username for the Tesla Remote Service, e.g email address. +thing-type.config.tesla.model3.allowWakeup.label = Allow Wake-Up +thing-type.config.tesla.model3.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain! +thing-type.config.tesla.model3.valetpin.label = Valet PIN +thing-type.config.tesla.model3.valetpin.description = PIN to use when enabling Valet Mode +thing-type.config.tesla.model3.vin.label = Vehicle Identification Number +thing-type.config.tesla.model3.vin.description = VIN of the vehicle +thing-type.config.tesla.models.allowWakeup.label = Allow Wake-Up +thing-type.config.tesla.models.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain! +thing-type.config.tesla.models.valetpin.label = Valet PIN +thing-type.config.tesla.models.valetpin.description = PIN to use when enabling Valet Mode +thing-type.config.tesla.models.vin.label = Vehicle Identification Number +thing-type.config.tesla.models.vin.description = VIN of the vehicle +thing-type.config.tesla.modelx.allowWakeup.label = Allow Wake-Up +thing-type.config.tesla.modelx.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain! +thing-type.config.tesla.modelx.valetpin.label = Valet PIN +thing-type.config.tesla.modelx.valetpin.description = PIN to use when enabling Valet Mode +thing-type.config.tesla.modelx.vin.label = Vehicle Identification Number +thing-type.config.tesla.modelx.vin.description = VIN of the vehicle +thing-type.config.tesla.modely.allowWakeup.label = Allow Wake-Up +thing-type.config.tesla.modely.allowWakeup.description = Allows waking up the vehicle. Caution: This can result in huge vampire drain! +thing-type.config.tesla.modely.valetpin.label = Valet PIN +thing-type.config.tesla.modely.valetpin.description = PIN to use when enabling Valet Mode +thing-type.config.tesla.modely.vin.label = Vehicle Identification Number +thing-type.config.tesla.modely.vin.description = VIN of the vehicle + +# channel types + +channel-type.tesla.autoconditioning.label = Auto Conditioning +channel-type.tesla.autoconditioning.description = Turns on auto-conditioning (a/c or heating) +channel-type.tesla.autoparkstate.label = Autopark State +channel-type.tesla.autoparkstate.description = Undocumented / To be defined +channel-type.tesla.autoparkstyle.label = Autopark Style +channel-type.tesla.autoparkstyle.description = Undocumented / To be defined +channel-type.tesla.batterycurrent.label = Battery Current +channel-type.tesla.batterycurrent.description = Current (Ampere) floating into (+) or out (-) of the battery +channel-type.tesla.batteryheater.label = Battery Heater +channel-type.tesla.batteryheater.description = Indicates if the battery heater is switched on +channel-type.tesla.batteryheaternopower.label = Battery Heater Power +channel-type.tesla.batteryheaternopower.description = Indicates if there is enough power to use the battery heater +channel-type.tesla.batterylevel.label = Battery Level +channel-type.tesla.batterylevel.description = State of the battery in % +channel-type.tesla.batteryrange.label = Battery Range +channel-type.tesla.batteryrange.description = Range of the battery +channel-type.tesla.calendarenabled.label = Calendar Enabled +channel-type.tesla.calendarenabled.description = Indicates if access to a remote calendar is enabled +channel-type.tesla.centerdisplay.label = Central Display State +channel-type.tesla.centerdisplay.description = Indicates the state of the central display in the vehicle +channel-type.tesla.centerrearseatheater.label = Center Rear Seat Heater +channel-type.tesla.centerrearseatheater.description = Indicates if the center rear seat heater is switched on +channel-type.tesla.charge.label = Charge +channel-type.tesla.charge.description = Start (ON) or stop (OFF) charging +channel-type.tesla.chargecable.label = Charge Cable +channel-type.tesla.chargecable.description = Undocumented / To be defined +channel-type.tesla.chargecurrent.label = Charge Current +channel-type.tesla.chargecurrent.description = Current (Ampere) requested from the charger +channel-type.tesla.chargeenablerequest.label = Charge Enable Request +channel-type.tesla.chargeenablerequest.description = Undocumented / To be defined +channel-type.tesla.chargeenergyadded.label = Charge Energy Added +channel-type.tesla.chargeenergyadded.description = Energy added, in kWh, during the last charging session +channel-type.tesla.chargeidealdistanceadded.label = "Ideal" Charge Distance Added +channel-type.tesla.chargeidealdistanceadded.description = "Ideal" range added during the last charging session +channel-type.tesla.chargelimit.label = Charge Limit +channel-type.tesla.chargelimit.description = Limit charging of the vehicle to the given % +channel-type.tesla.chargelimitmaximum.label = Charge Limit Maximum +channel-type.tesla.chargelimitmaximum.description = Maximum charging limit of the vehicle, as % +channel-type.tesla.chargelimitminimum.label = Charge Limit Minimum +channel-type.tesla.chargelimitminimum.description = Minimum charging limit of the vehicle, as % +channel-type.tesla.chargelimitsocstandard.label = Charge Limit SOC Standard +channel-type.tesla.chargelimitsocstandard.description = Standard charging limity of the vehicle, in % +channel-type.tesla.chargemaxcurrent.label = Charge Max Current +channel-type.tesla.chargemaxcurrent.description = Maximum current (Ampere) that can be requested from the charger +channel-type.tesla.chargeport.label = Charge Port +channel-type.tesla.chargeport.description = Open the Charge Port (ON) or indicates the state of the Charge Port (ON/OFF if Open/Closed) +channel-type.tesla.chargerate.label = Charge Rate +channel-type.tesla.chargerate.description = Distance per hour charging rate +channel-type.tesla.chargerateddistanceadded.label = "Rated" Charge Distance Added +channel-type.tesla.chargerateddistanceadded.description = "Rated" range added during the last charging session +channel-type.tesla.chargercurrent.label = Charge Current +channel-type.tesla.chargercurrent.description = Current (Ampere) actually being drawn from the charger +channel-type.tesla.chargermaxcurrent.label = Charger Maximum Current +channel-type.tesla.chargermaxcurrent.description = Maximum current (Ampere) that can be delivered by the charger +channel-type.tesla.chargerphases.label = Charger Phases +channel-type.tesla.chargerphases.description = Indicates the number of phases (1 to 3) used for charging +channel-type.tesla.chargerpower.label = Charger Power +channel-type.tesla.chargerpower.description = Power actually delivered by the charger +channel-type.tesla.chargervoltage.label = Charger Voltage +channel-type.tesla.chargervoltage.description = Voltage (V) actually presented by the charger +channel-type.tesla.chargestartingrange.label = Charge Starting Range +channel-type.tesla.chargestartingrange.description = Undocumented / To be defined +channel-type.tesla.chargestartingsoc.label = Charge Starting SOC +channel-type.tesla.chargestartingsoc.description = Undocumented / To be defined +channel-type.tesla.chargetomax.label = Charge To Max Range +channel-type.tesla.chargetomax.description = Indicates if the charging to the maximum range is enabled +channel-type.tesla.chargingstate.label = Charging State +channel-type.tesla.chargingstate.description = “Starting”, “Complete”, “Charging”, “Disconnected”, “Stopped”, “NoPower” +channel-type.tesla.chargingstate.state.option.Starting = Starting +channel-type.tesla.chargingstate.state.option.Complete = Complete +channel-type.tesla.chargingstate.state.option.Charging = Charging +channel-type.tesla.chargingstate.state.option.Disconnected = Disconnected +channel-type.tesla.chargingstate.state.option.Stopped = Stopped +channel-type.tesla.chargingstate.state.option.NoPower = No Power +channel-type.tesla.climate.label = Climate +channel-type.tesla.climate.description = Climate status indicator +channel-type.tesla.combinedtemp.label = Combined Temperature +channel-type.tesla.combinedtemp.description = Combined average temperature of the driver and passenger autoconditioning settings. The temperature for the driver and passenger will be synced when set. +channel-type.tesla.doorlock.label = Door Lock +channel-type.tesla.doorlock.description = Lock or unlock the car +channel-type.tesla.driverfrontdoor.label = Driver Front Door +channel-type.tesla.driverfrontdoor.description = Indicates if the front door at the driver's side is opened +channel-type.tesla.driverreardoor.label = Driver Rear Door +channel-type.tesla.driverreardoor.description = Indicates if the rear door at the driver's side is opened +channel-type.tesla.drivertemp.label = Driver Temperature +channel-type.tesla.drivertemp.description = Indicates the auto conditioning temperature set at the driver's side +channel-type.tesla.estimatedbatteryrange.label = Estimated Battery Range +channel-type.tesla.estimatedbatteryrange.description = Estimated battery range +channel-type.tesla.estimatedrange.label = Estimated Range +channel-type.tesla.estimatedrange.description = Estimated range of the vehicle +channel-type.tesla.eventstamp.label = Event Timestamp +channel-type.tesla.eventstamp.description = Timestamp of the last event received from the Tesla streaming service +channel-type.tesla.fan.label = Fan +channel-type.tesla.fan.description = Indicates the speed (0-7) of the fan +channel-type.tesla.flashlights.label = Flash Lights +channel-type.tesla.flashlights.description = Flash the lights of the car (when ON is received) +channel-type.tesla.frontdefroster.label = Front Defroster +channel-type.tesla.frontdefroster.description = Indicates if the front defroster is enabled +channel-type.tesla.fronttrunk.label = Front Trunk +channel-type.tesla.fronttrunk.description = Indicates if the front trunk is opened, or open the front trunk when ON is received +channel-type.tesla.gpstimestamp.label = GPS Time Stamp +channel-type.tesla.gpstimestamp.description = Time stamp of the most recent GPS location of the vehicle +channel-type.tesla.heading.label = Heading +channel-type.tesla.heading.description = Indicates the (compass) heading of the car, in 0-360 degrees +channel-type.tesla.headingestimation.label = Estimated Heading +channel-type.tesla.headingestimation.description = Estimated (compass) heading of the car, in 0 to 360 degrees +channel-type.tesla.homelink.label = Homelink Nearby +channel-type.tesla.homelink.description = Indicates if the Home Link is nearby +channel-type.tesla.honkhorn.label = Honk the Horn +channel-type.tesla.honkhorn.description = Honk the horn of the vehicle, when ON is received +channel-type.tesla.idealbatteryrange.label = Ideal Battery Range +channel-type.tesla.idealbatteryrange.description = Indicates the Batter Range +channel-type.tesla.insidetemp.label = Inside Temperature +channel-type.tesla.insidetemp.description = Indicates the inside temperature of the vehicle +channel-type.tesla.lastautoparkerror.label = Last Autopark Error +channel-type.tesla.lastautoparkerror.description = Not documented / To be defined +channel-type.tesla.leftrearbackseatheater.label = Left Rear Backseat Heater +channel-type.tesla.leftrearbackseatheater.description = Indicates the level (0,1,2 or 3) of the left rear backseat heater +channel-type.tesla.leftrearseatheater.label = Left Rear Seat Heater +channel-type.tesla.leftrearseatheater.description = Indicates if the left rear seat heater is switched on +channel-type.tesla.leftseatheater.label = Left Seat Heater +channel-type.tesla.leftseatheater.description = Indicates if the left seat heater is switched on +channel-type.tesla.lefttempdirection.label = Left Temperature Direction +channel-type.tesla.lefttempdirection.description = Not documented / To be defined +channel-type.tesla.location.label = Location +channel-type.tesla.location.description = The actual position of the vehicle +channel-type.tesla.managedcharging.label = Managed Charging +channel-type.tesla.managedcharging.description = Indicates managed charging is active +channel-type.tesla.managedchargingcancelled.label = Managed Charging Cancelled +channel-type.tesla.managedchargingcancelled.description = Indicates managed charging is cancelled by the user +channel-type.tesla.managedchargingstart.label = Managed Charging Start Time +channel-type.tesla.managedchargingstart.description = Not documented / To be defined +channel-type.tesla.maxavailabletemp.label = Maximum Temperature +channel-type.tesla.maxavailabletemp.description = Indicates the maximum inside temperature of the vehicle +channel-type.tesla.maxcharges.label = Max Charges +channel-type.tesla.maxcharges.description = Indicates the number of consecutive "Max Range Charges" performed by the vehicle +channel-type.tesla.minavailabletemp.label = Minimum Temperature +channel-type.tesla.minavailabletemp.description = Indicates the minimal inside temperature of the vehicle +channel-type.tesla.mobileenabled.label = Mobile Enabled +channel-type.tesla.mobileenabled.description = Indicates whether the vehicle can be remotely controlled +channel-type.tesla.notenoughpower.label = Not Enought Power +channel-type.tesla.notenoughpower.description = Indicates if not enough power (ON) is available to heat the vehicle +channel-type.tesla.notificationsenabled.label = Notifications Enabled +channel-type.tesla.notificationsenabled.description = Not documented / To be defined +channel-type.tesla.notificationssupported.label = Notifications Supported +channel-type.tesla.notificationssupported.description = Not documented / To be defined +channel-type.tesla.odometer.label = Odometer +channel-type.tesla.odometer.description = Odometer of the vehicle +channel-type.tesla.outsidetemp.label = Outside Temperature +channel-type.tesla.outsidetemp.description = Indicates the outside temperature of the vehicle +channel-type.tesla.parsedcalendar.label = Parsed Calendar Supported +channel-type.tesla.parsedcalendar.description = Not documented / To be defined +channel-type.tesla.passengerfrontdoor.label = Passenger Front Door +channel-type.tesla.passengerfrontdoor.description = Indicates if the front door at the passenger's side is opened +channel-type.tesla.passengerreardoor.label = Passenger Rear Door +channel-type.tesla.passengerreardoor.description = Indicates if the rear door at the passenger's side is opened +channel-type.tesla.passengertemp.label = Passenger Temperature +channel-type.tesla.passengertemp.description = Indicates the auto conditioning temperature set at the passenger's side +channel-type.tesla.power.label = Power +channel-type.tesla.power.description = Net kW flowing in (+) or out (-) of the battery +channel-type.tesla.preconditioning.label = Preconditioning +channel-type.tesla.preconditioning.description = Indicates if preconditioning is activated +channel-type.tesla.range.label = Range +channel-type.tesla.range.description = Vehicle range - Not documented / To be defined +channel-type.tesla.reardefroster.label = Rear Defroster +channel-type.tesla.reardefroster.description = Indicates if the rear defroster is enabled +channel-type.tesla.reartrunk.label = Rear Trunk +channel-type.tesla.reartrunk.description = Indicates if the rear trunk is opened, or open/close the rear trunk when ON/OFF is received +channel-type.tesla.remotestart.label = Remote Start +channel-type.tesla.remotestart.description = Not documented / To be defined +channel-type.tesla.remotestartenabled.label = Remote Start +channel-type.tesla.remotestartenabled.description = Not documented / To be defined +channel-type.tesla.remotestartsupported.label = Remote Start Supported +channel-type.tesla.remotestartsupported.description = Not documented / To be defined +channel-type.tesla.rightrearbackseatheater.label = Right Rear Backseat Heater +channel-type.tesla.rightrearbackseatheater.description = Indicates the level (0,1,2 or 3) of the right rear backseat heater +channel-type.tesla.rightrearseatheater.label = Right Rear Seat Heater +channel-type.tesla.rightrearseatheater.description = Indicates if the right rear seat heater is switched on +channel-type.tesla.rightseatheater.label = Right Seat Heater +channel-type.tesla.rightseatheater.description = Indicates if the right seat heater is switched on +channel-type.tesla.righttempdirection.label = Right Temperature Direction +channel-type.tesla.righttempdirection.description = Not documented / To be defined +channel-type.tesla.scheduledchargingpending.label = Scheduled Charging Pending +channel-type.tesla.scheduledchargingpending.description = Indicates if a scheduled charging session is still pending +channel-type.tesla.scheduledchargingstart.label = Scheduled Charging Start +channel-type.tesla.scheduledchargingstart.description = Indicates when the scheduled charging session will start, in yyyy-MM-dd'T'HH:mm:ss format +channel-type.tesla.shiftstate.label = Shift State +channel-type.tesla.shiftstate.description = Indicates the state of the transmission, “P”, “D”, “R”, or “N” +channel-type.tesla.sidemirrorheaters.label = Side Mirror Heaters +channel-type.tesla.sidemirrorheaters.description = Indicates if the side mirror heaters are switched on +channel-type.tesla.smartpreconditioning.label = Smart Preconditioning +channel-type.tesla.smartpreconditioning.description = Indicates if smart preconditioning is switched on +channel-type.tesla.soc.label = State of Charge +channel-type.tesla.soc.description = State of Charge, in % +channel-type.tesla.speed.label = Speed +channel-type.tesla.speed.description = Vehicle speed +channel-type.tesla.state.label = State +channel-type.tesla.state.description = “online”, “asleep”, “waking” +channel-type.tesla.steeringwheelheater.label = Steering Wheel Heater +channel-type.tesla.steeringwheelheater.description = Indicates if the steering wheel heater is switched on +channel-type.tesla.sunroof.label = Sunroof +channel-type.tesla.sunroof.description = Open or close the sunroof to provided % (0 closed, 100 fully open) +channel-type.tesla.sunroofstate.label = Sunroof State +channel-type.tesla.sunroofstate.description = “unknown”, “open”, “closed”, “vent”, “comfort” +channel-type.tesla.timetofullcharge.label = Time To Full Charge +channel-type.tesla.timetofullcharge.description = Number of hours to fully charge the battery +channel-type.tesla.tripcharging.label = Trip Charging +channel-type.tesla.tripcharging.description = Not documented / To be defined +channel-type.tesla.usablebatterylevel.label = Usable Battery Level +channel-type.tesla.usablebatterylevel.description = Indicates the % of battery that can be used for vehicle functions like driving +channel-type.tesla.userchargeenablerequest.label = User Charge Enable Request +channel-type.tesla.userchargeenablerequest.description = Not documented / To be defined +channel-type.tesla.valetmode.label = Valet Mode +channel-type.tesla.valetmode.description = Enable or disable Valet Mode +channel-type.tesla.valetpin.label = Valet PIN Required +channel-type.tesla.valetpin.description = Indicates if a PIN code is required to disable valet mode +channel-type.tesla.wakeup.label = Wake Up +channel-type.tesla.wakeup.description = Wake up the vehicle from a (deep) sleep +channel-type.tesla.wiperbladeheater.label = Wiperblade Heater +channel-type.tesla.wiperbladeheater.description = Indicates if the wiperblade heater is switched on diff --git a/bundles/org.openhab.binding.tibber/src/main/resources/OH-INF/i18n/tibber.properties b/bundles/org.openhab.binding.tibber/src/main/resources/OH-INF/i18n/tibber.properties new file mode 100644 index 0000000000000..3699fbd5332cc --- /dev/null +++ b/bundles/org.openhab.binding.tibber/src/main/resources/OH-INF/i18n/tibber.properties @@ -0,0 +1,41 @@ +# binding + +binding.tibber.name = Tibber Binding +binding.tibber.description = This binding retrieves price and consumption data from Tibber API using queries and live subscription + +# thing types + +thing-type.tibber.tibberapi.label = Tibber API +thing-type.tibber.tibberapi.description = Tibber API connector + +# thing types config + +thing-type.config.tibber.tibberapi.homeid.label = HomeID +thing-type.config.tibber.tibberapi.homeid.description = Tibber Home ID +thing-type.config.tibber.tibberapi.refresh.label = Refresh Interval +thing-type.config.tibber.tibberapi.refresh.description = Manually Set Polling Frequency (minutes) +thing-type.config.tibber.tibberapi.token.label = Token +thing-type.config.tibber.tibberapi.token.description = Tibber Personal Token + +# channel types + +channel-type.tibber.consumption.label = Total Consumption +channel-type.tibber.consumption.description = Consumption at given time interval (e.g. hourly, daily, last meter reading, accumulated since midnight) +channel-type.tibber.cost.label = Total Cost +channel-type.tibber.cost.description = Cost at given time interval (e.g. hourly, daily, accumulated since midnight) +channel-type.tibber.currency.label = Currency +channel-type.tibber.currency.description = Currency of Displayed Cost +channel-type.tibber.current.label = Current +channel-type.tibber.current.description = Current on given Phase +channel-type.tibber.level.label = Price Level +channel-type.tibber.level.description = Current price level +channel-type.tibber.power.label = Power consumption/production +channel-type.tibber.power.description = Power consumption/production for given time interval +channel-type.tibber.price.label = Current Total Price +channel-type.tibber.price.description = Total Price: Energy + Tax +channel-type.tibber.production.label = Total Production +channel-type.tibber.production.description = Accumulated Production since Midnight +channel-type.tibber.timestamp.label = Timestamp +channel-type.tibber.timestamp.description = Timestamp for measurement/change +channel-type.tibber.voltage.label = Voltage +channel-type.tibber.voltage.description = Voltage on given Phase diff --git a/bundles/org.openhab.binding.tivo/src/main/resources/OH-INF/i18n/tivo.properties b/bundles/org.openhab.binding.tivo/src/main/resources/OH-INF/i18n/tivo.properties new file mode 100644 index 0000000000000..f696c68be6016 --- /dev/null +++ b/bundles/org.openhab.binding.tivo/src/main/resources/OH-INF/i18n/tivo.properties @@ -0,0 +1,102 @@ +# binding + +binding.tivo.name = TiVo DVR Binding +binding.tivo.description = Controls TiVo DVRs that support the TiVo TCP Control Protocol v1.1 + +# thing types + +thing-type.tivo.sckt.label = TiVo DVR +thing-type.tivo.sckt.description = Monitor and control your TiVo via DIRECT SOCKET commands leveraging the TIVO protocol 1.1 specification. The TiVo TCP Control Protocol is an ASCII-based command protocol for remote control of a TiVo DVR over a TCP local network connection. The commands allow control of channel changes, user interface navigation and allow the client to send simulated remote control button presses to the Digital Video Recorder. + +# thing types config + +thing-type.config.tivo.sckt.cmdWaitInterval.label = Command Wait Interval (Milliseconds) +thing-type.config.tivo.sckt.cmdWaitInterval.description = Period to wait AFTER a command is sent to the TiVo in milliseconds, before checking that the command has completed. Default: 200 +thing-type.config.tivo.sckt.host.label = Address +thing-type.config.tivo.sckt.host.description = The IP address or host name of your TiVo DVR +thing-type.config.tivo.sckt.keepConActive.label = Keep Connection Open +thing-type.config.tivo.sckt.keepConActive.description = Keep connection to the TiVo open. Recommended for monitoring the TiVo for changes in TV channels. Disable if other applications that use the Remote Control Protocol port will also be used e.g. mobile remote control applications. Default: True (Enabled) +thing-type.config.tivo.sckt.numRetry.label = Connection Retries +thing-type.config.tivo.sckt.numRetry.description = The number of times to attempt reconnection to the TiVo box, if there is a connection failure. Default: 5 +thing-type.config.tivo.sckt.pollForChanges.label = Poll for Channel Changes +thing-type.config.tivo.sckt.pollForChanges.description = Check TiVo for channel changes. Enable if openHAB and a physical remote control (or other services use the Remote Control Protocol) will be used. Default: True (Enabled) +thing-type.config.tivo.sckt.pollInterval.label = Polling Interval (Seconds) +thing-type.config.tivo.sckt.pollInterval.description = Number of seconds between polling jobs to update status information from the TiVo. Default: 10 +thing-type.config.tivo.sckt.tcpPort.label = TCP Port +thing-type.config.tivo.sckt.tcpPort.description = The TCP port number used to connect to the TiVo. Default: 31339 + +# channel types + +channel-type.tivo.channelForce.label = Current Channel - Forced +channel-type.tivo.channelForce.description = Displays the current channel number. When changed (FORCECH), tunes the DVR to the specified channel, cancelling any recordings in progress if necessary i.e. all tuners are already in use / recording. The TiVo must be in Live TV mode for this command to work. Type: Number (1-9999) [Decimals allowed for OTA sub-channels], DisplayFormat: %d +channel-type.tivo.channelSet.label = Current Channel - Request +channel-type.tivo.channelSet.description = Displays the current channel number. When changed (SETCH), tunes the DVR to the specified channel (unless a recording is in progress on all available tuners). The TiVo must be in Live TV mode for this command to work. Type: Number (1-9999) [Decimals allowed for OTA sub-channels], DisplayFormat: %d +channel-type.tivo.dvrStatus.label = TiVo Status +channel-type.tivo.dvrStatus.description = Action return code / channel information returned by the TiVo. Type: String {ReadOnly) +channel-type.tivo.irCommand.label = Remote Control Button +channel-type.tivo.irCommand.description = Send a simulated button push (IRCODE) from the remote control to the TiVo. See README.md for supported codes. Type: String +channel-type.tivo.irCommand.state.option.UP = UP +channel-type.tivo.irCommand.state.option.DOWN = DOWN +channel-type.tivo.irCommand.state.option.LEFT = LEFT +channel-type.tivo.irCommand.state.option.RIGHT = RIGHT +channel-type.tivo.irCommand.state.option.SELECT = SELECT +channel-type.tivo.irCommand.state.option.TIVO = TIVO +channel-type.tivo.irCommand.state.option.LIVETV = LIVETV +channel-type.tivo.irCommand.state.option.GUIDE = GUIDE +channel-type.tivo.irCommand.state.option.INFO = INFO +channel-type.tivo.irCommand.state.option.EXIT = EXIT +channel-type.tivo.irCommand.state.option.THUMBSUP = THUMBSUP +channel-type.tivo.irCommand.state.option.THUMBSDOWN = THUMBSDOWN +channel-type.tivo.irCommand.state.option.CHANNELUP = CHANNELUP +channel-type.tivo.irCommand.state.option.CHANNELDOWN = CHANNELDOWN +channel-type.tivo.irCommand.state.option.PLAY = PLAY +channel-type.tivo.irCommand.state.option.FORWARD = FORWARD +channel-type.tivo.irCommand.state.option.REVERSE = REVERSE +channel-type.tivo.irCommand.state.option.PAUSE = PAUSE +channel-type.tivo.irCommand.state.option.SLOW = SLOW +channel-type.tivo.irCommand.state.option.REPLAY = REPLAY +channel-type.tivo.irCommand.state.option.ADVANCE = ADVANCE +channel-type.tivo.irCommand.state.option.RECORD = RECORD +channel-type.tivo.irCommand.state.option.NUM0 = NUM0 +channel-type.tivo.irCommand.state.option.NUM1 = NUM1 +channel-type.tivo.irCommand.state.option.NUM2 = NUM2 +channel-type.tivo.irCommand.state.option.NUM3 = NUM3 +channel-type.tivo.irCommand.state.option.NUM4 = NUM4 +channel-type.tivo.irCommand.state.option.NUM5 = NUM5 +channel-type.tivo.irCommand.state.option.NUM6 = NUM6 +channel-type.tivo.irCommand.state.option.NUM7 = NUM7 +channel-type.tivo.irCommand.state.option.NUM8 = NUM8 +channel-type.tivo.irCommand.state.option.NUM9 = NUM9 +channel-type.tivo.irCommand.state.option.ENTER = ENTER +channel-type.tivo.irCommand.state.option.CLEAR = CLEAR +channel-type.tivo.irCommand.state.option.ACTION_A = ACTION_A +channel-type.tivo.irCommand.state.option.ACTION_B = ACTION_B +channel-type.tivo.irCommand.state.option.ACTION_C = ACTION_C +channel-type.tivo.irCommand.state.option.ACTION_D = ACTION_D +channel-type.tivo.irCommand.state.option.CC_ON = CC_ON +channel-type.tivo.irCommand.state.option.CC_OFF = CC_OFF +channel-type.tivo.irCommand.state.option.FIND_REMOTE = FIND_REMOTE +channel-type.tivo.irCommand.state.option.ASPECT_CORRECTION_FULL = ASPECT_CORRECTION_FULL +channel-type.tivo.irCommand.state.option.ASPECT_CORRECTION_PANEL = ASPECT_CORRECTION_PANEL +channel-type.tivo.irCommand.state.option.ASPECT_CORRECTION_ZOOM = ASPECT_CORRECTION_ZOOM +channel-type.tivo.irCommand.state.option.ASPECT_CORRECTION_WIDE_ZOOM = ASPECT_CORRECTION_WIDE_ZOOM +channel-type.tivo.irCommand.state.option.VIDEO_MODE_FIXED_480i = VIDEO_MODE_FIXED_480i +channel-type.tivo.irCommand.state.option.VIDEO_MODE_FIXED_480p = VIDEO_MODE_FIXED_480p +channel-type.tivo.irCommand.state.option.VIDEO_MODE_FIXED_720p = VIDEO_MODE_FIXED_720p +channel-type.tivo.irCommand.state.option.VIDEO_MODE_FIXED_1080i = VIDEO_MODE_FIXED_1080i +channel-type.tivo.irCommand.state.option.VIDEO_MODE_HYBRID = VIDEO_MODE_HYBRID +channel-type.tivo.irCommand.state.option.VIDEO_MODE_HYBRID_720p = VIDEO_MODE_HYBRID_720p +channel-type.tivo.irCommand.state.option.VIDEO_MODE_HYBRID_1080i = VIDEO_MODE_HYBRID_1080i +channel-type.tivo.irCommand.state.option.VIDEO_MODE_NATIVE = VIDEO_MODE_NATIVE +channel-type.tivo.isRecording.label = Recording +channel-type.tivo.isRecording.description = Indicates if the current channel is recording. +channel-type.tivo.kbdCommand.label = Keyboard Command +channel-type.tivo.kbdCommand.description = Sends a code (KEYBOARD) corresponding to a keyboard key press to the TiVo e.g. A-Z. See Appendix A in document TCP Remote Protocol 1.1 for supported characters and special character codes. Type: String +channel-type.tivo.menuTeleport.label = Change Menu Screen +channel-type.tivo.menuTeleport.description = Change(TELEPORT) to one of the following TiVo menu screens: TIVO (Home), LIVE TV, GUIDE, NOW PLAYING (My Shows), SEARCH, NETFLIX. Type: String +channel-type.tivo.menuTeleport.state.option.TIVO = TIVO +channel-type.tivo.menuTeleport.state.option.LIVETV = LIVETV +channel-type.tivo.menuTeleport.state.option.GUIDE = GUIDE +channel-type.tivo.menuTeleport.state.option.NOWPLAYING = NOWPLAYING +channel-type.tivo.menuTeleport.state.option.SEARCH = SEARCH +channel-type.tivo.menuTeleport.state.option.NETFLIX = NETFLIX diff --git a/bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/i18n/touchwand.properties b/bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/i18n/touchwand.properties new file mode 100644 index 0000000000000..0425dfafe91e0 --- /dev/null +++ b/bundles/org.openhab.binding.touchwand/src/main/resources/OH-INF/i18n/touchwand.properties @@ -0,0 +1,68 @@ +# binding + +binding.touchwand.name = TouchWand Binding +binding.touchwand.description = Connect to TouchWand Wanderfull™ Hub and communicate with units connected to the controller. + +# thing types + +thing-type.touchwand.alarmsensor.label = TouchWand Alarm Sensor Unit +thing-type.touchwand.bridge.label = TouchWand Wanderfull Hub Bridge +thing-type.touchwand.bridge.description = Multifunctional Gateway - a bridge to units and scenarios +thing-type.touchwand.bsensor.label = TouchWand Binary Sensor Unit +thing-type.touchwand.dimmer.label = TouchWand Dimmer Unit +thing-type.touchwand.dimmer.channel.brightness.description = light brightness control +thing-type.touchwand.shutter.label = TouchWand Shutter Unit +thing-type.touchwand.shutter.channel.shutter.description = Shutter control +thing-type.touchwand.switch.label = TouchWand Switch Unit +thing-type.touchwand.switch.channel.switch.description = Unit on off switch +thing-type.touchwand.thermostat.label = TouchWand Thermostat Unit +thing-type.touchwand.wallcontroller.label = TouchWand WallController Unit +thing-type.touchwand.wallcontroller.channel.wallaction.description = WallController action + +# thing types config + +thing-type.config.touchwand.bridge.addSecondaryUnits.label = Add Secondary Controllers +thing-type.config.touchwand.bridge.addSecondaryUnits.description = If the controller is primary, add secondary controllers units as well +thing-type.config.touchwand.bridge.ipAddress.label = Network Address +thing-type.config.touchwand.bridge.ipAddress.description = Network address of this TouchWand Wanderfull Hub +thing-type.config.touchwand.bridge.password.label = Password +thing-type.config.touchwand.bridge.password.description = Password for TouchWand Wanderfull Hub +thing-type.config.touchwand.bridge.port.label = Port +thing-type.config.touchwand.bridge.port.description = Port of the TouchWand Wanderfull Hub communication channel +thing-type.config.touchwand.bridge.username.label = Username +thing-type.config.touchwand.bridge.username.description = Username for TouchWand Wanderfull Hub + +# channel types + +channel-type.touchwand.fanLevel.label = Fan Level +channel-type.touchwand.fanLevel.description = Fan level (Low, Medium, High, Auto) +channel-type.touchwand.fanLevel.state.option.low = Low +channel-type.touchwand.fanLevel.state.option.medium = Medium +channel-type.touchwand.fanLevel.state.option.high = High +channel-type.touchwand.fanLevel.state.option.fanAuto = Auto +channel-type.touchwand.illumination.label = Illumination +channel-type.touchwand.illumination.description = This channel shows the brightness of the environment in Lux. +channel-type.touchwand.isOpen.label = Open Status +channel-type.touchwand.isOpen.label = Open Status +channel-type.touchwand.leak.label = Leak Detected +channel-type.touchwand.mode.label = Mode +channel-type.touchwand.mode.description = Thermostat mode (Cool, Heat, Fan, Dry, Auto) +channel-type.touchwand.mode.state.option.cool = Cool +channel-type.touchwand.mode.state.option.heat = Heat +channel-type.touchwand.mode.state.option.fan = Fan +channel-type.touchwand.mode.state.option.auto = Auto +channel-type.touchwand.mode.state.option.dry = Dry +channel-type.touchwand.motion.label = Motion Status +channel-type.touchwand.motion.label = Motion Detected +channel-type.touchwand.roomTemperature.label = Room Temperature +channel-type.touchwand.roomTemperature.description = Current room temperature +channel-type.touchwand.shutter.label = Shutter +channel-type.touchwand.shutter.description = The Shutter channel allows control shutters +channel-type.touchwand.smoke.label = Smoke Detected +channel-type.touchwand.state.label = AC On Off State +channel-type.touchwand.switch.label = Switch +channel-type.touchwand.switch.description = The switch channel allows to switch the light on and off. +channel-type.touchwand.targetTemperature.label = Target Temperature +channel-type.touchwand.targetTemperature.description = The set point temperature +channel-type.touchwand.temperature.label = Temperature +channel-type.touchwand.wallaction.label = WallController action diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/i18n/tplinksmarthome.properties b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/i18n/tplinksmarthome.properties new file mode 100644 index 0000000000000..8472187fc373e --- /dev/null +++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/OH-INF/i18n/tplinksmarthome.properties @@ -0,0 +1,144 @@ +# binding + +binding.tplinksmarthome.name = TP-Link Smart Home Binding +binding.tplinksmarthome.description = This binding integrates the TP-Link Wi-Fi Smart Home devices. + +# thing types + +thing-type.tplinksmarthome.ep10.label = EP10 +thing-type.tplinksmarthome.ep10.description = TP-Link EP10 Kasa Smart Wi-Fi Plug Mini +thing-type.tplinksmarthome.ep40.label = EP40 +thing-type.tplinksmarthome.ep40.description = TP-Link EP40 Kasa Smart Wi-Fi Outdoor Plug +thing-type.tplinksmarthome.ep40.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.ep40.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.hs100.label = HS100 +thing-type.tplinksmarthome.hs100.description = TP-Link HS100 Smart Wi-Fi Plug +thing-type.tplinksmarthome.hs103.label = HS103 +thing-type.tplinksmarthome.hs103.description = TP-Link HS103 Smart Wi-Fi Plug Lite +thing-type.tplinksmarthome.hs105.label = HS105 +thing-type.tplinksmarthome.hs105.description = TP-Link HS105 Smart Wi-Fi Plug +thing-type.tplinksmarthome.hs107.label = HS107 +thing-type.tplinksmarthome.hs107.description = TP-Link HS107 Smart Wi-Fi Plug, 2-Outlets +thing-type.tplinksmarthome.hs107.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.hs107.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.hs110.label = HS110 +thing-type.tplinksmarthome.hs110.description = TP-Link HS110 Smart Wi-Fi Plug with Energy Monitoring +thing-type.tplinksmarthome.hs200.label = HS200 +thing-type.tplinksmarthome.hs200.description = TP-Link HS200 Smart Wi-Fi Switch +thing-type.tplinksmarthome.hs210.label = HS210 +thing-type.tplinksmarthome.hs210.description = TP-Link HS210 Smart Wi-Fi Light Switch 3-Way Kit +thing-type.tplinksmarthome.hs220.label = HS220 +thing-type.tplinksmarthome.hs220.description = TP-Link HS220 Smart Wi-Fi Light Switch, Dimmer +thing-type.tplinksmarthome.hs300.label = HS300 +thing-type.tplinksmarthome.hs300.description = TP-Link HS300 Smart Wi-Fi Power Strip +thing-type.tplinksmarthome.hs300.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.hs300.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.hs300.group.outlet3.label = Outlet 3 +thing-type.tplinksmarthome.hs300.group.outlet4.label = Outlet 4 +thing-type.tplinksmarthome.hs300.group.outlet5.label = Outlet 5 +thing-type.tplinksmarthome.hs300.group.outlet6.label = Outlet 6 +thing-type.tplinksmarthome.kb100.label = KB100 +thing-type.tplinksmarthome.kb100.description = TP-Link KB100 Kasa Smart Light Bulb +thing-type.tplinksmarthome.kb130.label = KB130 +thing-type.tplinksmarthome.kb130.description = TP-Link KB130 Kasa Multi-color Smart Light Bulb +thing-type.tplinksmarthome.kl110.label = KL110 +thing-type.tplinksmarthome.kl110.description = TP-Link KL110 Smart Wi-Fi LED Bulb with Brightness +thing-type.tplinksmarthome.kl120.label = KL120 +thing-type.tplinksmarthome.kl120.description = TP-Link KL120 Smart Wi-Fi LED Bulb with Tunable White Light Brightness +thing-type.tplinksmarthome.kl125.label = KL125 +thing-type.tplinksmarthome.kl125.description = TP-Link KL125 Kasa Smart Wi-Fi Bulb Multicolor +thing-type.tplinksmarthome.kl130.label = KL130 +thing-type.tplinksmarthome.kl130.description = TP-Link KL130 Smart Wi-Fi LED Bulb with Color Changing Hue +thing-type.tplinksmarthome.kl135.label = KL135 +thing-type.tplinksmarthome.kl135.description = TP-Link KL135 Kasa Smart Wi-Fi Bulb Multicolor +thing-type.tplinksmarthome.kl50.label = KL50 +thing-type.tplinksmarthome.kl50.description = Kasa Filament Smart Bulb, Soft White +thing-type.tplinksmarthome.kl60.label = KL60 +thing-type.tplinksmarthome.kl60.description = Kasa Filament Smart Bulb, Warm Amber +thing-type.tplinksmarthome.kp100.label = KP100 +thing-type.tplinksmarthome.kp100.description = TP-Link KP100 Kasa Wi-Fi Smart Plug - Slim Edition +thing-type.tplinksmarthome.kp105.label = KP105 +thing-type.tplinksmarthome.kp105.description = TP-Link KP105 Kasa Wi-Fi Smart Plug - Slim Edition +thing-type.tplinksmarthome.kp115.label = KP115 +thing-type.tplinksmarthome.kp115.description = TP-Link KP115 Kasa Wi-Fi Smart Plug with Energy Monitoring - Slim Edition +thing-type.tplinksmarthome.kp200.label = KP200 +thing-type.tplinksmarthome.kp200.description = TP-Link KP200 Smart Wi-Fi Power Outlet, 2-Sockets +thing-type.tplinksmarthome.kp200.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.kp200.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.kp303.label = KP303 +thing-type.tplinksmarthome.kp303.description = TP-Link HS300 Smart Wi-Fi Power Strip, 3-Outlets +thing-type.tplinksmarthome.kp303.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.kp303.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.kp303.group.outlet3.label = Outlet 3 +thing-type.tplinksmarthome.kp400.label = KP400 +thing-type.tplinksmarthome.kp400.description = TP-Link KP400 Smart Outdoor Plug +thing-type.tplinksmarthome.kp400.group.outlet1.label = Outlet 1 +thing-type.tplinksmarthome.kp400.group.outlet2.label = Outlet 2 +thing-type.tplinksmarthome.lb100.label = LB100 +thing-type.tplinksmarthome.lb100.description = TP-Link LB100 Smart Wi-Fi LED Bulb with Dimmable Light +thing-type.tplinksmarthome.lb110.label = LB110 +thing-type.tplinksmarthome.lb110.description = TP-Link LB110 Smart Wi-Fi LED Bulb with Dimmable Light +thing-type.tplinksmarthome.lb120.label = LB120 +thing-type.tplinksmarthome.lb120.description = TP-Link LB120 Smart Wi-Fi LED Bulb with Tunable White Light +thing-type.tplinksmarthome.lb130.label = LB130 +thing-type.tplinksmarthome.lb130.description = TP-Link LB130 Smart Wi-Fi LED Bulb with Color Changing Hue +thing-type.tplinksmarthome.lb200.label = LB200 +thing-type.tplinksmarthome.lb200.description = TP-Link LB200 Smart Wi-Fi LED Bulb with Dimmable Light +thing-type.tplinksmarthome.lb230.label = LB230 +thing-type.tplinksmarthome.lb230.description = TP-Link LB230 Smart Wi-Fi LED Bulb with Color Changing Hue +thing-type.tplinksmarthome.re270.label = RE270K +thing-type.tplinksmarthome.re270.description = TP-Link AC750 Wi-Fi Range Extender with Smart Plug +thing-type.tplinksmarthome.re370.label = RE370K +thing-type.tplinksmarthome.re370.description = TP-Link AC1200 Wi-Fi Range Extender with Smart Plug + +# thing types config + +thing-type.config.tplinksmarthome.device-bulb.deviceId.label = Device Id +thing-type.config.tplinksmarthome.device-bulb.deviceId.description = The id of the device. +thing-type.config.tplinksmarthome.device-bulb.ipAddress.label = IP Address +thing-type.config.tplinksmarthome.device-bulb.ipAddress.description = IP Address of the device. +thing-type.config.tplinksmarthome.device-bulb.refresh.label = Refresh Rate +thing-type.config.tplinksmarthome.device-bulb.refresh.description = Refresh of device state in seconds. +thing-type.config.tplinksmarthome.device-bulb.transitionPeriod.label = Transition Period +thing-type.config.tplinksmarthome.device-bulb.transitionPeriod.description = Time the transition to the new state takes in milliseconds. +thing-type.config.tplinksmarthome.device-plug.deviceId.label = Device Id +thing-type.config.tplinksmarthome.device-plug.deviceId.description = The id of the device. +thing-type.config.tplinksmarthome.device-plug.ipAddress.label = IP Address +thing-type.config.tplinksmarthome.device-plug.ipAddress.description = IP Address of the device. +thing-type.config.tplinksmarthome.device-plug.refresh.label = Refresh Rate +thing-type.config.tplinksmarthome.device-plug.refresh.description = Refresh of device state in seconds. +thing-type.config.tplinksmarthome.device-switch.deviceId.label = Device Id +thing-type.config.tplinksmarthome.device-switch.deviceId.description = The id of the device. +thing-type.config.tplinksmarthome.device-switch.ipAddress.label = IP Address +thing-type.config.tplinksmarthome.device-switch.ipAddress.description = IP Address of the device. +thing-type.config.tplinksmarthome.device-switch.refresh.label = Refresh Rate +thing-type.config.tplinksmarthome.device-switch.refresh.description = Refresh of device state in seconds. + +# channel group types + +channel-group-type.tplinksmarthome.energy-outlet.label = Outlet +channel-group-type.tplinksmarthome.switch-group.label = Outlet Group +channel-group-type.tplinksmarthome.switch-outlet.label = Outlet + +# channel types + +channel-type.tplinksmarthome.colorTemperatureAbs1.label = Color Temperature +channel-type.tplinksmarthome.colorTemperatureAbs1.description = This channel supports adjusting the color temperature from 2700K to 6500K. +channel-type.tplinksmarthome.colorTemperatureAbs2.label = Color Temperature +channel-type.tplinksmarthome.colorTemperatureAbs2.description = This channel supports adjusting the color temperature from 2500K to 9000K. +channel-type.tplinksmarthome.colorTemperatureAbs3.label = Color Temperature +channel-type.tplinksmarthome.colorTemperatureAbs3.description = This channel supports adjusting the color temperature from 2500K to 6500K. +channel-type.tplinksmarthome.current.label = Current +channel-type.tplinksmarthome.current.description = Actual current usage. +channel-type.tplinksmarthome.energy-usage.label = Energy Usage +channel-type.tplinksmarthome.energy-usage.description = Actual energy usage. +channel-type.tplinksmarthome.led.label = Switch Led +channel-type.tplinksmarthome.led.description = Switch the Smart Home device led on or off. +channel-type.tplinksmarthome.power.label = Power +channel-type.tplinksmarthome.power.description = Actual power usage. +channel-type.tplinksmarthome.rssi.label = Signal +channel-type.tplinksmarthome.rssi.description = Wi-Fi signal strength indicator. +channel-type.tplinksmarthome.switch-readonly.label = Switch +channel-type.tplinksmarthome.switch-readonly.description = Shows the switch state of the Smart Home device. +channel-type.tplinksmarthome.voltage.label = Voltage +channel-type.tplinksmarthome.voltage.description = Actual voltage usage. diff --git a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties new file mode 100644 index 0000000000000..8fe04b3f4a16d --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties @@ -0,0 +1,57 @@ +# binding + +binding.unifi.name = UniFi Binding +binding.unifi.description = The UniFi binding integrates the UniFi controller from Ubiquiti Networks to facilitate tracking of Wi-Fi clients. + +# thing types + +thing-type.unifi.controller.label = UniFi Controller +thing-type.unifi.controller.description = A UniFi controller. +thing-type.unifi.wirelessClient.label = UniFi Wireless Client +thing-type.unifi.wirelessClient.description = A wireless client connected to a UniFi wireless network + +# thing types config + +thing-type.config.unifi.controller.host.label = Hostname +thing-type.config.unifi.controller.host.description = Hostname of IP address of the UniFi Controller +thing-type.config.unifi.controller.password.label = Password +thing-type.config.unifi.controller.password.description = The password to access the UniFi Controller. +thing-type.config.unifi.controller.port.label = Port +thing-type.config.unifi.controller.port.description = Port of the UniFi Controller +thing-type.config.unifi.controller.refresh.label = Refresh Interval +thing-type.config.unifi.controller.refresh.description = The refresh interval in seconds to poll the UniFi controller +thing-type.config.unifi.controller.unifios.label = UniFi OS +thing-type.config.unifi.controller.unifios.description = If the UniFi Controller is running on UniFi OS. +thing-type.config.unifi.controller.username.label = Username +thing-type.config.unifi.controller.username.description = The username to access the UniFi Controller. +thing-type.config.unifi.wirelessClient.cid.label = Client ID +thing-type.config.unifi.wirelessClient.cid.description = The MAC address, IP address, hostname or alias of the client +thing-type.config.unifi.wirelessClient.considerHome.label = Consider Home Interval +thing-type.config.unifi.wirelessClient.considerHome.description = The interval in seconds to consider the client as home +thing-type.config.unifi.wirelessClient.site.label = Site +thing-type.config.unifi.wirelessClient.site.description = The site where the client should be found (optional) + +# channel types + +channel-type.unifi.ap.label = Access Point +channel-type.unifi.ap.description = Access Point the wireless client is connected to +channel-type.unifi.blocked.label = Blocked +channel-type.unifi.blocked.description = Is device blocked +channel-type.unifi.essid.label = Wireless Network +channel-type.unifi.essid.description = Wireless Network (ESSID) the wireless client is connected to +channel-type.unifi.ipAddress.label = IP Address +channel-type.unifi.ipAddress.description = IP address of the client +channel-type.unifi.lastSeen.label = Last Seen +channel-type.unifi.lastSeen.description = Timestamp of when the client was last seen +channel-type.unifi.macAddress.label = MAC Address +channel-type.unifi.macAddress.description = MAC address of the client +channel-type.unifi.online.label = Online +channel-type.unifi.online.description = Online status of the wireless client +channel-type.unifi.reconnect.label = Reconnect +channel-type.unifi.reconnect.description = Forces a client to reconnect +channel-type.unifi.rssi.label = Received Signal Strength Indicator +channel-type.unifi.rssi.description = Received Signal Strength Indicator (RSSI) of the wireless client +channel-type.unifi.site.label = Site Name +channel-type.unifi.site.description = UniFi Site the client is associated with +channel-type.unifi.uptime.label = Uptime +channel-type.unifi.uptime.description = Uptime of the client (in seconds) diff --git a/bundles/org.openhab.binding.unifiedremote/src/main/resources/OH-INF/i18n/unifiedremote.properties b/bundles/org.openhab.binding.unifiedremote/src/main/resources/OH-INF/i18n/unifiedremote.properties new file mode 100644 index 0000000000000..dc2450a462b54 --- /dev/null +++ b/bundles/org.openhab.binding.unifiedremote/src/main/resources/OH-INF/i18n/unifiedremote.properties @@ -0,0 +1,56 @@ +# binding + +binding.unifiedremote.name = Unified Remote Binding +binding.unifiedremote.description = This is the binding for Unified Remote Server (https://www.unifiedremote.com/). + +# thing types + +thing-type.unifiedremote.server.label = Unified Remote Server +thing-type.unifiedremote.server.description = Unified Remote Server Thing for Unified Remote Binding + +# thing types config + +thing-type.config.unifiedremote.server.host.label = Hostname +thing-type.config.unifiedremote.server.host.description = Unified Remote Server Hostname +thing-type.config.unifiedremote.server.tcpPort.label = TCP Port +thing-type.config.unifiedremote.server.tcpPort.description = Unified Remote Server Port TCP +thing-type.config.unifiedremote.server.udpPort.label = UDP Port +thing-type.config.unifiedremote.server.udpPort.description = Unified Remote Server Port UDP + +# channel types + +channel-type.unifiedremote.mouse-move-channel.label = Mouse Move Channel +channel-type.unifiedremote.mouse-move-channel.description = Relative mouse control on the server host +channel-type.unifiedremote.send-key-channel.label = Toggle Key Channel +channel-type.unifiedremote.send-key-channel.description = Toggle Key +channel-type.unifiedremote.send-key-channel.state.option.LEFT_CLICK = LEFT_CLICK +channel-type.unifiedremote.send-key-channel.state.option.RIGHT_CLICK = RIGHT_CLICK +channel-type.unifiedremote.send-key-channel.state.option.LOCK = LOCK +channel-type.unifiedremote.send-key-channel.state.option.UNLOCK = UNLOCK +channel-type.unifiedremote.send-key-channel.state.option.SLEEP = SLEEP +channel-type.unifiedremote.send-key-channel.state.option.SHUTDOWN = SHUTDOWN +channel-type.unifiedremote.send-key-channel.state.option.RESTART = RESTART +channel-type.unifiedremote.send-key-channel.state.option.LOGOFF = LOGOFF +channel-type.unifiedremote.send-key-channel.state.option.PLAY/PAUSE = PLAY/PAUSE +channel-type.unifiedremote.send-key-channel.state.option.NEXT = NEXT +channel-type.unifiedremote.send-key-channel.state.option.PREVIOUS = PREVIOUS +channel-type.unifiedremote.send-key-channel.state.option.STOP = STOP +channel-type.unifiedremote.send-key-channel.state.option.VOLUME_MUTE = VOLUME_MUTE +channel-type.unifiedremote.send-key-channel.state.option.VOLUME_UP = VOLUME_UP +channel-type.unifiedremote.send-key-channel.state.option.VOLUME_DOWN = VOLUME_DOWN +channel-type.unifiedremote.send-key-channel.state.option.BRIGHTNESS_UP = BRIGHTNESS_UP +channel-type.unifiedremote.send-key-channel.state.option.BRIGHTNESS_DOWN = BRIGHTNESS_DOWN +channel-type.unifiedremote.send-key-channel.state.option.MONITOR_OFF = MONITOR_OFF +channel-type.unifiedremote.send-key-channel.state.option.MONITOR_ON = MONITOR_ON +channel-type.unifiedremote.send-key-channel.state.option.ESCAPE = ESCAPE +channel-type.unifiedremote.send-key-channel.state.option.SPACE = SPACE +channel-type.unifiedremote.send-key-channel.state.option.BACK = BACK +channel-type.unifiedremote.send-key-channel.state.option.LWIN = LWIN +channel-type.unifiedremote.send-key-channel.state.option.CONTROL = CONTROL +channel-type.unifiedremote.send-key-channel.state.option.TAB = TAB +channel-type.unifiedremote.send-key-channel.state.option.MENU = MENU +channel-type.unifiedremote.send-key-channel.state.option.RETURN = RETURN +channel-type.unifiedremote.send-key-channel.state.option.UP = UP +channel-type.unifiedremote.send-key-channel.state.option.DOWN = DOWN +channel-type.unifiedremote.send-key-channel.state.option.LEFT = LEFT +channel-type.unifiedremote.send-key-channel.state.option.RIGHT = RIGHT diff --git a/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/upb.properties b/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/upb.properties new file mode 100644 index 0000000000000..385144f372f2c --- /dev/null +++ b/bundles/org.openhab.binding.upb/src/main/resources/OH-INF/i18n/upb.properties @@ -0,0 +1,48 @@ +# binding + +binding.upb.name = UPB Binding +binding.upb.description = The Universal Powerline Bus (UPB) binding reads and writes messages to and from a UPB modem + +# binding config + +binding.config.upb.networkId.label = Default Network ID for Devices +binding.config.upb.networkId.description = The ID of the primary UPB network. May be overridden on a per-device basis. + +# thing types + +thing-type.upb.generic.label = Generic Powerline Device +thing-type.upb.generic.description = A generic device in a UPB network +thing-type.upb.leviton-38a00-1.label = Leviton UPB 6-Button Scene Switch +thing-type.upb.leviton-38a00-1.description = A wall-mounted panel with six pushbuttons labeled ON, A, B, C, D, and OFF. +thing-type.upb.leviton-38a00-1.channel.btnA.label = Scene A +thing-type.upb.leviton-38a00-1.channel.btnB.label = Scene B +thing-type.upb.leviton-38a00-1.channel.btnC.label = Scene C +thing-type.upb.leviton-38a00-1.channel.btnD.label = Scene D +thing-type.upb.leviton-38a00-1.channel.btnOff.label = OFF Button +thing-type.upb.leviton-38a00-1.channel.btnOn.label = ON Button +thing-type.upb.serial-pim.label = Serial PIM +thing-type.upb.serial-pim.description = A serial Powerline Interface Module (PIM) is a modem for UPB +thing-type.upb.virtual.label = Virtual UPB Device +thing-type.upb.virtual.description = This pseudo-device is useful for switching scenes and receiving scene updates. It does not correspond to any physical device on the network. +thing-type.upb.virtual.channel.linkActivated.label = Link Activated +thing-type.upb.virtual.channel.linkDeactivated.label = Link Deactivated + +# thing types config + +thing-type.config.upb.device-address.networkId.label = Network ID +thing-type.config.upb.device-address.networkId.description = The ID of the UPB network that the device belongs to +thing-type.config.upb.device-address.unitId.label = Unit ID +thing-type.config.upb.device-address.unitId.description = The unit ID of the device on the UPB network +thing-type.config.upb.serial-pim.port.label = Serial port +thing-type.config.upb.serial-pim.port.description = The file name of the serial port to use to communicate with the PIM. + +# channel types + +channel-type.upb.link.label = Scene +channel-type.upb.link.description = Selected scene +channel-type.upb.scene-selection.label = Scene Selection Events + +# channel types config + +channel-type.config.upb.scene-selection.linkId.label = Link ID +channel-type.config.upb.scene-selection.linkId.description = The link ID or scene number that this channel corresponds to diff --git a/bundles/org.openhab.binding.upnpcontrol/src/main/resources/OH-INF/i18n/upnpcontrol.properties b/bundles/org.openhab.binding.upnpcontrol/src/main/resources/OH-INF/i18n/upnpcontrol.properties new file mode 100644 index 0000000000000..f84d6ced379cf --- /dev/null +++ b/bundles/org.openhab.binding.upnpcontrol/src/main/resources/OH-INF/i18n/upnpcontrol.properties @@ -0,0 +1,102 @@ +# binding + +binding.upnpcontrol.name = UPnP Control Binding +binding.upnpcontrol.description = This binding acts as a UPnP Control Point that can query media server content directories and serve content to media renderers. + +# binding config + +binding.config.upnpcontrol.path.label = Storage Path +binding.config.upnpcontrol.path.description = Folder path for playlists and favourites. If not set, it will default to $OPENHAB_USERDATA/upnpcontrol. The folder will be created on first use when it does not exist. + +# thing types + +thing-type.upnpcontrol.upnprenderer.label = UPnPRenderer +thing-type.upnpcontrol.upnprenderer.description = UPnP AV Renderer +thing-type.upnpcontrol.upnpserver.label = UPnPServer +thing-type.upnpcontrol.upnpserver.description = UPnP AV Server + +# thing types config + +thing-type.config.upnpcontrol.upnprenderer.maxNotificationDuration.label = Maximum Notification Duration +thing-type.config.upnpcontrol.upnprenderer.maxNotificationDuration.description = Specifies the maximum duration for notifications, longer notification sounds will be interrupted. O represents no maximum duration +thing-type.config.upnpcontrol.upnprenderer.notificationVolumeAdjustment.label = Notification Sound Volume Adjustment +thing-type.config.upnpcontrol.upnprenderer.notificationVolumeAdjustment.description = Specifies the percentage adjustment to the current sound volume when playing notifications +thing-type.config.upnpcontrol.upnprenderer.refresh.label = Refresh Interval +thing-type.config.upnpcontrol.upnprenderer.refresh.description = Specifies the refresh interval in seconds +thing-type.config.upnpcontrol.upnprenderer.responseTimeout.label = UPnP Response Timeout +thing-type.config.upnpcontrol.upnprenderer.responseTimeout.description = Specifies the timeout in milliseconds when waiting for responses on UPnP actions +thing-type.config.upnpcontrol.upnprenderer.seekStep.label = Fast Forward/Rewind Step +thing-type.config.upnpcontrol.upnprenderer.seekStep.description = Step in seconds for fast forward rewind +thing-type.config.upnpcontrol.upnprenderer.udn.label = Unique Device Name +thing-type.config.upnpcontrol.upnprenderer.udn.description = The UDN identifies the UPnP Renderer +thing-type.config.upnpcontrol.upnpserver.browseDown.label = Auto Browse Down +thing-type.config.upnpcontrol.upnpserver.browseDown.description = When browse or search results in exactly one container entry, iteratively browse down until the result contains multiple container entries or at least one media entry +thing-type.config.upnpcontrol.upnpserver.filter.label = Filter Content +thing-type.config.upnpcontrol.upnpserver.filter.description = Only list content which is playable on the selected renderer +thing-type.config.upnpcontrol.upnpserver.refresh.label = Refresh Interval +thing-type.config.upnpcontrol.upnpserver.refresh.description = Specifies the refresh interval in seconds +thing-type.config.upnpcontrol.upnpserver.responseTimeout.label = UPnP Response Timeout +thing-type.config.upnpcontrol.upnpserver.responseTimeout.description = Specifies the timeout in milliseconds when waiting for responses on UPnP actions +thing-type.config.upnpcontrol.upnpserver.searchFromRoot.label = Search From Root +thing-type.config.upnpcontrol.upnpserver.searchFromRoot.description = Always search from the root directory +thing-type.config.upnpcontrol.upnpserver.sortCriteria.label = Sort Criteria +thing-type.config.upnpcontrol.upnpserver.sortCriteria.description = Sort criteria for the titles in the selection list and when sending for playing to a renderer. The criteria are defined in UPnP sort criteria format. Examples: +dc:title, -dc:creator, +upnp:album. Supported sort criteria will depend on the media server +thing-type.config.upnpcontrol.upnpserver.udn.label = Unique Device Name +thing-type.config.upnpcontrol.upnpserver.udn.description = The UDN identifies the UPnP Media Server + +# channel types + +channel-type.upnpcontrol.album.label = Album +channel-type.upnpcontrol.album.description = Now playing album +channel-type.upnpcontrol.albumart.label = Album Art +channel-type.upnpcontrol.albumart.description = Now playing album art +channel-type.upnpcontrol.browse.label = Current Media Id +channel-type.upnpcontrol.browse.description = Current id of media entry or container, option list to browse hierarchy +channel-type.upnpcontrol.creator.label = Creator +channel-type.upnpcontrol.creator.description = Now playing creator +channel-type.upnpcontrol.favorite.label = Favorite +channel-type.upnpcontrol.favorite.description = Favorite name +channel-type.upnpcontrol.favoriteaction.label = Favorite Action +channel-type.upnpcontrol.favoriteaction.description = Favorite action +channel-type.upnpcontrol.favoriteaction.command.option.SAVE = Save +channel-type.upnpcontrol.favoriteaction.command.option.DELETE = Delete +channel-type.upnpcontrol.favoriteselect.label = Select Favorite +channel-type.upnpcontrol.favoriteselect.description = Select favorite to play +channel-type.upnpcontrol.genre.label = Genre +channel-type.upnpcontrol.genre.description = Now playing genre +channel-type.upnpcontrol.loudness.label = Loudness +channel-type.upnpcontrol.loudness.description = Loudness +channel-type.upnpcontrol.onlyplayone.label = Only Play One +channel-type.upnpcontrol.onlyplayone.description = Stop playback after playing one media entry from queue +channel-type.upnpcontrol.playlist.label = Playlist +channel-type.upnpcontrol.playlist.description = Playlist name +channel-type.upnpcontrol.playlistaction.label = Playlist Action +channel-type.upnpcontrol.playlistaction.description = Playlist action +channel-type.upnpcontrol.playlistaction.command.option.RESTORE = Restore +channel-type.upnpcontrol.playlistaction.command.option.SAVE = Save +channel-type.upnpcontrol.playlistaction.command.option.APPEND = Append +channel-type.upnpcontrol.playlistaction.command.option.DELETE = Delete +channel-type.upnpcontrol.playlistselect.label = Select Playlist +channel-type.upnpcontrol.playlistselect.description = Playlist for selection +channel-type.upnpcontrol.publisher.label = Publisher +channel-type.upnpcontrol.publisher.description = Now playing publisher +channel-type.upnpcontrol.reltrackposition.label = Relative Track Position +channel-type.upnpcontrol.reltrackposition.description = Track position as percentage of track duration +channel-type.upnpcontrol.repeat.label = Repeat +channel-type.upnpcontrol.repeat.description = Repeat the selection +channel-type.upnpcontrol.search.label = Search Criteria +channel-type.upnpcontrol.search.description = Search criteria for searching the directory. Search criteria are defined in UPnP search criteria format. Examples: dc:title contains "song", dc:creator contains "SpringSteen", unp:class = "object.item.audioItem", upnp:album contains "Born in" +channel-type.upnpcontrol.shuffle.label = Shuffle +channel-type.upnpcontrol.shuffle.description = Random shuffle the selection +channel-type.upnpcontrol.stop.label = Stop +channel-type.upnpcontrol.stop.description = Stop the player +channel-type.upnpcontrol.trackduration.label = Track Duration +channel-type.upnpcontrol.trackduration.description = Now playing track duration +channel-type.upnpcontrol.tracknumber.label = Track Number +channel-type.upnpcontrol.tracknumber.description = Now playing track number +channel-type.upnpcontrol.trackposition.label = Track Position +channel-type.upnpcontrol.trackposition.description = Now playing track position +channel-type.upnpcontrol.upnprenderer.label = Renderer +channel-type.upnpcontrol.upnprenderer.description = Select AV renderer +channel-type.upnpcontrol.uri.label = URI +channel-type.upnpcontrol.uri.description = Now playing URI diff --git a/bundles/org.openhab.binding.valloxmv/src/main/resources/OH-INF/i18n/valloxmv.properties b/bundles/org.openhab.binding.valloxmv/src/main/resources/OH-INF/i18n/valloxmv.properties new file mode 100644 index 0000000000000..4ea5837779ac6 --- /dev/null +++ b/bundles/org.openhab.binding.valloxmv/src/main/resources/OH-INF/i18n/valloxmv.properties @@ -0,0 +1,103 @@ +# binding + +binding.valloxmv.name = ValloxMV Binding +binding.valloxmv.description = Binding for online interface of Vallox ventilation unit + +# thing types + +thing-type.valloxmv.valloxmv.label = Vallox Ventilation Unit +thing-type.valloxmv.valloxmv.description = Interface to online interface of Vallox ventilation unit + +# thing types config + +thing-type.config.valloxmv.valloxmv.ip.label = IP Address +thing-type.config.valloxmv.valloxmv.ip.description = IP address or host name of online interface of ventilation unit +thing-type.config.valloxmv.valloxmv.updateinterval.label = Update Interval +thing-type.config.valloxmv.valloxmv.updateinterval.description = Data update interval in seconds (default: 60s) + +# channel types + +channel-type.valloxmv.awayairtemptarget.label = Away Target Temperature +channel-type.valloxmv.awayairtemptarget.description = Target temperature in away state +channel-type.valloxmv.awayspeedsetting.label = Away Fan Speed +channel-type.valloxmv.awayspeedsetting.description = Away fan speed in % (0-100) +channel-type.valloxmv.boostairtemptarget.label = Boost Target Temperature +channel-type.valloxmv.boostairtemptarget.description = Target temperature in boost state +channel-type.valloxmv.boostspeedsetting.label = Boost Fan Speed +channel-type.valloxmv.boostspeedsetting.description = Boost fan speed in % (0-100) +channel-type.valloxmv.boosttime.label = Boost Timer +channel-type.valloxmv.boosttime.description = Boost profile timer value in minutes +channel-type.valloxmv.boosttimerenabled.label = Boost Timer Enabled +channel-type.valloxmv.boosttimerenabled.description = Timer enabled setting in boost profile +channel-type.valloxmv.cellstate.label = Cell State +channel-type.valloxmv.cellstate.description = Current cell state +channel-type.valloxmv.cellstate.state.option.0 = Heat recovery +channel-type.valloxmv.cellstate.state.option.1 = Cool recovery +channel-type.valloxmv.cellstate.state.option.2 = Bypass +channel-type.valloxmv.cellstate.state.option.3 = Defrosting +channel-type.valloxmv.co2.label = CO2 +channel-type.valloxmv.co2.description = CO2 measurement +channel-type.valloxmv.extraairtemptarget.label = Extra Target Temperature +channel-type.valloxmv.extraairtemptarget.description = Target temperature in extra profile +channel-type.valloxmv.extraextrfan.label = Extra Extract Fan Speed +channel-type.valloxmv.extraextrfan.description = Extra profile extract fan speed in % (0-100) +channel-type.valloxmv.extrasuppfan.label = Extra Supply Fan Speed +channel-type.valloxmv.extrasuppfan.description = Extra profile supply fan speed in % (0-100) +channel-type.valloxmv.extratime.label = Extra Timer +channel-type.valloxmv.extratime.description = Extra profile timer value in minutes +channel-type.valloxmv.extratimerenabled.label = Extra Timer Enabled +channel-type.valloxmv.extratimerenabled.description = Timer enabled setting in extra profile +channel-type.valloxmv.extrfanbalancebase.label = Extract Fan Base Speed +channel-type.valloxmv.extrfanbalancebase.description = Extract fan base speed in % (0-100) +channel-type.valloxmv.fanspeed.label = Fan Speed +channel-type.valloxmv.fanspeed.description = Fan speed in % (0-100) +channel-type.valloxmv.fanspeedextract.label = Fan Speed Extracting +channel-type.valloxmv.fanspeedextract.description = Fan speed of extracting fan (1/min) +channel-type.valloxmv.fanspeedsupply.label = Fan Speed Supplying +channel-type.valloxmv.fanspeedsupply.description = Fan speed of supplying fan (1/min) +channel-type.valloxmv.filterchangeddate.label = Last Filter Change +channel-type.valloxmv.filterchangeddate.description = Date filter was changed last time +channel-type.valloxmv.fireplaceextrfan.label = Fireplace Extract Fan Speed +channel-type.valloxmv.fireplaceextrfan.description = Fireplace profile extract fan speed in % (0-100) +channel-type.valloxmv.fireplacesuppfan.label = Fireplace Supply Fan Speed +channel-type.valloxmv.fireplacesuppfan.description = Fireplace profile supply fan speed in % (0-100) +channel-type.valloxmv.fireplacetime.label = Fireplace Timer +channel-type.valloxmv.fireplacetime.description = Fireplace profile timer value in minutes +channel-type.valloxmv.fireplacetimerenabled.label = Fireplace Timer Enabled +channel-type.valloxmv.fireplacetimerenabled.description = Timer enabled setting in fireplace profile +channel-type.valloxmv.homeairtemptarget.label = Home Target Temperature +channel-type.valloxmv.homeairtemptarget.description = Target temperature in home state +channel-type.valloxmv.homespeedsetting.label = Home Fan Speed +channel-type.valloxmv.homespeedsetting.description = Home fan speed in % (0-100) +channel-type.valloxmv.humidity.label = Humidity +channel-type.valloxmv.humidity.description = Current humidity of the air flow exhausting the building. +channel-type.valloxmv.onoff.label = On +channel-type.valloxmv.onoff.description = Power switch for ventilation unit +channel-type.valloxmv.remainingfilterdays.label = Next Filter Change +channel-type.valloxmv.remainingfilterdays.description = Days until filter has to be changed +channel-type.valloxmv.state.label = State +channel-type.valloxmv.state.description = Current state of ventilation unit +channel-type.valloxmv.state.state.option.1 = Fireplace +channel-type.valloxmv.state.state.option.2 = Away +channel-type.valloxmv.state.state.option.3 = At home +channel-type.valloxmv.state.state.option.4 = Boost +channel-type.valloxmv.suppfanbalancebase.label = Supply Fan Base Speed +channel-type.valloxmv.suppfanbalancebase.description = Supply fan base speed in % (0-100) +channel-type.valloxmv.tempexhaust.label = Temperature Exhaust +channel-type.valloxmv.tempexhaust.description = Current temperature of the air flow exhausting the building. +channel-type.valloxmv.tempincoming.label = Temperature Incoming +channel-type.valloxmv.tempincoming.description = Current temperature of the air flow incoming to the building. +channel-type.valloxmv.tempincomingbeforeheating.label = Temperature Incoming Before Heating +channel-type.valloxmv.tempincomingbeforeheating.description = Current temperature of the air flow incoming to the building before heating (if optional heating module included in ventilation unit). +channel-type.valloxmv.tempinside.label = Temperature Inside +channel-type.valloxmv.tempinside.description = Current temperature inside the building. +channel-type.valloxmv.tempoutside.label = Temperature Outside +channel-type.valloxmv.tempoutside.description = Current temperature outside the building. +channel-type.valloxmv.uptimehours.label = Total Uptime Hours +channel-type.valloxmv.uptimehours.description = Total uptime in hours (+ uptime in years = total uptime) +channel-type.valloxmv.uptimehourscurrent.label = Current Uptime Hours +channel-type.valloxmv.uptimehourscurrent.description = Current uptime in hours +channel-type.valloxmv.uptimeyears.label = Total Uptime Years +channel-type.valloxmv.uptimeyears.description = Total uptime in years (+ uptime in hours = total uptime) +channel-type.valloxmv.weeklytimerenabled.label = Weekly Timer Enabled +channel-type.valloxmv.weeklytimerenabled.description = Weekly timer enabled setting diff --git a/bundles/org.openhab.binding.vdr/src/main/resources/OH-INF/i18n/vdr.properties b/bundles/org.openhab.binding.vdr/src/main/resources/OH-INF/i18n/vdr.properties new file mode 100644 index 0000000000000..afb331287566d --- /dev/null +++ b/bundles/org.openhab.binding.vdr/src/main/resources/OH-INF/i18n/vdr.properties @@ -0,0 +1,109 @@ +# binding + +binding.vdr.name = VDR Binding +binding.vdr.description = The Video Disk Recorder (VDR) binding allows to control your own Video Disk Recorder (https://www.tvdr.de). + +# thing types + +thing-type.vdr.vdr.label = VDR +thing-type.vdr.vdr.description = VDR - The Video Disk Recorder (https://tvdr.de) +thing-type.vdr.vdr.channel.currentEventBegin.label = Current EPG Event Begin +thing-type.vdr.vdr.channel.currentEventDuration.label = Current EPG Event Duration in Minutes +thing-type.vdr.vdr.channel.currentEventEnd.label = Current EPG Event End +thing-type.vdr.vdr.channel.currentEventSubTitle.label = Current EPG Event Sub Title +thing-type.vdr.vdr.channel.currentEventTitle.label = Current EPG Event Title +thing-type.vdr.vdr.channel.nextEventBegin.label = Next EPG Event Begin +thing-type.vdr.vdr.channel.nextEventDuration.label = Next EPG Event Duration in Minutes +thing-type.vdr.vdr.channel.nextEventEnd.label = Next EPG Event End +thing-type.vdr.vdr.channel.nextEventSubTitle.label = Next EPG Event Sub Title +thing-type.vdr.vdr.channel.nextEventTitle.label = Next EPG Event Title + +# thing types config + +thing-type.config.vdr.vdr.host.label = Hostname +thing-type.config.vdr.vdr.host.description = Hostname or IP Address of VDR instance +thing-type.config.vdr.vdr.port.label = SVDRP Port +thing-type.config.vdr.vdr.port.description = SVDRP Port of VDR instance +thing-type.config.vdr.vdr.refresh.label = Refresh Interval +thing-type.config.vdr.vdr.refresh.description = Interval in seconds the data from VDR instance is refreshed + +# channel types + +channel-type.vdr.vdrChannel.label = Channel Number +channel-type.vdr.vdrChannel.description = Current Channel Number +channel-type.vdr.vdrChannelName.label = Channel Name +channel-type.vdr.vdrChannelName.description = Current Channel Name +channel-type.vdr.vdrDiskUsage.label = Disk Usage +channel-type.vdr.vdrDiskUsage.description = Current Disk Usage in % +channel-type.vdr.vdrEventBegin.label = Event Start Time +channel-type.vdr.vdrEventBegin.description = Start Time of EPG Event +channel-type.vdr.vdrEventDuration.label = Event Duration +channel-type.vdr.vdrEventDuration.description = Duration of EPG Event in Minutes +channel-type.vdr.vdrEventEnd.label = Event End Time +channel-type.vdr.vdrEventEnd.description = End Time of EPG Event +channel-type.vdr.vdrEventSubTitle.label = Event Sub Title +channel-type.vdr.vdrEventSubTitle.description = Sub Title of EPG Event +channel-type.vdr.vdrEventTitle.label = Event Title +channel-type.vdr.vdrEventTitle.description = Title of EPG Event +channel-type.vdr.vdrKeyCode.label = VDR Key Code +channel-type.vdr.vdrKeyCode.description = Send Key Code of Remote Control to VDR +channel-type.vdr.vdrKeyCode.command.option.Up = Up +channel-type.vdr.vdrKeyCode.command.option.Down = Down +channel-type.vdr.vdrKeyCode.command.option.Menu = Menu +channel-type.vdr.vdrKeyCode.command.option.Ok = Ok +channel-type.vdr.vdrKeyCode.command.option.Back = Back +channel-type.vdr.vdrKeyCode.command.option.Left = Left +channel-type.vdr.vdrKeyCode.command.option.Right = Right +channel-type.vdr.vdrKeyCode.command.option.Red = Red +channel-type.vdr.vdrKeyCode.command.option.Green = Green +channel-type.vdr.vdrKeyCode.command.option.Yellow = Yellow +channel-type.vdr.vdrKeyCode.command.option.Blue = Blue +channel-type.vdr.vdrKeyCode.command.option.0 = 0 +channel-type.vdr.vdrKeyCode.command.option.1 = 1 +channel-type.vdr.vdrKeyCode.command.option.2 = 2 +channel-type.vdr.vdrKeyCode.command.option.3 = 3 +channel-type.vdr.vdrKeyCode.command.option.4 = 4 +channel-type.vdr.vdrKeyCode.command.option.5 = 5 +channel-type.vdr.vdrKeyCode.command.option.6 = 6 +channel-type.vdr.vdrKeyCode.command.option.7 = 7 +channel-type.vdr.vdrKeyCode.command.option.8 = 8 +channel-type.vdr.vdrKeyCode.command.option.9 = 9 +channel-type.vdr.vdrKeyCode.command.option.Info = Info +channel-type.vdr.vdrKeyCode.command.option.Play/Pause = Play/Pause +channel-type.vdr.vdrKeyCode.command.option.Play = Play +channel-type.vdr.vdrKeyCode.command.option.Pause = Pause +channel-type.vdr.vdrKeyCode.command.option.Stop = Stop +channel-type.vdr.vdrKeyCode.command.option.Record = Record +channel-type.vdr.vdrKeyCode.command.option.FastFwd = FastFwd +channel-type.vdr.vdrKeyCode.command.option.FastRew = FastRew +channel-type.vdr.vdrKeyCode.command.option.Next = Next +channel-type.vdr.vdrKeyCode.command.option.Prev = Prev +channel-type.vdr.vdrKeyCode.command.option.Power = Power +channel-type.vdr.vdrKeyCode.command.option.Channel+ = Channel+ +channel-type.vdr.vdrKeyCode.command.option.Channel- = Channel- +channel-type.vdr.vdrKeyCode.command.option.PrevChannel = PrevChannel +channel-type.vdr.vdrKeyCode.command.option.Volume+ = Volume+ +channel-type.vdr.vdrKeyCode.command.option.Volume- = Volume- +channel-type.vdr.vdrKeyCode.command.option.Mute = Mute +channel-type.vdr.vdrKeyCode.command.option.Audio = Audio +channel-type.vdr.vdrKeyCode.command.option.Subtitles = Subtitles +channel-type.vdr.vdrKeyCode.command.option.Schedule = Schedule +channel-type.vdr.vdrKeyCode.command.option.Channels = Channels +channel-type.vdr.vdrKeyCode.command.option.Timers = Timers +channel-type.vdr.vdrKeyCode.command.option.Recordings = Recordings +channel-type.vdr.vdrKeyCode.command.option.Setup = Setup +channel-type.vdr.vdrKeyCode.command.option.Commands = Commands +channel-type.vdr.vdrKeyCode.command.option.User0 = User0 +channel-type.vdr.vdrKeyCode.command.option.User1 = User1 +channel-type.vdr.vdrKeyCode.command.option.User2 = User2 +channel-type.vdr.vdrKeyCode.command.option.User3 = User3 +channel-type.vdr.vdrKeyCode.command.option.User4 = User4 +channel-type.vdr.vdrKeyCode.command.option.User5 = User5 +channel-type.vdr.vdrKeyCode.command.option.User6 = User6 +channel-type.vdr.vdrKeyCode.command.option.User7 = User7 +channel-type.vdr.vdrKeyCode.command.option.User8 = User8 +channel-type.vdr.vdrKeyCode.command.option.User9 = User9 +channel-type.vdr.vdrMessage.label = Display Message +channel-type.vdr.vdrMessage.description = Send Message to be displayed on VDR +channel-type.vdr.vdrRecordingActive.label = Recording Active +channel-type.vdr.vdrRecordingActive.description = ON if a recording is active diff --git a/bundles/org.openhab.binding.vektiva/src/main/resources/OH-INF/i18n/vektiva.properties b/bundles/org.openhab.binding.vektiva/src/main/resources/OH-INF/i18n/vektiva.properties new file mode 100644 index 0000000000000..f43ad190b1de5 --- /dev/null +++ b/bundles/org.openhab.binding.vektiva/src/main/resources/OH-INF/i18n/vektiva.properties @@ -0,0 +1,25 @@ +# binding + +binding.vektiva.name = Vektiva Binding +binding.vektiva.description = This is the binding for Vektiva products controlled by local API. + +# thing types + +thing-type.vektiva.smarwi.label = Vektiva Smarwi Thing +thing-type.vektiva.smarwi.description = Smarwi thing for Vektiva Binding + +# thing types config + +thing-type.config.vektiva.smarwi.ip.label = Smarwi IP Address +thing-type.config.vektiva.smarwi.ip.description = IP address of the Smarwi thing on the local network. +thing-type.config.vektiva.smarwi.refreshInterval.label = Refresh Interval +thing-type.config.vektiva.smarwi.refreshInterval.description = The refresh interval to poll Smarwi thing (in s). +thing-type.config.vektiva.smarwi.useWebSockets.label = Use WebSockets Feature for Faster State Update. +thing-type.config.vektiva.smarwi.useWebSockets.description = Enable web sockets technology. FW 203.2.4+ required + +# channel types + +channel-type.vektiva.control.label = Control +channel-type.vektiva.control.description = Control channel for Smarwi thing. +channel-type.vektiva.status.label = Status +channel-type.vektiva.status.description = Status of the Smarwi device (Stopped, Moving, Not ready, Blocked). diff --git a/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties new file mode 100644 index 0000000000000..198396a3a619e --- /dev/null +++ b/bundles/org.openhab.binding.velbus/src/main/resources/OH-INF/i18n/velbus.properties @@ -0,0 +1,545 @@ +# binding + +binding.velbus.name = Velbus Binding +binding.velbus.description = This is the binding for Velbus. + +# thing types + +thing-type.velbus.bridge.label = Velbus Serial Bridge +thing-type.velbus.bridge.description = This bridge represents a Velbus Serial-interface +thing-type.velbus.networkbridge.label = Velbus Network Bridge +thing-type.velbus.networkbridge.description = This bridge represents a Velbus connection over TCP/IP +thing-type.velbus.vmb1bl.label = VMB1BL +thing-type.velbus.vmb1bl.description = 1-channel blind control module for din rail +thing-type.velbus.vmb1bls.label = VMB1BLS +thing-type.velbus.vmb1bls.description = 1-channel blind control module for universal mounting +thing-type.velbus.vmb1dm.label = VMB1DM +thing-type.velbus.vmb1dm.description = Dimmer module for inductive/resistive and capacitive load +thing-type.velbus.vmb1led.label = VMB1LED +thing-type.velbus.vmb1led.description = 1-channel 0-10V controlled PWM dimmer for led strips +thing-type.velbus.vmb1ry.label = VMB1RY +thing-type.velbus.vmb1ry.description = 1-channel relay module +thing-type.velbus.vmb1ryno.label = VMB1RYNO +thing-type.velbus.vmb1ryno.description = 1-channel relay module with potential-free changeover contact +thing-type.velbus.vmb1rynos.label = VMB1RYNOS +thing-type.velbus.vmb1rynos.description = 1-channel relay module with potential-free changeover contact +thing-type.velbus.vmb1rys.label = VMB1RYS +thing-type.velbus.vmb1rys.description = 1-channel relay module with input +thing-type.velbus.vmb1ts.label = VMB1TS +thing-type.velbus.vmb1ts.description = Temperature Sensor Module +thing-type.velbus.vmb2bl.label = VMB2BL +thing-type.velbus.vmb2bl.description = 2-channel blind control module +thing-type.velbus.vmb2ble.label = VMB2BLE +thing-type.velbus.vmb2ble.description = 2-channel blind control module with extended possibilities +thing-type.velbus.vmb2pbn.label = VMB2PBN +thing-type.velbus.vmb2pbn.description = Push-button interface for Niko 1- or 2-fold push-buttons +thing-type.velbus.vmb4an.label = VMB4AN +thing-type.velbus.vmb4an.description = Analog I/O module +thing-type.velbus.vmb4dc.label = VMB4DC +thing-type.velbus.vmb4dc.description = 4-channel 0/1-10V dimmer controller +thing-type.velbus.vmb4ry.label = VMB4RY +thing-type.velbus.vmb4ry.description = 4-channel relay module +thing-type.velbus.vmb4ryld.label = VMB4RYLD +thing-type.velbus.vmb4ryld.description = 4-channel relay module with voltage outputs +thing-type.velbus.vmb4ryno.label = VMB4RYNO +thing-type.velbus.vmb4ryno.description = 4-channel relay module with potential-free contacts +thing-type.velbus.vmb6in.label = VMB6IN +thing-type.velbus.vmb6in.description = 6-channel input module +thing-type.velbus.vmb6pbn.label = VMB6PBN +thing-type.velbus.vmb6pbn.description = Push-button interface module for Niko 4- or 6-fold push-button +thing-type.velbus.vmb7in.label = VMB7IN +thing-type.velbus.vmb7in.description = 7-channel input module (potentialfree + pulse) +thing-type.velbus.vmb8ir.label = VMB8IR +thing-type.velbus.vmb8ir.description = Infrared remote control receiver module +thing-type.velbus.vmb8pb.label = VMB8PB +thing-type.velbus.vmb8pb.description = 8-Channel Push Button module +thing-type.velbus.vmb8pbu.label = VMB8PBU +thing-type.velbus.vmb8pbu.description = Push-button interface with 8 channels for universal mounting +thing-type.velbus.vmbdme.label = VMBDME +thing-type.velbus.vmbdme.description = Dimmer for electronic/resistive load +thing-type.velbus.vmbdmi.label = VMBDMI +thing-type.velbus.vmbdmi.description = Single channel triac dimmer for resistive and inductive loads +thing-type.velbus.vmbdmir.label = VMBDMI-R +thing-type.velbus.vmbdmir.description = Single channel triac dimmer for resistive and inductive loads +thing-type.velbus.vmbel1.label = VMBEL1 +thing-type.velbus.vmbel1.description = Edge-lit one touch button module +thing-type.velbus.vmbel2.label = VMBEL2 +thing-type.velbus.vmbel2.description = Edge-lit two touch buttons module +thing-type.velbus.vmbel4.label = VMBEL4 +thing-type.velbus.vmbel4.description = Edge-lit four touch buttons module +thing-type.velbus.vmbelo.label = VMBELO +thing-type.velbus.vmbelo.description = Edge-lit touch panel with Oled display +thing-type.velbus.vmbgp1-2.label = VMBGP1-2 +thing-type.velbus.vmbgp1-2.description = Glass control module with 1 touch key (Edition 2) +thing-type.velbus.vmbgp1.label = VMBGP1 +thing-type.velbus.vmbgp1.description = Glass control module with 1 touch key +thing-type.velbus.vmbgp2-2.label = VMBGP2-2 +thing-type.velbus.vmbgp2-2.description = Glass control module with 2 touch keys (Edition 2) +thing-type.velbus.vmbgp2.label = VMBGP2 +thing-type.velbus.vmbgp2.description = Glass control module with 2 touch keys +thing-type.velbus.vmbgp4-2.label = VMBGP4-2 +thing-type.velbus.vmbgp4-2.description = Glass control module with 4 touch keys (Edition 2) +thing-type.velbus.vmbgp4.label = VMBGP4 +thing-type.velbus.vmbgp4.description = Glass control module with 4 touch keys +thing-type.velbus.vmbgp4pir-2.label = VMBGP4PIR-2 +thing-type.velbus.vmbgp4pir-2.description = Glass control module with 4 touch keys and built-in motion and twilight sensor (Edition 2) +thing-type.velbus.vmbgp4pir.label = VMBGP4PIR +thing-type.velbus.vmbgp4pir.description = Glass control module with 4 touch keys and built-in motion and twilight sensor +thing-type.velbus.vmbgpo.label = VMBGPO +thing-type.velbus.vmbgpo.description = Glass control module with oled display +thing-type.velbus.vmbgpod-2.label = VMBGPOD-2 +thing-type.velbus.vmbgpod-2.description = Glass control module with oled display and temperature controller (Edition 2) +thing-type.velbus.vmbgpod.label = VMBGPOD +thing-type.velbus.vmbgpod.description = Glass control module with oled display and temperature controller +thing-type.velbus.vmbmeteo.label = VMBMETEO +thing-type.velbus.vmbmeteo.description = Weather station with thermometer, anemometer, rain sensor and light sensor +thing-type.velbus.vmbpirc.label = VMBPIRC +thing-type.velbus.vmbpirc.description = Motion and twilight sensor for ceiling mounting +thing-type.velbus.vmbpirm.label = VMBPIRM +thing-type.velbus.vmbpirm.description = Mini motion and twilight sensor for recessed or surface mounting +thing-type.velbus.vmbpiro.label = VMBPIRO +thing-type.velbus.vmbpiro.description = Outdoor motion, twilight and temperature sensor, Theben +thing-type.velbus.vmbrfr8s.label = VMBRFR8S +thing-type.velbus.vmbrfr8s.description = 8 channel RF receiver module +thing-type.velbus.vmbvp1.label = VMPVP1 +thing-type.velbus.vmbvp1.description = Doorbird interface module + +# thing types config + +bridge-type.config.velbus.bridge.port.label = Serial Port +bridge-type.config.velbus.bridge.port.description = Select serial port (COM1, /dev/ttyS0, ...) +bridge-type.config.velbus.bridge.reconnectionInterval.label = Reconnection Interval +bridge-type.config.velbus.bridge.reconnectionInterval.description = The interval (in seconds) at which reconnections should be reattempted in case of a communication problem, default 15. If set to 0 or left empty, no reconnections will be attempted. +bridge-type.config.velbus.bridge.timeUpdateInterval.label = Time Update Interval +bridge-type.config.velbus.bridge.timeUpdateInterval.description = The interval (in minutes) at which the realtime clock, date and daylight savings status of the modules will be updated, default 360. If set to 0 or left empty, no refresh will be scheduled. +bridge-type.config.velbus.networkbridge.address.label = IP Address or Hostname +bridge-type.config.velbus.networkbridge.address.description = IP Address or hostname of Velbus server +bridge-type.config.velbus.networkbridge.port.label = Port +bridge-type.config.velbus.networkbridge.port.description = Network port to communicate with Velbus server +bridge-type.config.velbus.networkbridge.reconnectionInterval.label = Reconnection Interval +bridge-type.config.velbus.networkbridge.reconnectionInterval.description = The interval (in seconds) at which reconnections should be reattempted in case of a communication problem, default 15. If set to 0 or left empty, no reconnections will be attempted. +bridge-type.config.velbus.networkbridge.timeUpdateInterval.label = Time Update Interval +bridge-type.config.velbus.networkbridge.timeUpdateInterval.description = The interval (in minutes) at which the realtime clock, date and daylight savings status of the modules will be updated, default 360. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.13channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.13channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.13channelDevice.CH10.label = CH10 Name +thing-type.config.velbus.13channelDevice.CH10.description = The name of CH10. +thing-type.config.velbus.13channelDevice.CH11.label = CH11 Name +thing-type.config.velbus.13channelDevice.CH11.description = The name of CH11. +thing-type.config.velbus.13channelDevice.CH12.label = CH12 Name +thing-type.config.velbus.13channelDevice.CH12.description = The name of CH12. +thing-type.config.velbus.13channelDevice.CH13.label = CH13 Name +thing-type.config.velbus.13channelDevice.CH13.description = The name of CH13. +thing-type.config.velbus.13channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.13channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.13channelDevice.CH3.label = CH3 Name +thing-type.config.velbus.13channelDevice.CH3.description = The name of CH3. +thing-type.config.velbus.13channelDevice.CH4.label = CH4 Name +thing-type.config.velbus.13channelDevice.CH4.description = The name of CH4. +thing-type.config.velbus.13channelDevice.CH5.label = CH5 Name +thing-type.config.velbus.13channelDevice.CH5.description = The name of CH5. +thing-type.config.velbus.13channelDevice.CH6.label = CH6 Name +thing-type.config.velbus.13channelDevice.CH6.description = The name of CH6. +thing-type.config.velbus.13channelDevice.CH7.label = CH7 Name +thing-type.config.velbus.13channelDevice.CH7.description = The name of CH7. +thing-type.config.velbus.13channelDevice.CH8.label = CH8 Name +thing-type.config.velbus.13channelDevice.CH8.description = The name of CH8. +thing-type.config.velbus.13channelDevice.CH9.label = CH9 Name +thing-type.config.velbus.13channelDevice.CH9.description = The name of CH9. +thing-type.config.velbus.13channelDevice.address.label = Address +thing-type.config.velbus.13channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.13channelDevice.refresh.label = Refresh Interval +thing-type.config.velbus.13channelDevice.refresh.description = Refresh interval for the sensors (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.1channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.1channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.1channelDevice.address.label = Address +thing-type.config.velbus.1channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.1channelDeviceWithDimspeed.CH1.label = CH1 Name +thing-type.config.velbus.1channelDeviceWithDimspeed.CH1.description = The name of CH1. +thing-type.config.velbus.1channelDeviceWithDimspeed.address.label = Address +thing-type.config.velbus.1channelDeviceWithDimspeed.address.description = The velbus address of the device +thing-type.config.velbus.1channelDeviceWithDimspeed.dimspeed.label = Dimspeed +thing-type.config.velbus.1channelDeviceWithDimspeed.dimspeed.description = The time (in seconds) needed for dimming from 0 to 100%. +thing-type.config.velbus.2channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.2channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.2channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.2channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.2channelDevice.address.label = Address +thing-type.config.velbus.2channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH1.label = CH1 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH1.description = The name of CH1. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH10.label = CH10 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH10.description = The name of CH10. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH11.label = CH11 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH11.description = The name of CH11. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH12.label = CH12 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH12.description = The name of CH12. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH13.label = CH13 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH13.description = The name of CH13. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH14.label = CH14 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH14.description = The name of CH14. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH15.label = CH15 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH15.description = The name of CH15. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH16.label = CH16 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH16.description = The name of CH16. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH17.label = CH17 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH17.description = The name of CH17. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH18.label = CH18 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH18.description = The name of CH18. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH19.label = CH19 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH19.description = The name of CH19. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH2.label = CH2 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH2.description = The name of CH2. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH20.label = CH20 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH20.description = The name of CH20. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH21.label = CH21 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH21.description = The name of CH21. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH22.label = CH22 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH22.description = The name of CH22. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH23.label = CH23 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH23.description = The name of CH23. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH24.label = CH24 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH24.description = The name of CH24. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH25.label = CH25 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH25.description = The name of CH25. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH26.label = CH26 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH26.description = The name of CH26. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH27.label = CH27 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH27.description = The name of CH27. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH28.label = CH28 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH28.description = The name of CH28. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH29.label = CH29 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH29.description = The name of CH29. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH3.label = CH3 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH3.description = The name of CH3. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH30.label = CH30 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH30.description = The name of CH30. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH31.label = CH31 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH31.description = The name of CH31. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH32.label = CH32 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH32.description = The name of CH32. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH33.label = CH33 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH33.description = The name of CH33 (temperature sensor channel). +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH4.label = CH4 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH4.description = The name of CH4. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH5.label = CH5 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH5.description = The name of CH5. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH6.label = CH6 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH6.description = The name of CH6. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH7.label = CH7 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH7.description = The name of CH7. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH8.label = CH8 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH8.description = The name of CH8. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH9.label = CH9 Name +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.CH9.description = The name of CH9. +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.address.label = Address +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.address.description = The velbus address of the device +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.refresh.label = Refresh Interval +thing-type.config.velbus.33channelDeviceWithTemperatureSensor.refresh.description = Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.4channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.4channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.4channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.4channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.4channelDevice.CH3.label = CH3 Name +thing-type.config.velbus.4channelDevice.CH3.description = The name of CH3. +thing-type.config.velbus.4channelDevice.CH4.label = CH4 Name +thing-type.config.velbus.4channelDevice.CH4.description = The name of CH4. +thing-type.config.velbus.4channelDevice.address.label = Address +thing-type.config.velbus.4channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.4channelDeviceWithDimspeed.CH1.label = CH1 Name +thing-type.config.velbus.4channelDeviceWithDimspeed.CH1.description = The name of CH1. +thing-type.config.velbus.4channelDeviceWithDimspeed.CH2.label = CH2 Name +thing-type.config.velbus.4channelDeviceWithDimspeed.CH2.description = The name of CH2. +thing-type.config.velbus.4channelDeviceWithDimspeed.CH3.label = CH3 Name +thing-type.config.velbus.4channelDeviceWithDimspeed.CH3.description = The name of CH3. +thing-type.config.velbus.4channelDeviceWithDimspeed.CH4.label = CH4 Name +thing-type.config.velbus.4channelDeviceWithDimspeed.CH4.description = The name of CH4. +thing-type.config.velbus.4channelDeviceWithDimspeed.address.label = Address +thing-type.config.velbus.4channelDeviceWithDimspeed.address.description = The velbus address of the device +thing-type.config.velbus.4channelDeviceWithDimspeed.dimspeed.label = Dimspeed +thing-type.config.velbus.4channelDeviceWithDimspeed.dimspeed.description = The time (in seconds) needed for dimming from 0 to 100%. +thing-type.config.velbus.5channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.5channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.5channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.5channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.5channelDevice.CH3.label = CH3 Name +thing-type.config.velbus.5channelDevice.CH3.description = The name of CH3. +thing-type.config.velbus.5channelDevice.CH4.label = CH4 Name +thing-type.config.velbus.5channelDevice.CH4.description = The name of CH4. +thing-type.config.velbus.5channelDevice.CH5.label = CH5 Name +thing-type.config.velbus.5channelDevice.CH5.description = The name of CH5. +thing-type.config.velbus.5channelDevice.address.label = Address +thing-type.config.velbus.5channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.6channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.6channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.6channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.6channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.6channelDevice.CH3.label = CH3 Name +thing-type.config.velbus.6channelDevice.CH3.description = The name of CH3. +thing-type.config.velbus.6channelDevice.CH4.label = CH4 Name +thing-type.config.velbus.6channelDevice.CH4.description = The name of CH4. +thing-type.config.velbus.6channelDevice.CH5.label = CH5 Name +thing-type.config.velbus.6channelDevice.CH5.description = The name of CH5. +thing-type.config.velbus.6channelDevice.CH6.label = CH6 Name +thing-type.config.velbus.6channelDevice.CH6.description = The name of CH6. +thing-type.config.velbus.6channelDevice.address.label = Address +thing-type.config.velbus.6channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.7channelDeviceWithCounters.CH1.label = CH1 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH1.description = The name of CH1. +thing-type.config.velbus.7channelDeviceWithCounters.CH2.label = CH2 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH2.description = The name of CH2. +thing-type.config.velbus.7channelDeviceWithCounters.CH3.label = CH3 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH3.description = The name of CH3. +thing-type.config.velbus.7channelDeviceWithCounters.CH4.label = CH4 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH4.description = The name of CH4. +thing-type.config.velbus.7channelDeviceWithCounters.CH5.label = CH5 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH5.description = The name of CH5. +thing-type.config.velbus.7channelDeviceWithCounters.CH6.label = CH6 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH6.description = The name of CH6. +thing-type.config.velbus.7channelDeviceWithCounters.CH7.label = CH7 Name +thing-type.config.velbus.7channelDeviceWithCounters.CH7.description = The name of CH7. +thing-type.config.velbus.7channelDeviceWithCounters.address.label = Address +thing-type.config.velbus.7channelDeviceWithCounters.address.description = The velbus address of the device +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.label = Counter 1 Pulse Multiplier +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.description = The pulse multiplier for counter 1 +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.option.1 = x1 +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.option.2.5 = x2.5 +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.option.0.05 = x0.05 +thing-type.config.velbus.7channelDeviceWithCounters.counter1PulseMultiplier.option.0.01 = x0.01 +thing-type.config.velbus.7channelDeviceWithCounters.counter1Unit.label = Counter 1 Unit +thing-type.config.velbus.7channelDeviceWithCounters.counter1Unit.description = The unit for Counter 1. +thing-type.config.velbus.7channelDeviceWithCounters.counter1Unit.option.kWh = kWh +thing-type.config.velbus.7channelDeviceWithCounters.counter1Unit.option.liters = liters +thing-type.config.velbus.7channelDeviceWithCounters.counter1Unit.option.m³ = m³ +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.label = Counter 2 Pulse Multiplier +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.description = The pulse multiplier for counter 2 +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.option.1 = x1 +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.option.2.5 = x2.5 +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.option.0.05 = x0.05 +thing-type.config.velbus.7channelDeviceWithCounters.counter2PulseMultiplier.option.0.01 = x0.01 +thing-type.config.velbus.7channelDeviceWithCounters.counter2Unit.label = Counter 2 Unit +thing-type.config.velbus.7channelDeviceWithCounters.counter2Unit.description = The unit for Counter 2. +thing-type.config.velbus.7channelDeviceWithCounters.counter2Unit.option.kWh = kWh +thing-type.config.velbus.7channelDeviceWithCounters.counter2Unit.option.liters = liters +thing-type.config.velbus.7channelDeviceWithCounters.counter2Unit.option.m³ = m³ +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.label = Counter 3 Pulse Multiplier +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.description = The pulse multiplier for counter 3 +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.option.1 = x1 +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.option.2.5 = x2.5 +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.option.0.05 = x0.05 +thing-type.config.velbus.7channelDeviceWithCounters.counter3PulseMultiplier.option.0.01 = x0.01 +thing-type.config.velbus.7channelDeviceWithCounters.counter3Unit.label = Counter 3 Unit +thing-type.config.velbus.7channelDeviceWithCounters.counter3Unit.description = The unit for Counter 3. +thing-type.config.velbus.7channelDeviceWithCounters.counter3Unit.option.kWh = kWh +thing-type.config.velbus.7channelDeviceWithCounters.counter3Unit.option.liters = liters +thing-type.config.velbus.7channelDeviceWithCounters.counter3Unit.option.m³ = m³ +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.label = Counter 4 Pulse Multiplier +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.description = The pulse multiplier for counter 4 +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.option.1 = x1 +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.option.2.5 = x2.5 +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.option.0.05 = x0.05 +thing-type.config.velbus.7channelDeviceWithCounters.counter4PulseMultiplier.option.0.01 = x0.01 +thing-type.config.velbus.7channelDeviceWithCounters.counter4Unit.label = Counter 4 Unit +thing-type.config.velbus.7channelDeviceWithCounters.counter4Unit.description = The unit for Counter 4. +thing-type.config.velbus.7channelDeviceWithCounters.counter4Unit.option.kWh = kWh +thing-type.config.velbus.7channelDeviceWithCounters.counter4Unit.option.liters = liters +thing-type.config.velbus.7channelDeviceWithCounters.counter4Unit.option.m³ = m³ +thing-type.config.velbus.7channelDeviceWithCounters.refresh.label = Refresh Interval +thing-type.config.velbus.7channelDeviceWithCounters.refresh.description = Refresh interval for the counters (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH1.label = CH1 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH1.description = The name of CH1. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH2.label = CH2 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH2.description = The name of CH2. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH3.label = CH3 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH3.description = The name of CH3. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH4.label = CH4 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH4.description = The name of CH4. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH5.label = CH5 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH5.description = The name of CH5. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH6.label = CH6 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH6.description = The name of CH6. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH7.label = CH7 Name +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.CH7.description = The name of CH7. +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.address.label = Address +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.address.description = The velbus address of the device +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.refresh.label = Refresh Interval +thing-type.config.velbus.7channelDeviceWithTemperatureSensor.refresh.description = Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.8channelDevice.CH1.label = CH1 Name +thing-type.config.velbus.8channelDevice.CH1.description = The name of CH1. +thing-type.config.velbus.8channelDevice.CH2.label = CH2 Name +thing-type.config.velbus.8channelDevice.CH2.description = The name of CH2. +thing-type.config.velbus.8channelDevice.CH3.label = CH3 Name +thing-type.config.velbus.8channelDevice.CH3.description = The name of CH3. +thing-type.config.velbus.8channelDevice.CH4.label = CH4 Name +thing-type.config.velbus.8channelDevice.CH4.description = The name of CH4. +thing-type.config.velbus.8channelDevice.CH5.label = CH5 Name +thing-type.config.velbus.8channelDevice.CH5.description = The name of CH5. +thing-type.config.velbus.8channelDevice.CH6.label = CH6 Name +thing-type.config.velbus.8channelDevice.CH6.description = The name of CH6. +thing-type.config.velbus.8channelDevice.CH7.label = CH7 Name +thing-type.config.velbus.8channelDevice.CH7.description = The name of CH7. +thing-type.config.velbus.8channelDevice.CH8.label = CH8 Name +thing-type.config.velbus.8channelDevice.CH8.description = The name of CH8. +thing-type.config.velbus.8channelDevice.address.label = Address +thing-type.config.velbus.8channelDevice.address.description = The velbus address of the device +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH1.label = CH1 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH1.description = The name of CH1. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH2.label = CH2 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH2.description = The name of CH2. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH3.label = CH3 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH3.description = The name of CH3. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH4.label = CH4 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH4.description = The name of CH4. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH5.label = CH5 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH5.description = The name of CH5. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH6.label = CH6 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH6.description = The name of CH6. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH7.label = CH7 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH7.description = The name of CH7. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH8.label = CH8 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH8.description = The name of CH8. +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH9.label = CH9 Name +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.CH9.description = The name of CH9 (temperature sensor channel). +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.address.label = Address +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.address.description = The velbus address of the device +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.refresh.label = Refresh Interval +thing-type.config.velbus.9channelDeviceWithTemperatureSensor.refresh.description = Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. +thing-type.config.velbus.temperatureSensorDevice.address.label = Address +thing-type.config.velbus.temperatureSensorDevice.address.description = The velbus address of the device +thing-type.config.velbus.temperatureSensorDevice.refresh.label = Refresh Interval +thing-type.config.velbus.temperatureSensorDevice.refresh.description = Refresh interval for the temperature sensor (in seconds), default 300. If set to 0 or left empty, no refresh will be scheduled. + +# channel group types + +channel-group-type.velbus.1channelFeedbackModule.label = Feedback +channel-group-type.velbus.1channelFeedbackModule.description = This is a generic module with 1 feedback channel. +channel-group-type.velbus.1channelInputModuleWithTemperatureSensor.label = Input with Temperature Sensor +channel-group-type.velbus.1channelInputModuleWithTemperatureSensor.description = This is a generic module with 8 input channels and a temperature sensor. +channel-group-type.velbus.2channelFeedbackModule.label = Feedback +channel-group-type.velbus.2channelFeedbackModule.description = This is a generic module with 2 feedback channels. +channel-group-type.velbus.32channelButtonModule.label = Button +channel-group-type.velbus.32channelButtonModule.description = This is a generic module with 32 button channels. +channel-group-type.velbus.32channelFeedbackModule.label = Feedback +channel-group-type.velbus.32channelFeedbackModule.description = This is a generic module with 32 feedback channels. +channel-group-type.velbus.33channelInputModuleWithTemperatureSensor.label = Input with Temperature Sensor +channel-group-type.velbus.33channelInputModuleWithTemperatureSensor.description = This is a generic module with 32 input channels and a temperature sensor. +channel-group-type.velbus.4channelAnalogInputModule.label = Analog Input +channel-group-type.velbus.4channelAnalogInputModule.description = This is a generic analog module with 4 input channels. +channel-group-type.velbus.4channelAnalogOutputModule.label = Analog Input +channel-group-type.velbus.4channelAnalogOutputModule.description = This is a generic analog module with 4 output channels. +channel-group-type.velbus.4channelCounterModule.label = Counters +channel-group-type.velbus.4channelCounterModule.description = This is a generic module with 4 counter channels. +channel-group-type.velbus.4channelFeedbackModule.label = Feedback +channel-group-type.velbus.4channelFeedbackModule.description = This is a generic module with 4 feedback channels. +channel-group-type.velbus.6channelButtonModule.label = Button +channel-group-type.velbus.6channelButtonModule.description = This is a generic module with 6 button channels. +channel-group-type.velbus.6channelFeedbackModule.label = Feedback +channel-group-type.velbus.6channelFeedbackModule.description = This is a generic module with 6 feedback channels. +channel-group-type.velbus.6channelInputModule.label = Input +channel-group-type.velbus.6channelInputModule.description = This is a generic module with 6 input channels. +channel-group-type.velbus.7channelInputModule.label = Input +channel-group-type.velbus.7channelInputModule.description = This is a generic module with 7 input channels. +channel-group-type.velbus.8channelButtonModule.label = Button +channel-group-type.velbus.8channelButtonModule.description = This is a generic module with 8 button channels. +channel-group-type.velbus.8channelFeedbackModule.label = Feedback +channel-group-type.velbus.8channelFeedbackModule.description = This is a generic module with 8 feedback channels. +channel-group-type.velbus.8channelInputModule.label = Input +channel-group-type.velbus.8channelInputModule.description = This is a generic module with 8 input channels. +channel-group-type.velbus.9channelInputModuleWithTemperatureAndLightSensor.label = Input with Temperature/Light Sensor +channel-group-type.velbus.9channelInputModuleWithTemperatureAndLightSensor.description = This is a generic module with 8 input channels, a temperature sensor and a light sensor. +channel-group-type.velbus.9channelInputModuleWithTemperatureSensor.label = Input with Temperature Sensor +channel-group-type.velbus.9channelInputModuleWithTemperatureSensor.description = This is a generic module with 8 input channels and a temperature sensor. +channel-group-type.velbus.clockAlarm.label = Clock Alarm +channel-group-type.velbus.clockAlarm.description = This is a clock alarm with two configurable alarms that can be programmed with a wake up time and a bed time. +channel-group-type.velbus.clockAlarm.channel.clockAlarm1BedtimeHour.label = Clock Alarm 1 Bedtime Hour +channel-group-type.velbus.clockAlarm.channel.clockAlarm1BedtimeMinute.label = Clock Alarm 1 Bedtime Minute +channel-group-type.velbus.clockAlarm.channel.clockAlarm1Enabled.label = Clock Alarm 1 Enabled +channel-group-type.velbus.clockAlarm.channel.clockAlarm1Type.label = Clock Alarm 1 Type +channel-group-type.velbus.clockAlarm.channel.clockAlarm1WakeupHour.label = Clock Alarm 1 Wakeup Hour +channel-group-type.velbus.clockAlarm.channel.clockAlarm1WakeupMinute.label = Clock Alarm 1 Wakeup Minute +channel-group-type.velbus.clockAlarm.channel.clockAlarm2BedtimeHour.label = Clock Alarm 2 Bedtime Hour +channel-group-type.velbus.clockAlarm.channel.clockAlarm2BedtimeMinute.label = Clock Alarm 2 Bedtime Minute +channel-group-type.velbus.clockAlarm.channel.clockAlarm2Enabled.label = Clock Alarm 2 Enabled +channel-group-type.velbus.clockAlarm.channel.clockAlarm2Type.label = Clock Alarm 2 Type +channel-group-type.velbus.clockAlarm.channel.clockAlarm2WakeupHour.label = Clock Alarm 2 Wakeup Hour +channel-group-type.velbus.clockAlarm.channel.clockAlarm2WakeupMinute.label = Clock Alarm 2 Wakeup Minute +channel-group-type.velbus.oledDisplay.label = O-LED Display +channel-group-type.velbus.oledDisplay.channel.MEMO.label = Memo +channel-group-type.velbus.oledDisplay.channel.SCREENSAVER.label = Screensaver +channel-group-type.velbus.thermostat.label = Thermostat +channel-group-type.velbus.thermostat.description = This is a thermostat that supports heating/cooling and comfort/day/night/safe modes. +channel-group-type.velbus.thermostat.channel.alarm1.label = Alarm 1 +channel-group-type.velbus.thermostat.channel.alarm2.label = Alarm 2 +channel-group-type.velbus.thermostat.channel.alarm3.label = Alarm 3 +channel-group-type.velbus.thermostat.channel.alarm4.label = Alarm 4 +channel-group-type.velbus.thermostat.channel.boost.label = Boost +channel-group-type.velbus.thermostat.channel.cooler.label = Cooler +channel-group-type.velbus.thermostat.channel.coolingModeComfortTemperatureSetpoint.label = Cooling Mode Comfort Temperature Setpoint +channel-group-type.velbus.thermostat.channel.coolingModeDayTemperatureSetpoint.label = Cooling Mode Day Temperature Setpoint +channel-group-type.velbus.thermostat.channel.coolingModeNightTemperatureSetpoint.label = Cooling Mode Night Temperature Setpoint +channel-group-type.velbus.thermostat.channel.coolingModeSafeTemperatureSetpoint.label = Cooling Mode Safe Temperature Setpoint +channel-group-type.velbus.thermostat.channel.currentTemperatureSetpoint.label = Current Temperature Setpoint +channel-group-type.velbus.thermostat.channel.heater.label = Heater +channel-group-type.velbus.thermostat.channel.heatingModeAntiFrostTemperatureSetpoint.label = Heating Mode Antifrost Temperature Setpoint +channel-group-type.velbus.thermostat.channel.heatingModeComfortTemperatureSetpoint.label = Heating Mode Comfort Temperature Setpoint +channel-group-type.velbus.thermostat.channel.heatingModeDayTemperatureSetpoint.label = Heating Mode Day Temperature Setpoint +channel-group-type.velbus.thermostat.channel.heatingModeNightTemperatureSetpoint.label = Heating Mode Night Temperature Setpoint +channel-group-type.velbus.thermostat.channel.pump.label = Pump +channel-group-type.velbus.weatherStation.label = Weather Station +channel-group-type.velbus.weatherStation.description = This is a weather station with channels for temperature, rainfall, illuminance and windspeed. + +# channel types + +channel-type.velbus.alarmType.label = Alarm Type +channel-type.velbus.alarmType.description = Type (local/global) of the alarm clock in Velbus +channel-type.velbus.alarmType.state.option.LOCAL = Local +channel-type.velbus.alarmType.state.option.GLOBAL = Global +channel-type.velbus.brightness.label = Brightness +channel-type.velbus.brightness.description = Brightness control for dimmer action in Velbus +channel-type.velbus.button-channel.label = Button Channel +channel-type.velbus.button-channel.command.option.PRESSED = pressed +channel-type.velbus.button-channel.command.option.LONG_PRESSED = long pressed +channel-type.velbus.counter.label = Counter +channel-type.velbus.current.label = Current +channel-type.velbus.current.description = Currently measured current +channel-type.velbus.heatingMode.label = Mode +channel-type.velbus.heatingMode.description = Mode (comfort/day/night/safe) for the thermostat in Velbus +channel-type.velbus.heatingMode.state.option.COMFORT = Comfort +channel-type.velbus.heatingMode.state.option.DAY = Day +channel-type.velbus.heatingMode.state.option.NIGHT = Night +channel-type.velbus.heatingMode.state.option.SAFE = Safe +channel-type.velbus.heatingOperatingMode.label = Operating Mode +channel-type.velbus.heatingOperatingMode.description = Operating mode (heating/cooling) for the thermostat in Velbus +channel-type.velbus.heatingOperatingMode.state.option.HEATING = Heating +channel-type.velbus.heatingOperatingMode.state.option.COOLING = Cooling +channel-type.velbus.hour.label = Hour +channel-type.velbus.illuminance.label = Illuminance +channel-type.velbus.illuminance.description = Currently measured illuminance +channel-type.velbus.ledFeedback.label = Feedback LED +channel-type.velbus.ledFeedback.description = Feedback LED for the push button in Velbus +channel-type.velbus.ledFeedback.state.option.CLEAR_LED = Off +channel-type.velbus.ledFeedback.state.option.SET_LED = On +channel-type.velbus.ledFeedback.state.option.SLOW_BLINK_LED = Slow blink +channel-type.velbus.ledFeedback.state.option.FAST_BLINK_LED = Fast blink +channel-type.velbus.ledFeedback.state.option.VERY_FAST_BLINK_LED = Very fast blink +channel-type.velbus.minute.label = Minute +channel-type.velbus.percentage.label = Percentage +channel-type.velbus.percentage.description = Current percentage +channel-type.velbus.rainfall.label = Rainfall +channel-type.velbus.rainfall.description = Currently measured quantity of rain +channel-type.velbus.resistance.label = Resistance +channel-type.velbus.resistance.description = Currently measured resistance +channel-type.velbus.rollershutter.label = Rollershutter +channel-type.velbus.rollershutter.description = Rollershutter control for rollershutter action in Velbus +channel-type.velbus.switch.label = Switch +channel-type.velbus.switch.description = Switch control for action in Velbus +channel-type.velbus.temperature.label = Temperature +channel-type.velbus.temperature.description = Current temperature +channel-type.velbus.temperatureSetpoint.label = Temperature Setpoint +channel-type.velbus.text.label = Text +channel-type.velbus.thermostat-trigger-channel.label = Thermostat Trigger Channel +channel-type.velbus.trigger-channel.label = Trigger Channel +channel-type.velbus.voltage.label = Voltage +channel-type.velbus.voltage.description = Currently measured voltage +channel-type.velbus.windspeed.label = Wind Speed +channel-type.velbus.windspeed.description = Currently measured wind speed diff --git a/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/i18n/venstarthermostat.properties b/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/i18n/venstarthermostat.properties new file mode 100644 index 0000000000000..e4bd2256dfa32 --- /dev/null +++ b/bundles/org.openhab.binding.venstarthermostat/src/main/resources/OH-INF/i18n/venstarthermostat.properties @@ -0,0 +1,96 @@ +# binding + +binding.venstarthermostat.name = Venstar Thermostats +binding.venstarthermostat.description = This is a binding for Venstar Thermostats. + +# thing types + +thing-type.venstarthermostat.colorTouchThermostat.label = ColorTouch Thermostat +thing-type.venstarthermostat.colorTouchThermostat.description = Venstar ColorTouch Thermostat + +# thing types config + +thing-type.config.venstarthermostat.colorTouchThermostat.password.label = Password +thing-type.config.venstarthermostat.colorTouchThermostat.refresh.label = Refresh interval +thing-type.config.venstarthermostat.colorTouchThermostat.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.venstarthermostat.colorTouchThermostat.url.label = URL +thing-type.config.venstarthermostat.colorTouchThermostat.url.description = URL of the thermostat in the format 'proto://host' (example: https://192.168.1.100) +thing-type.config.venstarthermostat.colorTouchThermostat.username.label = Username + +# channel types + +channel-type.venstarthermostat.aux1Runtime.label = Aux1 Runtime Minutes +channel-type.venstarthermostat.aux1Runtime.description = Run time in aux1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.aux2Runtime.label = Aux2 Runtime Minutes +channel-type.venstarthermostat.aux2Runtime.description = Run time in aux2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.awayMode.label = Away Mode +channel-type.venstarthermostat.awayMode.description = Current Away Mode +channel-type.venstarthermostat.awayMode.state.option.home = Home +channel-type.venstarthermostat.awayMode.state.option.away = Away +channel-type.venstarthermostat.awayModeRaw.label = Away Mode (Raw) +channel-type.venstarthermostat.awayModeRaw.description = Current Away Mode, as an integer number +channel-type.venstarthermostat.cool1Runtime.label = Cool1 Runtime Minutes +channel-type.venstarthermostat.cool1Runtime.description = Run time in cool1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.cool2Runtime.label = Cool2 Runtime Minutes +channel-type.venstarthermostat.cool2Runtime.description = Run time in cool2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.coolingSetpoint.label = Cooling Setpoint +channel-type.venstarthermostat.coolingSetpoint.description = Cooling Setpoint +channel-type.venstarthermostat.fanMode.label = Fan Mode +channel-type.venstarthermostat.fanMode.description = Current Fan Mode +channel-type.venstarthermostat.fanMode.state.option.auto = Auto +channel-type.venstarthermostat.fanMode.state.option.on = On +channel-type.venstarthermostat.fanModeRaw.label = Fan Mode (Raw) +channel-type.venstarthermostat.fanModeRaw.description = Current Fan Mode, as an integer number +channel-type.venstarthermostat.fanState.label = Fan State +channel-type.venstarthermostat.fanState.description = Current Fan State +channel-type.venstarthermostat.fanStateRaw.label = Fan State (Raw) +channel-type.venstarthermostat.fanStateRaw.description = Current Fan State, as an integer number +channel-type.venstarthermostat.freeCoolRuntime.label = Free Cool Runtime Minutes +channel-type.venstarthermostat.freeCoolRuntime.description = Run time in Free Cool mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.heat1Runtime.label = Heat1 Runtime Minutes +channel-type.venstarthermostat.heat1Runtime.description = Run time in heat1 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.heat2Runtime.label = Heat2 Runtime Minutes +channel-type.venstarthermostat.heat2Runtime.description = Run time in heat2 mode in minutes (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.heatingSetpoint.label = Heating Setpoint +channel-type.venstarthermostat.heatingSetpoint.description = Heating Setpoint +channel-type.venstarthermostat.humidity.label = Humidity +channel-type.venstarthermostat.humidity.description = Indoor Humidity +channel-type.venstarthermostat.outdoorTemperature.label = Outdoor Temperature +channel-type.venstarthermostat.outdoorTemperature.description = Outdoor Temperature +channel-type.venstarthermostat.scheduleMode.label = Schedule Mode +channel-type.venstarthermostat.scheduleMode.description = Current Schedule Mode +channel-type.venstarthermostat.scheduleMode.state.option.disabled = Disabled +channel-type.venstarthermostat.scheduleMode.state.option.enabled = Enabled +channel-type.venstarthermostat.scheduleModeRaw.label = Schedule Mode (Raw) +channel-type.venstarthermostat.scheduleModeRaw.description = Current Schedule Mode, as an integer number +channel-type.venstarthermostat.schedulePart.label = Schedule Part +channel-type.venstarthermostat.schedulePart.description = Current Schedule Part +channel-type.venstarthermostat.schedulePart.state.option.morning = Morning +channel-type.venstarthermostat.schedulePart.state.option.day = Day +channel-type.venstarthermostat.schedulePart.state.option.evening = Evening +channel-type.venstarthermostat.schedulePart.state.option.night = Night +channel-type.venstarthermostat.schedulePart.state.option.inactive = Inactive +channel-type.venstarthermostat.schedulePartRaw.label = Schedule Part (Raw) +channel-type.venstarthermostat.schedulePartRaw.description = Current Schedule Part, as an integer number +channel-type.venstarthermostat.systemMode.label = System Mode +channel-type.venstarthermostat.systemMode.description = Current System Operating Mode +channel-type.venstarthermostat.systemMode.state.option.off = Off +channel-type.venstarthermostat.systemMode.state.option.heat = Heat +channel-type.venstarthermostat.systemMode.state.option.cool = Cool +channel-type.venstarthermostat.systemMode.state.option.auto = Auto +channel-type.venstarthermostat.systemModeRaw.label = System Mode (Raw) +channel-type.venstarthermostat.systemModeRaw.description = Current System Operating Mode, as an integer number +channel-type.venstarthermostat.systemState.label = System State +channel-type.venstarthermostat.systemState.description = Current System Operating State +channel-type.venstarthermostat.systemState.state.option.idle = Idle +channel-type.venstarthermostat.systemState.state.option.heating = Heating +channel-type.venstarthermostat.systemState.state.option.cooling = Cooling +channel-type.venstarthermostat.systemState.state.option.lockout = Lockout +channel-type.venstarthermostat.systemState.state.option.error = Error +channel-type.venstarthermostat.systemStateRaw.label = System State (Raw) +channel-type.venstarthermostat.systemStateRaw.description = Current System Operating State, as an integer +channel-type.venstarthermostat.temperature.label = Temperature +channel-type.venstarthermostat.temperature.description = Temperature +channel-type.venstarthermostat.timestampRuntime.label = Runtime Record Timestamp +channel-type.venstarthermostat.timestampRuntime.description = Time stamp of Runtime Update (Day 0 = TODAY, Day 6 = 6 days ago) +channel-type.venstarthermostat.timestampRuntime.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM diff --git a/bundles/org.openhab.binding.ventaair/src/main/resources/OH-INF/i18n/ventaair.properties b/bundles/org.openhab.binding.ventaair/src/main/resources/OH-INF/i18n/ventaair.properties new file mode 100644 index 0000000000000..bec544e58e739 --- /dev/null +++ b/bundles/org.openhab.binding.ventaair/src/main/resources/OH-INF/i18n/ventaair.properties @@ -0,0 +1,84 @@ +# binding + +binding.ventaair.name = VentaAir Binding +binding.ventaair.description = This is the binding for Venta Air - Air cleaning and humidifying devices + +# thing types + +thing-type.ventaair.generic.label = Generic Humidifier/Cleaner +thing-type.ventaair.generic.description = Thing for Venta Air Humidifiers/Cleaners +thing-type.ventaair.lw60t.label = LW60-T VentaAir Humidifier +thing-type.ventaair.lw60t.description = Thing for Venta Air LW60-T Humidifiers + +# thing types config + +thing-type.config.ventaair.humidifier.deviceType.label = Device Type +thing-type.config.ventaair.humidifier.deviceType.description = Type of the device as integer +thing-type.config.ventaair.humidifier.hash.label = Hash +thing-type.config.ventaair.humidifier.hash.description = Optional negative number that relates to a connection (like from the VentaApp) to the device +thing-type.config.ventaair.humidifier.ipAddress.label = IP Address +thing-type.config.ventaair.humidifier.ipAddress.description = IP Address or hostname of the device +thing-type.config.ventaair.humidifier.macAddress.label = MAC Address +thing-type.config.ventaair.humidifier.macAddress.description = MAC Address of the device +thing-type.config.ventaair.humidifier.pollingTime.label = Polling Interval +thing-type.config.ventaair.humidifier.pollingTime.description = Time in seconds between fetching data from the device + +# channel types + +channel-type.ventaair.automatic.label = Automatic +channel-type.ventaair.automatic.description = Automatic +channel-type.ventaair.boost.label = Boost +channel-type.ventaair.boost.description = Boost +channel-type.ventaair.childLock.label = Child Lock +channel-type.ventaair.childLock.description = Child Lock +channel-type.ventaair.cleanMode.label = Cleaning Mode +channel-type.ventaair.cleanMode.description = Device is in cleaning mode (ON) +channel-type.ventaair.cleaningTime.label = Cleaning Time +channel-type.ventaair.cleaningTime.description = Time until next cleaning (in hours) +channel-type.ventaair.discReplaceTime.label = Hygiene Disc Replacement +channel-type.ventaair.discReplaceTime.description = Time until the Hygiene Disc should be replaced (in hours) +channel-type.ventaair.fanRPM.label = Fan RPM +channel-type.ventaair.fanRPM.description = Fan RPM +channel-type.ventaair.fanSpeed.label = Fan Speed +channel-type.ventaair.fanSpeed.description = Speed of the ventilation fan (0-5) +channel-type.ventaair.fanSpeed.state.option.0 = Off +channel-type.ventaair.fanSpeed.state.option.1 = 1 +channel-type.ventaair.fanSpeed.state.option.2 = 2 +channel-type.ventaair.fanSpeed.state.option.3 = 3 +channel-type.ventaair.fanSpeed.state.option.4 = 4 +channel-type.ventaair.fanSpeed.state.option.5 = 5 +channel-type.ventaair.humidity.label = Humidity +channel-type.ventaair.humidity.description = Current Humidity +channel-type.ventaair.operationTime.label = Operation Time +channel-type.ventaair.operationTime.description = Operation Time since the device was first started (in hours) +channel-type.ventaair.sleepMode.label = Sleep Mode +channel-type.ventaair.sleepMode.description = Sleep Mode +channel-type.ventaair.targetHumidity.label = Target Humidity +channel-type.ventaair.targetHumidity.description = Target Humidity (30-70) +channel-type.ventaair.targetHumidity.state.option.30 = 30 % +channel-type.ventaair.targetHumidity.state.option.35 = 35 % +channel-type.ventaair.targetHumidity.state.option.40 = 40 % +channel-type.ventaair.targetHumidity.state.option.45 = 45 % +channel-type.ventaair.targetHumidity.state.option.50 = 50 % +channel-type.ventaair.targetHumidity.state.option.55 = 55 % +channel-type.ventaair.targetHumidity.state.option.60 = 60 % +channel-type.ventaair.targetHumidity.state.option.65 = 65 % +channel-type.ventaair.targetHumidity.state.option.70 = 70 % +channel-type.ventaair.temperature.label = Temperature +channel-type.ventaair.temperature.description = Current Temperature +channel-type.ventaair.timer.label = Timer +channel-type.ventaair.timer.description = Timer (0,1,3,5,7,9h) +channel-type.ventaair.timer.state.option.0 = Off +channel-type.ventaair.timer.state.option.1 = 1 hour +channel-type.ventaair.timer.state.option.3 = 3 hours +channel-type.ventaair.timer.state.option.5 = 5 hours +channel-type.ventaair.timer.state.option.7 = 7 hours +channel-type.ventaair.timer.state.option.9 = 9 hours +channel-type.ventaair.timerTimePassed.label = Timer Time Passed +channel-type.ventaair.timerTimePassed.description = Time that has passed since set by the Timer +channel-type.ventaair.waterLevel.label = Water Level +channel-type.ventaair.waterLevel.description = Water Level +channel-type.ventaair.waterLevel.state.option.0 = Critical +channel-type.ventaair.waterLevel.state.option.1 = Refill tank +channel-type.ventaair.waterLevel.state.option.2 = OK +channel-type.ventaair.waterLevel.state.option.3 = Full diff --git a/bundles/org.openhab.binding.verisure/src/main/resources/OH-INF/i18n/verisure.properties b/bundles/org.openhab.binding.verisure/src/main/resources/OH-INF/i18n/verisure.properties new file mode 100644 index 0000000000000..0f9e8758836a0 --- /dev/null +++ b/bundles/org.openhab.binding.verisure/src/main/resources/OH-INF/i18n/verisure.properties @@ -0,0 +1,167 @@ +# binding + +binding.verisure.name = Verisure Binding +binding.verisure.description = This is the binding for Verisure Alarm System. + +# thing types + +thing-type.verisure.alarm.label = Verisure Alarm +thing-type.verisure.alarm.description = A Verisure Alarm. +thing-type.verisure.bridge.label = Verisure Bridge +thing-type.verisure.bridge.description = This bridge represents the http://mypages.verisure.com web page connector. +thing-type.verisure.broadbandConnection.label = Verisure Broadband Connection +thing-type.verisure.broadbandConnection.description = Status of the Verisure broadband connection. +thing-type.verisure.doorWindowSensor.label = Verisure Door or Window Sensor +thing-type.verisure.doorWindowSensor.description = A Verisure door or window sensor in your system. +thing-type.verisure.eventLog.label = Verisure Event Log +thing-type.verisure.eventLog.description = Contents of the Verisure event log. +thing-type.verisure.gateway.label = Verisure Gateway +thing-type.verisure.gateway.description = Communication status for the Verisure Gateway. +thing-type.verisure.miceDetection.label = Verisure Mice Detection +thing-type.verisure.miceDetection.description = Status of the Verisure mice detection. +thing-type.verisure.nightControl.label = Verisure Night Control +thing-type.verisure.nightControl.description = A climate device in a Night Control. +thing-type.verisure.siren.label = Verisure Siren +thing-type.verisure.siren.description = A climate device in a Siren. +thing-type.verisure.smartLock.label = Yale Doorman SmartLock +thing-type.verisure.smartLock.description = Integrated Yale Doorman SmartLock. +thing-type.verisure.smartPlug.label = Verisure SmartPlug +thing-type.verisure.smartPlug.description = A Verisure SmartPlug in your system. +thing-type.verisure.smokeDetector.label = Verisure Smoke Detector +thing-type.verisure.smokeDetector.description = A climate device in a Smoke detector. +thing-type.verisure.userPresence.label = Verisure User Presence +thing-type.verisure.userPresence.description = Verisure Presence information about your configured and active Verisure users. +thing-type.verisure.waterDetector.label = Verisure Water Detector +thing-type.verisure.waterDetector.description = A climate device in a Water detector. + +# thing types config + +thing-type.config.verisure.alarm.deviceId.label = Device Id +thing-type.config.verisure.alarm.deviceId.description = Unique Id. +thing-type.config.verisure.bridge.password.label = Password +thing-type.config.verisure.bridge.password.description = The password used to login to http://mypage.verisure.com. +thing-type.config.verisure.bridge.pin.label = Pin Code +thing-type.config.verisure.bridge.pin.description = The username's pin code to arm/disarm alarm and lock/unlock door. Comma separated in case of many installations. +thing-type.config.verisure.bridge.refresh.label = Refresh Interval +thing-type.config.verisure.bridge.refresh.description = Specifies the refresh interval in seconds. +thing-type.config.verisure.bridge.username.label = Username +thing-type.config.verisure.bridge.username.description = The username used to login to http://mypage.verisure.com. +thing-type.config.verisure.broadbandConnection.deviceId.label = Device Id +thing-type.config.verisure.broadbandConnection.deviceId.description = Unique Id. +thing-type.config.verisure.doorWindowSensor.deviceId.label = Device Id +thing-type.config.verisure.doorWindowSensor.deviceId.description = Verisure Id. +thing-type.config.verisure.eventLog.deviceId.label = Device Id +thing-type.config.verisure.eventLog.deviceId.description = Unique Id. +thing-type.config.verisure.eventLog.eventTriggerDelay.label = Event Trigger Delay +thing-type.config.verisure.eventLog.eventTriggerDelay.description = Specifies the event trigger delay in milliseconds. +thing-type.config.verisure.eventLog.numberOfEvents.label = Number of Events +thing-type.config.verisure.eventLog.numberOfEvents.description = Number of events to fetch each poll. +thing-type.config.verisure.gateway.deviceId.label = Device Id +thing-type.config.verisure.gateway.deviceId.description = Unique Id. +thing-type.config.verisure.miceDetection.deviceId.label = Device Id +thing-type.config.verisure.miceDetection.deviceId.description = Unique Id. +thing-type.config.verisure.nightControl.deviceId.label = Device Id +thing-type.config.verisure.nightControl.deviceId.description = Verisure Id. +thing-type.config.verisure.siren.deviceId.label = Device Id +thing-type.config.verisure.siren.deviceId.description = Verisure Id. +thing-type.config.verisure.smartLock.deviceId.label = Device Id +thing-type.config.verisure.smartLock.deviceId.description = Verisure Id. +thing-type.config.verisure.smartPlug.deviceId.label = Device Id +thing-type.config.verisure.smartPlug.deviceId.description = Verisure Id. +thing-type.config.verisure.smokeDetector.deviceId.label = Device Id +thing-type.config.verisure.smokeDetector.deviceId.description = Verisure Id. +thing-type.config.verisure.userPresence.deviceId.label = Device Id +thing-type.config.verisure.userPresence.deviceId.description = Unique Id. +thing-type.config.verisure.waterDetector.deviceId.label = Device Id +thing-type.config.verisure.waterDetector.deviceId.description = Verisure Id. + +# channel types + +channel-type.verisure.alarmStatus.label = Alarm Status +channel-type.verisure.alarmStatus.description = Verisure alarm status. +channel-type.verisure.alarmStatus.state.option.DISARMED = DISARMED +channel-type.verisure.alarmStatus.state.option.ARMED_HOME = ARMED HOME +channel-type.verisure.alarmStatus.state.option.ARMED_AWAY = ARMED AWAY +channel-type.verisure.autoRelock.label = SmartLock Auto Re-lock +channel-type.verisure.autoRelock.description = Verisure smart lock auto re-lock status. +channel-type.verisure.changedByUser.label = Operated By +channel-type.verisure.changedByUser.description = User who did the last change. +channel-type.verisure.changedVia.label = Changed via +channel-type.verisure.changedVia.description = Method used to change status. +channel-type.verisure.communicationTestResult.label = Verisure GW Communication Test Result +channel-type.verisure.communicationTestResult.description = Verisure Gateway communication test result. +channel-type.verisure.connected.label = Broadband Connection Status +channel-type.verisure.connected.description = Verisure broadband connection status. +channel-type.verisure.countLast24Hours.label = Mouse Count Last 24 Hours +channel-type.verisure.countLast24Hours.description = Mouse count last 24 hours. +channel-type.verisure.countLatestDetection.label = Mouse Count Latest Detection +channel-type.verisure.countLatestDetection.description = Mouse count latest detection during last 24 hours. +channel-type.verisure.durationLast24Hours.label = Duration Last 24 Hours +channel-type.verisure.durationLast24Hours.description = Duration last 24 hours. +channel-type.verisure.durationLatestDetection.label = Duration Last Detection +channel-type.verisure.durationLatestDetection.description = Duration last detection. +channel-type.verisure.eventLog.label = Verisure Event Log +channel-type.verisure.eventLog.description = Verisure event log as a JSON array. +channel-type.verisure.hazardous.label = Hazardous +channel-type.verisure.hazardous.description = Is Verisure smart plug configured as hazardous. +channel-type.verisure.humidity.label = Humidity +channel-type.verisure.humidity.description = Current humidity in %. +channel-type.verisure.humidityEnabled.label = Humidity Enabled +channel-type.verisure.humidityEnabled.description = Is Climate device capable of reporting humidity. +channel-type.verisure.installationId.label = Installation Site Id +channel-type.verisure.installationId.description = ID of the installation site. +channel-type.verisure.installationName.label = Installation Site Name +channel-type.verisure.installationName.description = Name of the installation site. +channel-type.verisure.label.label = Label +channel-type.verisure.label.description = The name of the door/window. +channel-type.verisure.lastEventCategory.label = Last Event Category +channel-type.verisure.lastEventCategory.description = The last event's category in the event log. +channel-type.verisure.lastEventDeviceId.label = Last Event Device Id +channel-type.verisure.lastEventDeviceId.description = The last event's device id in the event log. +channel-type.verisure.lastEventDeviceType.label = Last Event Device Type +channel-type.verisure.lastEventDeviceType.description = The last event's device type in the event log. +channel-type.verisure.lastEventId.label = Last Event Id +channel-type.verisure.lastEventId.description = The last event's id in the event log. +channel-type.verisure.lastEventType.label = Last Event Type +channel-type.verisure.lastEventType.description = The last event's type in the event log. +channel-type.verisure.lastEventUserName.label = Last Event User Name +channel-type.verisure.lastEventUserName.description = The last event's user name in the event log. +channel-type.verisure.location.label = Location +channel-type.verisure.location.description = The location of the device. +channel-type.verisure.model.label = Verisure GW Model +channel-type.verisure.model.description = Verisure Gateway model. +channel-type.verisure.motorJam.label = SmartLock Motor Jam +channel-type.verisure.motorJam.description = Tells if the SmartLock motor has jammed. +channel-type.verisure.numericStatus.label = Current Numeric Status +channel-type.verisure.numericStatus.description = Information about current numeric status. +channel-type.verisure.smartLockStatus.label = SmartLock Status +channel-type.verisure.smartLockStatus.description = Verisure smart lock status. +channel-type.verisure.smartLockVoiceLevel.label = SmartLock Voice Level Setting +channel-type.verisure.smartLockVoiceLevel.description = Verisure smart lock voice level status. +channel-type.verisure.smartLockVoiceLevel.state.option.ESSENTIAL = ESSENTIAL +channel-type.verisure.smartLockVoiceLevel.state.option.NORMAL = NORMAL +channel-type.verisure.smartLockVolume.label = SmartLock Volume +channel-type.verisure.smartLockVolume.description = Verisure smart lock volume status. +channel-type.verisure.smartLockVolume.state.option.SILENCE = SILENCE +channel-type.verisure.smartLockVolume.state.option.LOW = LOW +channel-type.verisure.smartLockVolume.state.option.HIGH = HIGH +channel-type.verisure.smartPlugStatus.label = SmartPlug Status +channel-type.verisure.smartPlugStatus.description = Verisure smart plug status. +channel-type.verisure.state.label = Door/Window State +channel-type.verisure.state.description = Is door/window opened or closed. (OPEN/CLOSED) +channel-type.verisure.status.label = Current Status +channel-type.verisure.status.description = Information on current status. +channel-type.verisure.temperature.label = Temperature +channel-type.verisure.temperature.description = Current temperature. +channel-type.verisure.timestamp.label = TimeStamp +channel-type.verisure.timestamp.description = Date and time of last event change. +channel-type.verisure.timestamp.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM +channel-type.verisure.triggerChannel.label = Trigger Channel +channel-type.verisure.userDeviceName.label = User Device Name +channel-type.verisure.userDeviceName.description = Information on user device name. +channel-type.verisure.userLocationStatus.label = User Location Status +channel-type.verisure.userLocationStatus.description = Information on user location status (HOME/AWAY). +channel-type.verisure.userName.label = User Name +channel-type.verisure.userName.description = Name of the user. +channel-type.verisure.webAccount.label = User Email +channel-type.verisure.webAccount.description = The User's Email address. diff --git a/bundles/org.openhab.binding.vitotronic/src/main/resources/OH-INF/i18n/vitotronic.properties b/bundles/org.openhab.binding.vitotronic/src/main/resources/OH-INF/i18n/vitotronic.properties new file mode 100644 index 0000000000000..c433aa667cb46 --- /dev/null +++ b/bundles/org.openhab.binding.vitotronic/src/main/resources/OH-INF/i18n/vitotronic.properties @@ -0,0 +1,161 @@ +# binding + +binding.vitotronic.name = Vitotronic Binding +binding.vitotronic.description = This is the binding for Vitotronic. + +# thing types + +thing-type.vitotronic.bridge.label = Bridge Vitotronic Optolink Adapter +thing-type.vitotronic.bridge.description = This bridge represents the Vitotronic Optolink adapter +thing-type.vitotronic.circuit.label = Circuit +thing-type.vitotronic.circuit.description = Heating circuit controls the flow of heating water between the heating system and the radiators in the rooms +thing-type.vitotronic.circuit.channel.timer_FR.label = Friday Heating Timer +thing-type.vitotronic.circuit.channel.timer_FR.description = On/Off timer for Friday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_MO.label = Monday Heating Timer +thing-type.vitotronic.circuit.channel.timer_MO.description = On/Off timer for Monday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_SA.label = Saturday Heating Timer +thing-type.vitotronic.circuit.channel.timer_SA.description = On/Off timer for Saturday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_SU.label = Sunday Heating Timer +thing-type.vitotronic.circuit.channel.timer_SU.description = On/Off timer for Sunday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_TH.label = Thursday Heating Timer +thing-type.vitotronic.circuit.channel.timer_TH.description = On/Off timer for Thursday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_TU.label = Tuesday Heating Timer +thing-type.vitotronic.circuit.channel.timer_TU.description = On/Off timer for Tuesday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_WE.label = Wednesday Heating Timer +thing-type.vitotronic.circuit.channel.timer_WE.description = On/Off timer for Wednesday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_FR.label = Friday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_FR.description = On/Off timer for Friday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_MO.label = Monday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_MO.description = On/Off timer for Monday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_SA.label = Saturday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_SA.description = On/Off timer for Saturday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_SU.label = Sunday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_SU.description = On/Off timer for Sunday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_TH.label = Thursday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_TH.description = On/Off timer for Thursday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_TU.label = Tuesday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_TU.description = On/Off timer for Tuesday. Up to 4 timers can be set +thing-type.vitotronic.circuit.channel.timer_ww_WE.label = Wednesday Hot Water Timer +thing-type.vitotronic.circuit.channel.timer_ww_WE.description = On/Off timer for Wednesday. Up to 4 timers can be set +thing-type.vitotronic.gasburner.label = Gas Burner +thing-type.vitotronic.gasburner.description = Condensing Technology Gas Burner +thing-type.vitotronic.gasburner.channel.powerlevel.description = Power of the gas burner +thing-type.vitotronic.heating.label = Vitotronic +thing-type.vitotronic.heating.description = Vitotronic core system +thing-type.vitotronic.oilburner.label = Oil Burner +thing-type.vitotronic.oilburner.description = Oil Fireplace +thing-type.vitotronic.oilburner.channel.powerlevel.description = Power of the oil burner +thing-type.vitotronic.pelletburner.label = Pellet Burner +thing-type.vitotronic.pelletburner.description = Pellet Fireplace, works for wood also +thing-type.vitotronic.pelletburner.channel.powerlevel.description = Power of the pellet burner +thing-type.vitotronic.pump.label = Pump +thing-type.vitotronic.pump.description = Single pump +thing-type.vitotronic.solar.label = Solar Heating +thing-type.vitotronic.solar.description = Solar water heating (SWH): Convert sunlight into energy for water heating +thing-type.vitotronic.storagetank.label = Hotwater Storagetank +thing-type.vitotronic.storagetank.description = Storage Tank, stores heat in a water tank on 3 levels: bottom, middle, top=hot water +thing-type.vitotronic.temperaturesensor.label = Temperature Sensor +thing-type.vitotronic.temperaturesensor.description = Single temperature sensor +thing-type.vitotronic.valve.label = Valve +thing-type.vitotronic.valve.description = Single valve + +# thing types config + +thing-type.config.vitotronic.bridge.adapterID.label = Adapter ID +thing-type.config.vitotronic.bridge.adapterID.description = The ID of the adapter. +thing-type.config.vitotronic.bridge.ipAddress.label = IP Address +thing-type.config.vitotronic.bridge.ipAddress.description = The IP address of the Optolink adapter +thing-type.config.vitotronic.bridge.port.label = Adapter Port +thing-type.config.vitotronic.bridge.port.description = Port of the LAN gateway +thing-type.config.vitotronic.bridge.refreshInterval.label = Refresh Interval +thing-type.config.vitotronic.bridge.refreshInterval.description = Refreshtime in seconds. + +# channel types + +channel-type.vitotronic.actualpower.label = Actual Power Level +channel-type.vitotronic.actualpower.description = Actual power of the burner +channel-type.vitotronic.airshutter_prim.label = Primary Airshutter +channel-type.vitotronic.airshutter_prim.description = Position of the primary air shutter +channel-type.vitotronic.airshutter_sec.label = Secondary Airshutter +channel-type.vitotronic.airshutter_sec.description = Position of the secondary air shutter +channel-type.vitotronic.boiler_temp.label = Boiler +channel-type.vitotronic.boiler_temp.description = Temperature sensor of boiler (fireplace) +channel-type.vitotronic.bottom_temp.label = Bottom +channel-type.vitotronic.bottom_temp.description = Temperature sensor at the bottom of the storage tank +channel-type.vitotronic.bufferload.label = Buffer Load Pump +channel-type.vitotronic.bufferload.description = State of the pump (on/off) +channel-type.vitotronic.circuitpump.label = Circuit Pump +channel-type.vitotronic.circuitpump.description = Circuit pump state +channel-type.vitotronic.collector_temp.label = Collector +channel-type.vitotronic.collector_temp.description = Actual temperature of the collector +channel-type.vitotronic.consumedoil.label = Consumed Oil +channel-type.vitotronic.consumedoil.description = Consumed Oil since start of heating in Liter +channel-type.vitotronic.consumedpellets.label = Consumed Pellets +channel-type.vitotronic.consumedpellets.description = Consumed Pellets since start of heating in tons +channel-type.vitotronic.error.label = Errors +channel-type.vitotronic.error.description = True, if errors for the burner exists +channel-type.vitotronic.exhaust_temp.label = Exhaust Temperature +channel-type.vitotronic.exhaust_temp.description = Actual temperature of the exhaust +channel-type.vitotronic.fanspeed.label = Fan Speed +channel-type.vitotronic.fanspeed.description = Fan Speed in rpm +channel-type.vitotronic.fanspeed_target.label = Target Fan Speed +channel-type.vitotronic.fanspeed_target.description = Fan Speed in rpm +channel-type.vitotronic.flame_temp.label = Flame +channel-type.vitotronic.flame_temp.description = Temperature of flame +channel-type.vitotronic.flow_temp.label = Flow +channel-type.vitotronic.flow_temp.description = Temperature sensor of the circuit flow +channel-type.vitotronic.flowuprating.label = Pump +channel-type.vitotronic.flowuprating.description = Pump state +channel-type.vitotronic.gradient.label = Gradient +channel-type.vitotronic.gradient.description = The gradient relative to outside temperature +channel-type.vitotronic.hotwater_temp.label = Hot Water +channel-type.vitotronic.hotwater_temp.description = Temperature sensor of the hot water +channel-type.vitotronic.hotwater_temp_setpoint.label = Hotwater TempSet +channel-type.vitotronic.hotwater_temp_setpoint.description = Set the hot water temperature +channel-type.vitotronic.lambdasensor.label = Lambdasensor (O2) +channel-type.vitotronic.lambdasensor.description = Oxygen content of the exhaust air +channel-type.vitotronic.loadsuppression.label = Load Suppression +channel-type.vitotronic.loadsuppression.description = State of the load suppression (on/off) +channel-type.vitotronic.malfunction.label = Heating Malfunction +channel-type.vitotronic.malfunction.description = General Malfunction state of the heating +channel-type.vitotronic.middle_temp.label = Middle +channel-type.vitotronic.middle_temp.description = Temperature sensor in the middle of the storage tank +channel-type.vitotronic.niveau.label = Niveau +channel-type.vitotronic.niveau.description = The niveau relative to outside temperature +channel-type.vitotronic.ontime.label = On Time +channel-type.vitotronic.ontime.description = Ontime in hours +channel-type.vitotronic.ontimelevel1.label = On Time Level 1 +channel-type.vitotronic.ontimelevel1.description = Ontime in hours +channel-type.vitotronic.ontimelevel2.label = On Time Level 2 +channel-type.vitotronic.ontimelevel2.description = Ontime in hours +channel-type.vitotronic.operationmode.label = Operationmode +channel-type.vitotronic.operationmode.description = Operationmode +channel-type.vitotronic.outside_temp.label = Outside Temperature +channel-type.vitotronic.outside_temp.description = Outside temperature sensor +channel-type.vitotronic.party_temp_setpoint.label = Partymode TempSet +channel-type.vitotronic.party_temp_setpoint.description = Target temperature of party mode +channel-type.vitotronic.partymode.label = Partymode +channel-type.vitotronic.partymode.description = Partymode on/off +channel-type.vitotronic.powerlevel.label = Power Level +channel-type.vitotronic.producedheat.label = Produced Heat +channel-type.vitotronic.producedheat.description = Produced heat since starting solar system +channel-type.vitotronic.pump.label = Pump +channel-type.vitotronic.pump.description = Pump state +channel-type.vitotronic.room_temp.label = Room Temp +channel-type.vitotronic.room_temp.description = Temperature of rooms +channel-type.vitotronic.room_temp_setpoint.label = Room TempSet +channel-type.vitotronic.room_temp_setpoint.description = Target temperature of rooms +channel-type.vitotronic.save_temp_setpoint.label = Savemode TempSet +channel-type.vitotronic.save_temp_setpoint.description = Target temperature of save mode +channel-type.vitotronic.savemode.label = Savemode +channel-type.vitotronic.savemode.description = Savemode on/off +channel-type.vitotronic.starts.label = Starts +channel-type.vitotronic.starts.description = Count of starts +channel-type.vitotronic.storagetank_temp.label = Storagetank +channel-type.vitotronic.storagetank_temp.description = Actual temperature of the storage tank (solar sensor) +channel-type.vitotronic.systemtime.label = DateTime of the Heating System +channel-type.vitotronic.temperature.label = Temperature +channel-type.vitotronic.temperature.description = Generic temperature sensor +channel-type.vitotronic.timer.label = Timer for Heating or Warm Water +channel-type.vitotronic.valve.label = Valve +channel-type.vitotronic.valve.description = Value of a generic valve diff --git a/bundles/org.openhab.binding.warmup/src/main/resources/OH-INF/i18n/warmup.properties b/bundles/org.openhab.binding.warmup/src/main/resources/OH-INF/i18n/warmup.properties new file mode 100644 index 0000000000000..3028eceac0856 --- /dev/null +++ b/bundles/org.openhab.binding.warmup/src/main/resources/OH-INF/i18n/warmup.properties @@ -0,0 +1,46 @@ +# binding + +binding.warmup.name = Warmup Binding +binding.warmup.description = This is the binding for a Warmup 4iE Thermostat primarily used for controlling underfloor heating. + +# thing types + +thing-type.warmup.my-warmup.label = My Warmup Account +thing-type.warmup.my-warmup.description = Connection to the https://my.warmup.com site +thing-type.warmup.room.label = Room +thing-type.warmup.room.description = Warmup 4iE Device controlling a room + +# thing types config + +thing-type.config.warmup.my-warmup.password.label = Password +thing-type.config.warmup.my-warmup.password.description = Password for my.warmup.com +thing-type.config.warmup.my-warmup.refreshInterval.label = Refresh Interval +thing-type.config.warmup.my-warmup.refreshInterval.description = Interval in seconds between automatic refreshes +thing-type.config.warmup.my-warmup.username.label = Username +thing-type.config.warmup.my-warmup.username.description = Username for my.warmup.com +thing-type.config.warmup.room.overrideDuration.label = Override Duration +thing-type.config.warmup.room.overrideDuration.description = Duration in minutes of override when target temperature is changed +thing-type.config.warmup.room.serialNumber.label = Serial Number + +# channel types + +channel-type.warmup.currentTemperature.label = Current Temperature +channel-type.warmup.currentTemperature.description = Current temperature in room, may be air or floor dependent on Heating Target +channel-type.warmup.frostProtectionMode.label = Frost Protection Mode +channel-type.warmup.overrideRemaining.label = Override Remaining +channel-type.warmup.overrideRemaining.description = How long until the override deactivates +channel-type.warmup.runMode.label = Run Mode +channel-type.warmup.runMode.description = The heat regulation mode of the thermostat +channel-type.warmup.runMode.state.option.not_set = Not Set +channel-type.warmup.runMode.state.option.off = Off +channel-type.warmup.runMode.state.option.schedule = Schedule +channel-type.warmup.runMode.state.option.override = Override +channel-type.warmup.runMode.state.option.fixed = Fixed +channel-type.warmup.runMode.state.option.anti_frost = Frost Protection +channel-type.warmup.runMode.state.option.holiday = Holiday +channel-type.warmup.runMode.state.option.fil_pilote = Fil Pilote +channel-type.warmup.runMode.state.option.gradual = Gradual +channel-type.warmup.runMode.state.option.relay = Relay +channel-type.warmup.runMode.state.option.previous = Previous +channel-type.warmup.targetTemperature.label = Target Temperature +channel-type.warmup.targetTemperature.description = Target temperature currently set on device diff --git a/bundles/org.openhab.binding.webthing/src/main/resources/OH-INF/i18n/webthing.properties b/bundles/org.openhab.binding.webthing/src/main/resources/OH-INF/i18n/webthing.properties new file mode 100644 index 0000000000000..2bca6cbac9a24 --- /dev/null +++ b/bundles/org.openhab.binding.webthing/src/main/resources/OH-INF/i18n/webthing.properties @@ -0,0 +1,29 @@ +# binding + +binding.webthing.name = WebThing Binding +binding.webthing.description = The WebThing binding supports an interface to remote devices implementing the Web Thing API. + +# thing types + +thing-type.webthing.generic.label = WebThing +thing-type.webthing.generic.description = The WebThing to be connected + +# thing types config + +thing-type.config.webthing.generic.webThingURI.label = URI +thing-type.config.webthing.generic.webThingURI.description = The URI of the WebThing to be connected. E.g. the URI of a web-connected MotionSensor or a URI of a web-connected Display + +# channel types + +channel-type.webthing.color.label = Webthing Binding Channel +channel-type.webthing.color.description = Color channel for Webthing Binding +channel-type.webthing.contact.label = Webthing Binding Channel +channel-type.webthing.contact.description = Contact channel for Webthing Binding +channel-type.webthing.dimmer.label = Webthing Binding Channel +channel-type.webthing.dimmer.description = Dimmer channel for Webthing Binding +channel-type.webthing.number.label = Webthing Binding Channel +channel-type.webthing.number.description = Number channel for Webthing Binding +channel-type.webthing.string.label = Webthing Binding Channel +channel-type.webthing.string.description = String channel for Webthing Binding +channel-type.webthing.switch.label = Webthing Binding Channel +channel-type.webthing.switch.description = Switch channel for Webthing Binding diff --git a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties new file mode 100644 index 0000000000000..92b9c22c56e1d --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties @@ -0,0 +1,126 @@ +# binding + +binding.wemo.name = WeMo Binding +binding.wemo.description = The WeMo binding integrates Belkin WeMo devices. + +# thing types + +thing-type.wemo.CoffeeMaker.label = Mr. Coffee WeMo Enabled Coffeemaker +thing-type.wemo.CoffeeMaker.description = This is a WeMo enabled coffee maker +thing-type.wemo.MZ100.label = WeMo LED Light +thing-type.wemo.MZ100.description = This is a standard WeMo light bulb with E27 socket +thing-type.wemo.Maker.label = WeMo Maker +thing-type.wemo.Maker.description = This is a WeMo Maker +thing-type.wemo.bridge.label = WeMo Link +thing-type.wemo.bridge.description = The Wemo Link represents the Belkin WeMo Link bridge. +thing-type.wemo.dimmer.label = WeMo DimmerSwitch +thing-type.wemo.dimmer.description = This is a WeMo DimmerSwitch +thing-type.wemo.insight.label = WeMo Insight Switch +thing-type.wemo.insight.description = This is a WeMo Insight Switch with energy measurement +thing-type.wemo.lightswitch.label = WeMo Light Switch +thing-type.wemo.lightswitch.description = This is a WeMo LightSwitch +thing-type.wemo.motion.label = WeMo Motion +thing-type.wemo.motion.description = This is a WeMo MotionSensor +thing-type.wemo.socket.label = WeMo Switch +thing-type.wemo.socket.description = This is a standard WeMo Switch + +# thing types config + +thing-type.config.wemo.CoffeeMaker.pollingInterval.label = Polling Interval +thing-type.config.wemo.CoffeeMaker.pollingInterval.description = Interval polling the WeMo Coffee Maker. +thing-type.config.wemo.CoffeeMaker.udn.label = Unique Device Name +thing-type.config.wemo.CoffeeMaker.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.MZ100.deviceID.label = Device ID +thing-type.config.wemo.MZ100.deviceID.description = The device ID identifies one certain WeMo light. +thing-type.config.wemo.Maker.udn.label = Unique Device Name +thing-type.config.wemo.Maker.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.bridge.udn.label = Unique Device Name +thing-type.config.wemo.bridge.udn.description = The UDN identifies the WeMo Link Device +thing-type.config.wemo.dimmer.udn.label = Unique Device Name +thing-type.config.wemo.dimmer.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.insight.udn.label = Unique Device Name +thing-type.config.wemo.insight.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.lightswitch.udn.label = Unique Device Name +thing-type.config.wemo.lightswitch.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.motion.udn.label = Unique Device Name +thing-type.config.wemo.motion.udn.description = The UDN identifies the WeMo Device +thing-type.config.wemo.socket.udn.label = Unique Device Name +thing-type.config.wemo.socket.udn.description = The UDN identifies the WeMo Device + +# channel types + +channel-type.wemo.averagePower.label = Average Power +channel-type.wemo.averagePower.description = The average power consumption +channel-type.wemo.brewed.label = Brewed +channel-type.wemo.brewed.description = Date/time the coffee maker last completed brewing coffee +channel-type.wemo.brightness.label = Brightness +channel-type.wemo.brightness.description = The brightness channel allows to control the brightness of a light. It is also possible to switch the light on and off. +channel-type.wemo.cleanAdvise.label = CleanAdvise +channel-type.wemo.cleanAdvise.description = Indicates if a WeMo Coffee Maker needs to be cleaned +channel-type.wemo.coffeeMode.label = Mode +channel-type.wemo.coffeeMode.description = Shows the operation mode of a WeMo Coffee Maker +channel-type.wemo.coffeeMode.state.option.Refill = Not Ready: Refill Water and Replace Carafe +channel-type.wemo.coffeeMode.state.option.PlaceCarafe = Not Ready: Replace Carafe +channel-type.wemo.coffeeMode.state.option.RefillWater = Not Ready: Refill Water +channel-type.wemo.coffeeMode.state.option.Ready = Ready +channel-type.wemo.coffeeMode.state.option.Brewing = Brewing +channel-type.wemo.coffeeMode.state.option.Brewed = Brewing Finished +channel-type.wemo.coffeeMode.state.option.CleaningBrewing = Cleaning Coffee Maker +channel-type.wemo.coffeeMode.state.option.CleaningSoaking = Cleaning Filter +channel-type.wemo.coffeeMode.state.option.BrewFailCarafeRemoved = Brewing Failed: Carafe Removed +channel-type.wemo.currentPower.label = Power +channel-type.wemo.currentPower.description = The current power consumption +channel-type.wemo.endTime.label = NightMode End Time +channel-type.wemo.endTime.description = Time when the Night Mode ends +channel-type.wemo.endTime.state.pattern = %1$tR +channel-type.wemo.energyToday.label = Energy Today +channel-type.wemo.energyToday.description = Todays power consumption +channel-type.wemo.energyTotal.label = Energy Total +channel-type.wemo.energyTotal.description = Total power consumption +channel-type.wemo.faderCountDownTime.label = Fader CountDown Time +channel-type.wemo.faderCountDownTime.description = The fading duration time in minutes +channel-type.wemo.faderEnabled.label = Fader OFF/ON +channel-type.wemo.faderEnabled.description = Allows to switch the fader ON/OFF +channel-type.wemo.filterAdvise.label = FilterAdvise +channel-type.wemo.filterAdvise.description = Indicates if a WeMo Coffee Maker needs to have the filter changed +channel-type.wemo.lastChangedAt.label = Last Activity (Date/Time) +channel-type.wemo.lastChangedAt.description = Date/time when the state last changed +channel-type.wemo.lastCleaned.label = LastCleaned +channel-type.wemo.lastCleaned.description = Date/time the coffee maker last completed cleaning +channel-type.wemo.lastMotionDetected.label = Last Activity (Date/Time) +channel-type.wemo.lastMotionDetected.description = Date/time when last motion was detected +channel-type.wemo.lastOnFor.label = Last Activity (s) +channel-type.wemo.lastOnFor.description = Duration the device has been switched on for +channel-type.wemo.modeTime.label = ModeTime +channel-type.wemo.modeTime.description = Shows the current amount of time, in minutes, that the Coffee Maker has been in the current mode +channel-type.wemo.motionDetection.label = Motion Status +channel-type.wemo.motionDetection.description = Indicates whether motion is detected or not +channel-type.wemo.nightMode.label = NightMode OFF/ON +channel-type.wemo.nightMode.description = Allows to switch the nightMode ON/OFF +channel-type.wemo.nightModeBrightness.label = Night Mode Brightness +channel-type.wemo.nightModeBrightness.description = Allows setting the brightness of Night Mode +channel-type.wemo.onStandBy.label = On Standby +channel-type.wemo.onStandBy.description = Appliance on standby +channel-type.wemo.onToday.label = Today's Activity (s) +channel-type.wemo.onToday.description = How long has the device been switched on today +channel-type.wemo.onTotal.label = Total Activity (s) +channel-type.wemo.onTotal.description = How long has the device been switched on totally +channel-type.wemo.relay.label = Relay +channel-type.wemo.relay.description = Switches the integrated relay contact close/open +channel-type.wemo.sensor.label = Sensor +channel-type.wemo.sensor.description = Shows the state of the integrated sensor +channel-type.wemo.standByLimit.label = StandBy Limit +channel-type.wemo.standByLimit.description = Minimum energy draw to register device as switched on +channel-type.wemo.startTime.label = NightMode Start Time +channel-type.wemo.startTime.description = Time when the Night Mode starts +channel-type.wemo.startTime.state.pattern = %1$tR +channel-type.wemo.state.label = Switch +channel-type.wemo.state.description = Turns the power on or off +channel-type.wemo.timeRemaining.label = TimeRemaining +channel-type.wemo.timeRemaining.description = Shows the remaining brewing time of a WeMo Coffee Maker +channel-type.wemo.timerStart.label = Timer OFF/ON +channel-type.wemo.timerStart.description = Allows to switch the timer ON/OFF +channel-type.wemo.timespan.label = Usage Timespan (s) +channel-type.wemo.timespan.description = Time used to measure average usage +channel-type.wemo.waterLevelReached.label = WaterLevelReached +channel-type.wemo.waterLevelReached.description = Indicates if the WeMo Coffee Maker needs to be refilled diff --git a/bundles/org.openhab.binding.wifiled/src/main/resources/OH-INF/i18n/wifiled.properties b/bundles/org.openhab.binding.wifiled/src/main/resources/OH-INF/i18n/wifiled.properties new file mode 100644 index 0000000000000..d2a6f3fb0ec03 --- /dev/null +++ b/bundles/org.openhab.binding.wifiled/src/main/resources/OH-INF/i18n/wifiled.properties @@ -0,0 +1,62 @@ +# binding + +binding.wifiled.name = WiFi LED Binding +binding.wifiled.description = Binding for WiFi LED devices. These are known as Magic Home RGBW LED, UFO LED, LED NET controller etc. + +# thing types + +thing-type.wifiled.wifiled.label = WiFi LED +thing-type.wifiled.wifiled.description = WiFi LED Device + +# thing types config + +thing-type.config.wifiled.wifiled.driver.label = Device Driver +thing-type.config.wifiled.wifiled.driver.description = The driver used to control the device +thing-type.config.wifiled.wifiled.driver.option.CLASSIC = CLASSIC +thing-type.config.wifiled.wifiled.driver.option.FADING = FADING +thing-type.config.wifiled.wifiled.fadeDurationInMs.label = Fading Duration +thing-type.config.wifiled.wifiled.fadeDurationInMs.description = The duration for the color fading in milliseconds +thing-type.config.wifiled.wifiled.fadeSteps.label = Fading Steps +thing-type.config.wifiled.wifiled.fadeSteps.description = The number of steps used to fade over to the new color +thing-type.config.wifiled.wifiled.ip.label = IP +thing-type.config.wifiled.wifiled.ip.description = IP address or host name of the WIFI LED Controller +thing-type.config.wifiled.wifiled.pollingPeriod.label = Polling Period +thing-type.config.wifiled.wifiled.pollingPeriod.description = Polling period for refreshing the data in s +thing-type.config.wifiled.wifiled.port.label = Port +thing-type.config.wifiled.wifiled.port.description = Used Port of the device +thing-type.config.wifiled.wifiled.protocol.label = Device Protocol +thing-type.config.wifiled.wifiled.protocol.description = The protocol used for communication with the device +thing-type.config.wifiled.wifiled.protocol.option.LD382A = LD382A +thing-type.config.wifiled.wifiled.protocol.option.LD382 = LD382 +thing-type.config.wifiled.wifiled.protocol.option.LD686 = LD686 + +# channel types + +channel-type.wifiled.color.label = Color +channel-type.wifiled.power.label = Power +channel-type.wifiled.power.description = Power state +channel-type.wifiled.program.label = Program +channel-type.wifiled.program.state.option.97 = NONE +channel-type.wifiled.program.state.option.37 = Seven Colors Cross Fade +channel-type.wifiled.program.state.option.38 = Red Gradual Change +channel-type.wifiled.program.state.option.39 = Green Gradual Change +channel-type.wifiled.program.state.option.40 = Blue Gradual Change +channel-type.wifiled.program.state.option.41 = Yellow Gradual Change +channel-type.wifiled.program.state.option.42 = Cyan Gradual Change +channel-type.wifiled.program.state.option.43 = Purple Gradual Change +channel-type.wifiled.program.state.option.44 = White Gradual Change +channel-type.wifiled.program.state.option.45 = Red,Green Cross Fade +channel-type.wifiled.program.state.option.46 = Red, Blue Cross Fade +channel-type.wifiled.program.state.option.47 = Green, Blue Cross Fade +channel-type.wifiled.program.state.option.48 = Seven Colors Strobe Flash +channel-type.wifiled.program.state.option.49 = Red Strobe Flash +channel-type.wifiled.program.state.option.50 = Green Strobe Flash +channel-type.wifiled.program.state.option.51 = Blue Strobe Flash +channel-type.wifiled.program.state.option.52 = Yellow Strobe Flash +channel-type.wifiled.program.state.option.53 = Cyan Strobe Flash +channel-type.wifiled.program.state.option.54 = Purple Strobe Flash +channel-type.wifiled.program.state.option.55 = White Strobe Flash +channel-type.wifiled.program.state.option.56 = Seven Colors Jumping Change +channel-type.wifiled.programSpeed.label = Program Speed +channel-type.wifiled.white.label = White +channel-type.wifiled.white2.label = White 2 diff --git a/bundles/org.openhab.binding.wlanthermo/src/main/resources/OH-INF/i18n/wlanthermo.properties b/bundles/org.openhab.binding.wlanthermo/src/main/resources/OH-INF/i18n/wlanthermo.properties new file mode 100644 index 0000000000000..4f249f8fff46c --- /dev/null +++ b/bundles/org.openhab.binding.wlanthermo/src/main/resources/OH-INF/i18n/wlanthermo.properties @@ -0,0 +1,212 @@ +# binding + +binding.wlanthermo.name = WlanThermo Binding +binding.wlanthermo.description = This is the binding for WlanThermo, ref. https://wlanthermo.de/ + +# thing types + +thing-type.wlanthermo.esp32.label = WlanThermo Mini V2, Nano V3, Link V1 +thing-type.wlanthermo.esp32.description = WlanThermo device with ESP32 processor, such as Mini V2 (ESP32), Nano V3, Link V1 +thing-type.wlanthermo.esp32.group.channel1.label = Temperature Probe 1 +thing-type.wlanthermo.esp32.group.channel1.description = This group contains all channels for temperature probe 1 +thing-type.wlanthermo.esp32.group.channel10.label = Temperature Probe 10 +thing-type.wlanthermo.esp32.group.channel10.description = This group contains all channels for temperature probe 10 +thing-type.wlanthermo.esp32.group.channel11.label = Temperature Probe 11 +thing-type.wlanthermo.esp32.group.channel11.description = This group contains all channels for temperature probe 11 +thing-type.wlanthermo.esp32.group.channel12.label = Temperature Probe 12 +thing-type.wlanthermo.esp32.group.channel12.description = This group contains all channels for temperature probe 12 +thing-type.wlanthermo.esp32.group.channel13.label = Temperature Probe 13 +thing-type.wlanthermo.esp32.group.channel13.description = This group contains all channels for temperature probe 13 +thing-type.wlanthermo.esp32.group.channel14.label = Temperature Probe 14 +thing-type.wlanthermo.esp32.group.channel14.description = This group contains all channels for temperature probe 14 +thing-type.wlanthermo.esp32.group.channel15.label = Temperature Probe 15 +thing-type.wlanthermo.esp32.group.channel15.description = This group contains all channels for temperature probe 15 +thing-type.wlanthermo.esp32.group.channel16.label = Temperature Probe 16 +thing-type.wlanthermo.esp32.group.channel16.description = This group contains all channels for temperature probe 16 +thing-type.wlanthermo.esp32.group.channel17.label = Temperature Probe 17 +thing-type.wlanthermo.esp32.group.channel17.description = This group contains all channels for temperature probe 17 +thing-type.wlanthermo.esp32.group.channel18.label = Temperature Probe 18 +thing-type.wlanthermo.esp32.group.channel18.description = This group contains all channels for temperature probe 18 +thing-type.wlanthermo.esp32.group.channel19.label = Temperature Probe 19 +thing-type.wlanthermo.esp32.group.channel19.description = This group contains all channels for temperature probe 19 +thing-type.wlanthermo.esp32.group.channel2.label = Temperature Probe 2 +thing-type.wlanthermo.esp32.group.channel2.description = This group contains all channels for temperature probe 2 +thing-type.wlanthermo.esp32.group.channel20.label = Temperature Probe 20 +thing-type.wlanthermo.esp32.group.channel20.description = This group contains all channels for temperature probe 20 +thing-type.wlanthermo.esp32.group.channel21.label = Temperature Probe 21 +thing-type.wlanthermo.esp32.group.channel21.description = This group contains all channels for temperature probe 21 +thing-type.wlanthermo.esp32.group.channel22.label = Temperature Probe 22 +thing-type.wlanthermo.esp32.group.channel22.description = This group contains all channels for temperature probe 22 +thing-type.wlanthermo.esp32.group.channel23.label = Temperature Probe 23 +thing-type.wlanthermo.esp32.group.channel23.description = This group contains all channels for temperature probe 23 +thing-type.wlanthermo.esp32.group.channel24.label = Temperature Probe 24 +thing-type.wlanthermo.esp32.group.channel24.description = This group contains all channels for temperature probe 24 +thing-type.wlanthermo.esp32.group.channel3.label = Temperature Probe 3 +thing-type.wlanthermo.esp32.group.channel3.description = This group contains all channels for temperature probe 3 +thing-type.wlanthermo.esp32.group.channel4.label = Temperature Probe 4 +thing-type.wlanthermo.esp32.group.channel4.description = This group contains all channels for temperature probe 4 +thing-type.wlanthermo.esp32.group.channel5.label = Temperature Probe 5 +thing-type.wlanthermo.esp32.group.channel5.description = This group contains all channels for temperature probe 5 +thing-type.wlanthermo.esp32.group.channel6.label = Temperature Probe 6 +thing-type.wlanthermo.esp32.group.channel6.description = This group contains all channels for temperature probe 6 +thing-type.wlanthermo.esp32.group.channel7.label = Temperature Probe 7 +thing-type.wlanthermo.esp32.group.channel7.description = This group contains all channels for temperature probe 7 +thing-type.wlanthermo.esp32.group.channel8.label = Temperature Probe 8 +thing-type.wlanthermo.esp32.group.channel8.description = This group contains all channels for temperature probe 8 +thing-type.wlanthermo.esp32.group.channel9.label = Temperature Probe 9 +thing-type.wlanthermo.esp32.group.channel9.description = This group contains all channels for temperature probe 9 +thing-type.wlanthermo.esp32.group.pit1.label = Pitmaster 1 +thing-type.wlanthermo.esp32.group.pit1.description = This group contains all channels for pitmaster channel 1 +thing-type.wlanthermo.esp32.group.pit2.label = Pitmaster 2 +thing-type.wlanthermo.esp32.group.pit2.description = This group contains all channels for pitmaster channel 2 +thing-type.wlanthermo.mini.label = WlanThermo Mini V1/V2 +thing-type.wlanthermo.mini.description = WlanThermo Mini with Raspberry Pi processor, such as Mini V1/V2 +thing-type.wlanthermo.mini.group.channel0.label = Temperature Probe 1 +thing-type.wlanthermo.mini.group.channel0.description = This group contains all channels for temperature probe 1 +thing-type.wlanthermo.mini.group.channel1.label = Temperature Probe 2 +thing-type.wlanthermo.mini.group.channel1.description = This group contains all channels for temperature probe 2 +thing-type.wlanthermo.mini.group.channel2.label = Temperature Probe 3 +thing-type.wlanthermo.mini.group.channel2.description = This group contains all channels for temperature probe 3 +thing-type.wlanthermo.mini.group.channel3.label = Temperature Probe 4 +thing-type.wlanthermo.mini.group.channel3.description = This group contains all channels for temperature probe 4 +thing-type.wlanthermo.mini.group.channel4.label = Temperature Probe 5 +thing-type.wlanthermo.mini.group.channel4.description = This group contains all channels for temperature probe 5 +thing-type.wlanthermo.mini.group.channel5.label = Temperature Probe 6 +thing-type.wlanthermo.mini.group.channel5.description = This group contains all channels for temperature probe 6 +thing-type.wlanthermo.mini.group.channel6.label = Temperature Probe 7 +thing-type.wlanthermo.mini.group.channel6.description = This group contains all channels for temperature probe 7 +thing-type.wlanthermo.mini.group.channel7.label = Temperature Probe 8 +thing-type.wlanthermo.mini.group.channel7.description = This group contains all channels for temperature probe 8 +thing-type.wlanthermo.mini.group.channel8.label = Temperature Probe 9 +thing-type.wlanthermo.mini.group.channel8.description = This group contains all channels for temperature probe 9 +thing-type.wlanthermo.mini.group.channel9.label = Temperature Probe 10 +thing-type.wlanthermo.mini.group.channel9.description = This group contains all channels for temperature probe 10 +thing-type.wlanthermo.mini.group.pit1.label = Pitmaster 1 +thing-type.wlanthermo.mini.group.pit1.description = This group contains all channels for pitmaster channel 1 +thing-type.wlanthermo.mini.group.pit2.label = Pitmaster 2 +thing-type.wlanthermo.mini.group.pit2.description = This group contains all channels for pitmaster channel 2 +thing-type.wlanthermo.nano.label = WlanThermo Nano +thing-type.wlanthermo.nano.description = WlanThermo Nano V1/V1+ +thing-type.wlanthermo.nano.group.channel1.label = Temperature Probe 1 +thing-type.wlanthermo.nano.group.channel1.description = This group contains all channels for temperature probe 1 +thing-type.wlanthermo.nano.group.channel2.label = Temperature Probe 2 +thing-type.wlanthermo.nano.group.channel2.description = This group contains all channels for temperature probe 2 +thing-type.wlanthermo.nano.group.channel3.label = Temperature Probe 3 +thing-type.wlanthermo.nano.group.channel3.description = This group contains all channels for temperature probe 3 +thing-type.wlanthermo.nano.group.channel4.label = Temperature Probe 4 +thing-type.wlanthermo.nano.group.channel4.description = This group contains all channels for temperature probe 4 +thing-type.wlanthermo.nano.group.channel5.label = Temperature Probe 5 +thing-type.wlanthermo.nano.group.channel5.description = This group contains all channels for temperature probe 5 +thing-type.wlanthermo.nano.group.channel6.label = Temperature Probe 6 +thing-type.wlanthermo.nano.group.channel6.description = This group contains all channels for temperature probe 6 +thing-type.wlanthermo.nano.group.channel7.label = Temperature Probe 7 +thing-type.wlanthermo.nano.group.channel7.description = This group contains all channels for temperature probe 7 +thing-type.wlanthermo.nano.group.channel8.label = Temperature Probe 8 +thing-type.wlanthermo.nano.group.channel8.description = This group contains all channels for temperature probe 8 +thing-type.wlanthermo.nano.group.pit1.label = Pitmaster 1 +thing-type.wlanthermo.nano.group.pit1.description = This group contains all channels for pitmaster channel 1 + +# thing types config + +thing-type.config.wlanthermo.esp32.ipAddress.label = Network Address +thing-type.config.wlanthermo.esp32.ipAddress.description = Network address of the WlanThermo Nano. +thing-type.config.wlanthermo.esp32.password.label = Password +thing-type.config.wlanthermo.esp32.password.description = Optional, only required for write access. Default: 'admin' +thing-type.config.wlanthermo.esp32.pollingInterval.label = Polling Interval +thing-type.config.wlanthermo.esp32.pollingInterval.description = Seconds between fetching values from the WlanThermo Nano. +thing-type.config.wlanthermo.esp32.username.label = Username +thing-type.config.wlanthermo.esp32.username.description = Optional, only required for write access. Default: 'admin' +thing-type.config.wlanthermo.mini.ipAddress.label = Network Address +thing-type.config.wlanthermo.mini.ipAddress.description = Network address of the WlanThermo Mini. +thing-type.config.wlanthermo.mini.pollingInterval.label = Polling Interval +thing-type.config.wlanthermo.mini.pollingInterval.description = Seconds between fetching values from the WlanThermo Mini. +thing-type.config.wlanthermo.nano.ipAddress.label = Network Address +thing-type.config.wlanthermo.nano.ipAddress.description = Network address of the WlanThermo Nano. +thing-type.config.wlanthermo.nano.password.label = Password +thing-type.config.wlanthermo.nano.password.description = Optional, only required for write access. Default: 'admin' +thing-type.config.wlanthermo.nano.pollingInterval.label = Polling Interval +thing-type.config.wlanthermo.nano.pollingInterval.description = Seconds between fetching values from the WlanThermo Nano. +thing-type.config.wlanthermo.nano.username.label = Username +thing-type.config.wlanthermo.nano.username.description = Optional, only required for write access. Default: 'admin' + +# channel group types + +channel-group-type.wlanthermo.cg_pitmaster_esp32.label = Pitmaster +channel-group-type.wlanthermo.cg_pitmaster_mini.label = Pitmaster Mini +channel-group-type.wlanthermo.cg_pitmaster_nano.label = Pitmaster Nano +channel-group-type.wlanthermo.cg_system_esp32.label = System Channels +channel-group-type.wlanthermo.cg_system_esp32.description = This group contains all system channels +channel-group-type.wlanthermo.cg_system_mini.label = System Channel +channel-group-type.wlanthermo.cg_system_mini.description = This group contains all system channels +channel-group-type.wlanthermo.cg_system_nano.label = System Channel +channel-group-type.wlanthermo.cg_system_nano.description = This group contains all system channels +channel-group-type.wlanthermo.cg_temperature_esp32.label = Temperature Sensor +channel-group-type.wlanthermo.cg_temperature_mini.label = Sensor Mini +channel-group-type.wlanthermo.cg_temperature_nano.label = Sensor Nano + +# channel types + +channel-type.wlanthermo.alarm_device.label = Alarm Buzzer +channel-type.wlanthermo.alarm_device_ro.label = Alarm Buzzer +channel-type.wlanthermo.alarm_openhab.label = OpenHAB Alarm Trigger +channel-type.wlanthermo.alarm_openhab_high.label = High Temperature Alarm +channel-type.wlanthermo.alarm_openhab_low.label = Low Temperature Alarm +channel-type.wlanthermo.alarm_push.label = Push-Alarm +channel-type.wlanthermo.channel_id.label = Temperature Channel ID +channel-type.wlanthermo.channel_id_ro.label = Channel ID +channel-type.wlanthermo.charging.label = Charging +channel-type.wlanthermo.color.label = Color +channel-type.wlanthermo.color_name_esp32.label = Color +channel-type.wlanthermo.color_name_esp32.state.option.#FFFF00 = yellow +channel-type.wlanthermo.color_name_esp32.state.option.#FFC002 = dark yellow +channel-type.wlanthermo.color_name_esp32.state.option.#00FF00 = green +channel-type.wlanthermo.color_name_esp32.state.option.#FFFFFF = white +channel-type.wlanthermo.color_name_esp32.state.option.#FF1DC4 = pink +channel-type.wlanthermo.color_name_esp32.state.option.#E46C0A = orange +channel-type.wlanthermo.color_name_esp32.state.option.#C3D69B = olive +channel-type.wlanthermo.color_name_esp32.state.option.#0FE6F1 = light blue +channel-type.wlanthermo.color_name_esp32.state.option.#0000FF = blue +channel-type.wlanthermo.color_name_esp32.state.option.#03A923 = dark green +channel-type.wlanthermo.color_name_esp32.state.option.#C84B32 = brown +channel-type.wlanthermo.color_name_esp32.state.option.#FF9B69 = light brown +channel-type.wlanthermo.color_name_esp32.state.option.#5082BE = dark blue +channel-type.wlanthermo.color_name_esp32.state.option.#FFB1D0 = light pink +channel-type.wlanthermo.color_name_esp32.state.option.#A6EF03 = light green +channel-type.wlanthermo.color_name_esp32.state.option.#D42A6B = dark pink +channel-type.wlanthermo.color_name_esp32.state.option.#FFDA8F = beige +channel-type.wlanthermo.color_name_esp32.state.option.#00B0F0 = azure +channel-type.wlanthermo.color_name_esp32.state.option.#948A54 = dark olive +channel-type.wlanthermo.color_name_mini_ro.label = Color Name +channel-type.wlanthermo.color_name_nano.label = Color +channel-type.wlanthermo.color_name_nano.state.option.niagara = Niagara +channel-type.wlanthermo.color_name_nano.state.option.rosa = Rosa +channel-type.wlanthermo.color_name_nano.state.option.lapis blue = Lapis Blue +channel-type.wlanthermo.color_name_nano.state.option.orange = Orange +channel-type.wlanthermo.color_name_nano.state.option.lila = Lila +channel-type.wlanthermo.color_name_nano.state.option.red = Red +channel-type.wlanthermo.color_name_nano.state.option.green = Green +channel-type.wlanthermo.color_name_nano.state.option.gold = Gold +channel-type.wlanthermo.color_name_nano.state.option.kale = Kale +channel-type.wlanthermo.color_name_nano.state.option.brown = Brown +channel-type.wlanthermo.color_ro.label = Color +channel-type.wlanthermo.cpu_load.label = CPU Load +channel-type.wlanthermo.duty_cycle.label = Duty Cycle / Control Out +channel-type.wlanthermo.duty_cycle_ro.label = Duty Cycle / Control Out +channel-type.wlanthermo.enabled.label = Enabled +channel-type.wlanthermo.lid_open.label = Lid Open +channel-type.wlanthermo.name.label = Name +channel-type.wlanthermo.name_ro.label = Name +channel-type.wlanthermo.pid_id.label = PID Profile ID +channel-type.wlanthermo.pitmaster_type.label = State +channel-type.wlanthermo.pitmaster_type.state.option.off = Off +channel-type.wlanthermo.pitmaster_type.state.option.manual = Manual +channel-type.wlanthermo.pitmaster_type.state.option.auto = Auto +channel-type.wlanthermo.rssi.label = RSSI in dBm +channel-type.wlanthermo.temperature.label = Current Temperature +channel-type.wlanthermo.temperature_max.label = High Temperature Alarm +channel-type.wlanthermo.temperature_max_ro.label = High Temperature Alarm +channel-type.wlanthermo.temperature_min.label = Low Temperature Alarm +channel-type.wlanthermo.temperature_min_ro.label = Low Temperature Alarm +channel-type.wlanthermo.temperature_setpoint.label = Setpoint Temperature +channel-type.wlanthermo.temperature_setpoint_ro.label = Setpoint Temperature +channel-type.wlanthermo.typ.label = Type diff --git a/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/i18n/wled.properties b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/i18n/wled.properties new file mode 100644 index 0000000000000..2ad26997e0472 --- /dev/null +++ b/bundles/org.openhab.binding.wled/src/main/resources/OH-INF/i18n/wled.properties @@ -0,0 +1,92 @@ +# binding + +binding.wled.name = WLED Binding +binding.wled.description = This is the binding for WLED + +# thing types + +thing-type.wled.wled.label = WLED String +thing-type.wled.wled.description = A WLED string of LEDs + +# thing types config + +thing-type.config.wled.wled.address.label = Address +thing-type.config.wled.wled.address.description = Use this format http://192.168.1.2:80 +thing-type.config.wled.wled.pollTime.label = Poll States +thing-type.config.wled.wled.pollTime.description = Time in seconds of how often to fetch the state of the LEDs. +thing-type.config.wled.wled.saturationThreshold.label = Saturation Threshold +thing-type.config.wled.wled.saturationThreshold.description = This feature allows you to specify a number that if the saturation drops below, will trigger white. +thing-type.config.wled.wled.segmentIndex.label = Segment Index +thing-type.config.wled.wled.segmentIndex.description = Leave this as 0 if you are not using segments, otherwise set this to the segment index number that you wish to control. + +# channel types + +channel-type.wled.fx.label = Effect +channel-type.wled.fx.description = Use the built in FX +channel-type.wled.grouping.label = Grouping +channel-type.wled.grouping.description = How many consecutive LEDs of the same segment will be grouped to the same color +channel-type.wled.intensity.label = FX Intensity +channel-type.wled.intensity.description = Change the intensity of the FX +channel-type.wled.liveOverride.label = Live Override +channel-type.wled.liveOverride.description = Live data override. 0 is off, 1 is override until live data ends, 2 is override until ESP reboot +channel-type.wled.liveOverride.state.option.0 = Off +channel-type.wled.liveOverride.state.option.1 = Override Live +channel-type.wled.liveOverride.state.option.2 = Until Reboot +channel-type.wled.masterControls.label = Master Controls +channel-type.wled.masterControls.description = Allows you to exit FX mode and use the LEDS like a normal light +channel-type.wled.mirror.label = Mirror Effect +channel-type.wled.mirror.description = Mirror the effect for this segment +channel-type.wled.palettes.label = Palettes +channel-type.wled.palettes.description = Change the colours used by the FX +channel-type.wled.playlists.label = Playlists +channel-type.wled.playlists.description = The currently playing play list +channel-type.wled.presetCycle.label = Preset Cycle +channel-type.wled.presetCycle.description = Cycle through the saved presets +channel-type.wled.presetDuration.label = Preset Duration +channel-type.wled.presetDuration.description = Time for how long to show each preset for before moving to the next +channel-type.wled.presets.label = Presets +channel-type.wled.presets.description = Auto rotate or change to a saved preset +channel-type.wled.presets.state.option.1 = Preset 1 +channel-type.wled.presets.state.option.2 = Preset 2 +channel-type.wled.presets.state.option.3 = Preset 3 +channel-type.wled.presets.state.option.4 = Preset 4 +channel-type.wled.presets.state.option.5 = Preset 5 +channel-type.wled.presets.state.option.6 = Preset 6 +channel-type.wled.presets.state.option.7 = Preset 7 +channel-type.wled.presets.state.option.8 = Preset 8 +channel-type.wled.presets.state.option.9 = Preset 9 +channel-type.wled.presets.state.option.10 = Preset 10 +channel-type.wled.presets.state.option.11 = Preset 11 +channel-type.wled.presets.state.option.12 = Preset 12 +channel-type.wled.presets.state.option.13 = Preset 13 +channel-type.wled.presets.state.option.14 = Preset 14 +channel-type.wled.presets.state.option.15 = Preset 15 +channel-type.wled.presets.state.option.16 = Preset 16 +channel-type.wled.primaryColor.label = Primary Color +channel-type.wled.primaryColor.description = Allows you to change the primary color used in FX +channel-type.wled.primaryWhite.label = Primary White +channel-type.wled.primaryWhite.description = Changes the brightness of the primary white LED +channel-type.wled.reverse.label = Reverse Direction +channel-type.wled.reverse.description = Reverse the direction of the current segment +channel-type.wled.secondaryColor.label = Secondary Color +channel-type.wled.secondaryColor.description = Allows you to change the secondary color used in FX +channel-type.wled.secondaryWhite.label = Secondary White +channel-type.wled.secondaryWhite.description = Changes the brightness of the secondary white LED +channel-type.wled.segmentBrightness.label = Segment Brightness +channel-type.wled.segmentBrightness.description = Changes the brightness of the whole segment +channel-type.wled.sleep.label = Sleep Timer +channel-type.wled.sleep.description = Fade the level of light and turn off after set time +channel-type.wled.spacing.label = Spacing +channel-type.wled.spacing.description = How many LEDs are turned off and skipped between each group +channel-type.wled.speed.label = FX Speed +channel-type.wled.speed.description = Change the speed of the FX +channel-type.wled.syncReceive.label = Sync Receive +channel-type.wled.syncReceive.description = Allows UDP packets from other WLED lights to control this one. +channel-type.wled.syncSend.label = Sync Send +channel-type.wled.syncSend.description = Sends UDP packets that tell other WLED lights to follow this one. +channel-type.wled.tertiaryColor.label = Tertiary Color +channel-type.wled.tertiaryColor.description = Allows you to change the third color used in FX +channel-type.wled.tertiaryWhite.label = Tertiary White +channel-type.wled.tertiaryWhite.description = Changes the brightness of the third white LED +channel-type.wled.transformTime.label = Transform Time +channel-type.wled.transformTime.description = Time it takes to change/fade from one look to the next. diff --git a/bundles/org.openhab.binding.wolfsmartset/src/main/resources/OH-INF/i18n/wolfsmartset.properties b/bundles/org.openhab.binding.wolfsmartset/src/main/resources/OH-INF/i18n/wolfsmartset.properties new file mode 100644 index 0000000000000..b42be5e09a58f --- /dev/null +++ b/bundles/org.openhab.binding.wolfsmartset/src/main/resources/OH-INF/i18n/wolfsmartset.properties @@ -0,0 +1,37 @@ +# binding + +binding.wolfsmartset.name = WolfSmartset Binding +binding.wolfsmartset.description = This is the binding for WolfSmartset smart systems. + +# thing types + +thing-type.wolfsmartset.account.label = WolfSmartset Account +thing-type.wolfsmartset.account.description = Represents an account at WolfSmartset +thing-type.wolfsmartset.system.label = WolfSmartset System +thing-type.wolfsmartset.system.description = An WolfSmartset system +thing-type.wolfsmartset.unit.label = WolfSmartset Unit +thing-type.wolfsmartset.unit.description = An WolfSmartset remote unit + +# thing types config + +thing-type.config.wolfsmartset.account.discoveryEnabled.label = Background Discovery +thing-type.config.wolfsmartset.account.discoveryEnabled.description = Enable/disable automatic discovery +thing-type.config.wolfsmartset.account.password.label = Password +thing-type.config.wolfsmartset.account.refreshIntervalStructure.label = Structure Refresh Interval +thing-type.config.wolfsmartset.account.refreshIntervalStructure.description = Specifies the refresh interval in minutes +thing-type.config.wolfsmartset.account.refreshIntervalValues.label = States Refresh Interval +thing-type.config.wolfsmartset.account.refreshIntervalValues.description = Specifies time in seconds to refresh states +thing-type.config.wolfsmartset.account.username.label = Username +thing-type.config.wolfsmartset.system.systemId.label = System ID +thing-type.config.wolfsmartset.system.systemId.description = System ID assigned to this system by WolfSmartset +thing-type.config.wolfsmartset.unit.unitId.label = Unit Id +thing-type.config.wolfsmartset.unit.unitId.description = Id assigned to this unit (e.g. rs:101) + +# channel types + +channel-type.wolfsmartset.barometric-pressure.label = Pressure +channel-type.wolfsmartset.contact.label = Contact +channel-type.wolfsmartset.datetime.label = Date Time +channel-type.wolfsmartset.number.label = Number +channel-type.wolfsmartset.string.label = String +channel-type.wolfsmartset.temperature.label = Temperature diff --git a/bundles/org.openhab.binding.xmppclient/src/main/resources/OH-INF/i18n/xmppclient.properties b/bundles/org.openhab.binding.xmppclient/src/main/resources/OH-INF/i18n/xmppclient.properties new file mode 100644 index 0000000000000..70efda676bf4a --- /dev/null +++ b/bundles/org.openhab.binding.xmppclient/src/main/resources/OH-INF/i18n/xmppclient.properties @@ -0,0 +1,34 @@ +# binding + +binding.xmppclient.name = XMPPClient Binding +binding.xmppclient.description = This is the binding for XMPP (Jabber) notifications. + +# thing types + +thing-type.xmppclient.xmppBridge.label = XMPP Client +thing-type.xmppclient.xmppBridge.description = A connection to a XMPP server + +# thing types config + +thing-type.config.xmppclient.xmppBridge.domain.label = Domain +thing-type.config.xmppclient.xmppBridge.domain.description = The XMPP Domain (the right side of JID, e.g. example.com for JID user@example.com) +thing-type.config.xmppclient.xmppBridge.host.label = Server Hostname/IP +thing-type.config.xmppclient.xmppBridge.host.description = The IP/Hostname of the XMPP server (if not specified, the Domain will be used) +thing-type.config.xmppclient.xmppBridge.password.label = Password +thing-type.config.xmppclient.xmppBridge.password.description = The XMPP Password +thing-type.config.xmppclient.xmppBridge.port.label = XMPP Server Port +thing-type.config.xmppclient.xmppBridge.port.description = The default port is 5222. +thing-type.config.xmppclient.xmppBridge.username.label = Username +thing-type.config.xmppclient.xmppBridge.username.description = The XMPP Username (the left side of JID, e.g. user for JID user@example.com) + +# channel types + +channel-type.xmppclient.publishTrigger.label = Publish Trigger +channel-type.xmppclient.publishTrigger.description = This channel is triggered when a message is received on the configured XMPP account. The event payload will be the received text. + +# channel types config + +channel-type.config.xmppclient.publishTrigger.payload.label = Payload Condition +channel-type.config.xmppclient.publishTrigger.payload.description = An optional condition on the value +channel-type.config.xmppclient.publishTrigger.separator.label = Separator Character +channel-type.config.xmppclient.publishTrigger.separator.description = The trigger channel payload usually only contains the received text. If you define a separator character, for example '#', the sender UID and received text will be in the trigger channel payload. For example: pavel@example.com#My Message Text. diff --git a/bundles/org.openhab.binding.yamahareceiver/src/main/resources/OH-INF/i18n/yamahareceiver.properties b/bundles/org.openhab.binding.yamahareceiver/src/main/resources/OH-INF/i18n/yamahareceiver.properties new file mode 100644 index 0000000000000..a041c68f91f9e --- /dev/null +++ b/bundles/org.openhab.binding.yamahareceiver/src/main/resources/OH-INF/i18n/yamahareceiver.properties @@ -0,0 +1,181 @@ +# binding + +binding.yamahareceiver.name = YamahaReceiver Binding +binding.yamahareceiver.description = For all network enabled Yamaha receivers. + +# thing types + +thing-type.yamahareceiver.yamahaAV.label = Yamaha Receiver +thing-type.yamahareceiver.yamahaAV.description = Yamaha Receiver of product line CX-A5000, RX-A30xx, RX-A20xx, RX-A10xx, RX-Vxxx, RX-Z7, DSP-Z7, RX-S600, HTR-xxxx +thing-type.yamahareceiver.zone.label = Yamaha Receiver Zone +thing-type.yamahareceiver.zone.description = Yamaha Receiver Zone + +# thing types config + +thing-type.config.yamahareceiver.yamahaAV.albumUrl.label = Album URL +thing-type.config.yamahareceiver.yamahaAV.albumUrl.description = When the album image is not provided by the Yamaha input source, you can specify the default image URL to apply. +thing-type.config.yamahareceiver.yamahaAV.host.label = Address +thing-type.config.yamahareceiver.yamahaAV.host.description = The address of the AVR to control. +thing-type.config.yamahareceiver.yamahaAV.inputMapping.label = Input Mapping +thing-type.config.yamahareceiver.yamahaAV.inputMapping.description = Some Yamaha models return different input values on status update than required in the change input commands. For example: HDMI1 command may be reported as HDMI_1 after status update. There are other related edge cases (USB, iPad_USB). This setting allows the user to customize the return input mapping to meet their AVR model. The setting is a comma separated list of value mapping from to. Example: HDMI_1=HDMI1,HDMI 1=HDMI1,HDMI1=HDMI1 +thing-type.config.yamahareceiver.yamahaAV.port.label = Port +thing-type.config.yamahareceiver.yamahaAV.port.description = The API port of the AVR to control. Usually 80 +thing-type.config.yamahareceiver.yamahaAV.refreshInterval.label = Refresh Interval +thing-type.config.yamahareceiver.yamahaAV.refreshInterval.description = Refresh interval in seconds. +thing-type.config.yamahareceiver.zone.volumeDbMax.label = Maximum Volume +thing-type.config.yamahareceiver.zone.volumeDbMax.description = Highest volume in dB. +thing-type.config.yamahareceiver.zone.volumeDbMin.label = Minimum Volume +thing-type.config.yamahareceiver.zone.volumeDbMin.description = Lowest volume in dB. +thing-type.config.yamahareceiver.zone.volumeRelativeChangeFactor.label = Relative Volume Change +thing-type.config.yamahareceiver.zone.volumeRelativeChangeFactor.description = Relative volume change in percent. +thing-type.config.yamahareceiver.zone.zone.label = Zone +thing-type.config.yamahareceiver.zone.zone.description = The zone can be Main_Zone, ZONE_2, ZONE_3, ZONE_4 depending on your device. + +# channel group types + +channel-group-type.yamahareceiver.navigation_channels.label = Navigation Control +channel-group-type.yamahareceiver.navigation_channels.description = Allow to navigate for inputs like USB, iPOD, NET_RADIO +channel-group-type.yamahareceiver.playback_channels.label = Playback Control +channel-group-type.yamahareceiver.playback_channels.description = Control the playback for the current zone and allow to select preset channels +channel-group-type.yamahareceiver.zone_channels.label = Zone Control +channel-group-type.yamahareceiver.zone_channels.description = Control the zone + +# channel types + +channel-type.yamahareceiver.defaultpreset.label = Preset +channel-type.yamahareceiver.defaultpreset.description = Select a saved channel by its preset number +channel-type.yamahareceiver.defaultpreset.state.option.1 = Item_1 +channel-type.yamahareceiver.defaultpreset.state.option.2 = Item_2 +channel-type.yamahareceiver.defaultpreset.state.option.3 = Item_3 +channel-type.yamahareceiver.defaultpreset.state.option.4 = Item_4 +channel-type.yamahareceiver.defaultpreset.state.option.5 = Item_5 +channel-type.yamahareceiver.defaultpreset.state.option.6 = Item_6 +channel-type.yamahareceiver.defaultpreset.state.option.7 = Item_7 +channel-type.yamahareceiver.defaultpreset.state.option.8 = Item_8 +channel-type.yamahareceiver.defaultpreset.state.option.9 = Item_9 +channel-type.yamahareceiver.defaultpreset.state.option.10 = Item_10 +channel-type.yamahareceiver.defaultpreset.state.option.11 = Item_11 +channel-type.yamahareceiver.defaultpreset.state.option.12 = Item_12 +channel-type.yamahareceiver.defaultpreset.state.option.13 = Item_13 +channel-type.yamahareceiver.defaultpreset.state.option.14 = Item_14 +channel-type.yamahareceiver.defaultpreset.state.option.15 = Item_15 +channel-type.yamahareceiver.defaultpreset.state.option.16 = Item_16 +channel-type.yamahareceiver.defaultpreset.state.option.17 = Item_17 +channel-type.yamahareceiver.defaultpreset.state.option.18 = Item_18 +channel-type.yamahareceiver.defaultpreset.state.option.19 = Item_19 +channel-type.yamahareceiver.defaultpreset.state.option.20 = Item_20 +channel-type.yamahareceiver.defaultpreset.state.option.21 = Item_21 +channel-type.yamahareceiver.defaultpreset.state.option.22 = Item_22 +channel-type.yamahareceiver.defaultpreset.state.option.23 = Item_23 +channel-type.yamahareceiver.defaultpreset.state.option.24 = Item_24 +channel-type.yamahareceiver.defaultpreset.state.option.25 = Item_25 +channel-type.yamahareceiver.defaultpreset.state.option.26 = Item_26 +channel-type.yamahareceiver.defaultpreset.state.option.27 = Item_27 +channel-type.yamahareceiver.defaultpreset.state.option.28 = Item_28 +channel-type.yamahareceiver.defaultpreset.state.option.29 = Item_29 +channel-type.yamahareceiver.defaultpreset.state.option.30 = Item_30 +channel-type.yamahareceiver.defaultpreset.state.option.31 = Item_31 +channel-type.yamahareceiver.defaultpreset.state.option.32 = Item_32 +channel-type.yamahareceiver.defaultpreset.state.option.33 = Item_33 +channel-type.yamahareceiver.defaultpreset.state.option.34 = Item_34 +channel-type.yamahareceiver.defaultpreset.state.option.35 = Item_35 +channel-type.yamahareceiver.defaultpreset.state.option.36 = Item_36 +channel-type.yamahareceiver.defaultpreset.state.option.37 = Item_37 +channel-type.yamahareceiver.defaultpreset.state.option.38 = Item_38 +channel-type.yamahareceiver.defaultpreset.state.option.39 = Item_39 +channel-type.yamahareceiver.defaultpreset.state.option.40 = Item_40 +channel-type.yamahareceiver.dialogueLevel.label = Dialogue Level +channel-type.yamahareceiver.dialogueLevel.description = Set the dialogue level +channel-type.yamahareceiver.hdmi1Out.label = HDMI1 Output +channel-type.yamahareceiver.hdmi1Out.description = Switch the HDMI1 Output ON/OFF +channel-type.yamahareceiver.hdmi2Out.label = HDMI2 Output +channel-type.yamahareceiver.hdmi2Out.description = Switch the HDMI2 Output ON/OFF +channel-type.yamahareceiver.mute.label = Mute +channel-type.yamahareceiver.mute.description = Enable/Disable Mute on the AVR +channel-type.yamahareceiver.navigation_back.label = Back +channel-type.yamahareceiver.navigation_back.description = Go one level back +channel-type.yamahareceiver.navigation_backtoroot.label = Back to Root +channel-type.yamahareceiver.navigation_backtoroot.description = Go back to the root menu +channel-type.yamahareceiver.navigation_current_item.label = Item +channel-type.yamahareceiver.navigation_current_item.description = Shows the current item number +channel-type.yamahareceiver.navigation_leftright.label = Left/Right +channel-type.yamahareceiver.navigation_leftright.description = Allows to move the cursor left/right +channel-type.yamahareceiver.navigation_level.label = Menu Depth +channel-type.yamahareceiver.navigation_level.description = Hierarchical level +channel-type.yamahareceiver.navigation_menu.label = Menu +channel-type.yamahareceiver.navigation_menu.description = Shows the current navigation menu and allows to change to a channel by a full path. For example for net radio: Bookmarks/__My_Favorites/radio_station_name. You can also just use the station name without a full path if the AVR is in that navigation menu already. +channel-type.yamahareceiver.navigation_select.label = Select +channel-type.yamahareceiver.navigation_select.description = Select the current cursor item +channel-type.yamahareceiver.navigation_total_items.label = Items +channel-type.yamahareceiver.navigation_total_items.description = Shows the maximum item number +channel-type.yamahareceiver.navigation_updown.label = Up/Down +channel-type.yamahareceiver.navigation_updown.description = Allows to move the cursor up/down +channel-type.yamahareceiver.party_mode.label = Party Mode +channel-type.yamahareceiver.party_mode.description = Party mode ON/OFF +channel-type.yamahareceiver.party_mode_mute.label = Party Mode Mute +channel-type.yamahareceiver.party_mode_mute.description = Mute when party mode +channel-type.yamahareceiver.party_mode_volume.label = Party Mode Volume Up/Down +channel-type.yamahareceiver.party_mode_volume.description = Increase or decrease of party mode volume +channel-type.yamahareceiver.playback.label = Playback Control +channel-type.yamahareceiver.playback.description = Control the playback of the current input. Can also be used as Play/Pause and Next/Previous Type +channel-type.yamahareceiver.playback.state.option.Play = Play +channel-type.yamahareceiver.playback.state.option.Pause = Pause +channel-type.yamahareceiver.playback.state.option.Stop = Stop +channel-type.yamahareceiver.playback.state.option.FastForward = Fast Forward +channel-type.yamahareceiver.playback.state.option.Rewind = Rewind +channel-type.yamahareceiver.playback.state.option.Next = Next +channel-type.yamahareceiver.playback.state.option.Previous = Previous +channel-type.yamahareceiver.playback_album.label = Album +channel-type.yamahareceiver.playback_album.description = Album +channel-type.yamahareceiver.playback_artist.label = Artist +channel-type.yamahareceiver.playback_artist.description = Artist +channel-type.yamahareceiver.playback_song.label = Title +channel-type.yamahareceiver.playback_song.description = Track title +channel-type.yamahareceiver.playback_song_image_url.label = Track Picture URL +channel-type.yamahareceiver.playback_song_image_url.description = Track picture URL +channel-type.yamahareceiver.playback_station.label = Station +channel-type.yamahareceiver.playback_station.description = Current station name +channel-type.yamahareceiver.power.label = Power +channel-type.yamahareceiver.power.description = Power the AVR or zone ON/OFF +channel-type.yamahareceiver.scene.label = Scene +channel-type.yamahareceiver.scene.description = Set the active scene of the AVR +channel-type.yamahareceiver.scene.state.option.Scene 1 = Scene 1 +channel-type.yamahareceiver.scene.state.option.Scene 2 = Scene 2 +channel-type.yamahareceiver.scene.state.option.Scene 3 = Scene 3 +channel-type.yamahareceiver.scene.state.option.Scene 4 = Scene 4 +channel-type.yamahareceiver.surroundProgram.label = Surround Program +channel-type.yamahareceiver.surroundProgram.description = Select the surround program of the AVR +channel-type.yamahareceiver.surroundProgram.state.option.Music Video = Music Video +channel-type.yamahareceiver.surroundProgram.state.option.The Roxy Theater = The Roxy Theater +channel-type.yamahareceiver.surroundProgram.state.option.Cellar Club = Cellar Club +channel-type.yamahareceiver.surroundProgram.state.option.Hall in Vienna = Hall in Vienna +channel-type.yamahareceiver.surroundProgram.state.option.Hall in Munich = Hall in Munich +channel-type.yamahareceiver.surroundProgram.state.option.Roleplaying Game = Roleplaying Game +channel-type.yamahareceiver.surroundProgram.state.option.Action Game = Action Game +channel-type.yamahareceiver.surroundProgram.state.option.Sports = Sports +channel-type.yamahareceiver.surroundProgram.state.option.Mono Movie = Mono Movie +channel-type.yamahareceiver.surroundProgram.state.option.Drama = Drama +channel-type.yamahareceiver.surroundProgram.state.option.Adventure = Adventure +channel-type.yamahareceiver.surroundProgram.state.option.Sci-Fi = Sci-Fi +channel-type.yamahareceiver.surroundProgram.state.option.Spectacle = Spectacle +channel-type.yamahareceiver.surroundProgram.state.option.Standard = Standard +channel-type.yamahareceiver.surroundProgram.state.option.Pro Logic = Pro Logic +channel-type.yamahareceiver.surroundProgram.state.option.Neo:6 Music = Neo:6 Music +channel-type.yamahareceiver.surroundProgram.state.option.Neo:6 Cinema = Neo:6 Cinema +channel-type.yamahareceiver.surroundProgram.state.option.PLII[x] Game = PLII[x] Game +channel-type.yamahareceiver.surroundProgram.state.option.PLII[x] Music = PLII[x] Music +channel-type.yamahareceiver.surroundProgram.state.option.PLII[x] Movie = PLII[x] Movie +channel-type.yamahareceiver.surroundProgram.state.option.7ch Enhancer = 7ch Enhancer +channel-type.yamahareceiver.surroundProgram.state.option.2ch Stereo = 2ch Stereo +channel-type.yamahareceiver.surroundProgram.state.option.5ch Stereo = 5ch Stereo +channel-type.yamahareceiver.surroundProgram.state.option.7ch Stereo = 7ch Stereo +channel-type.yamahareceiver.surroundProgram.state.option.Straight = Straight +channel-type.yamahareceiver.surroundProgram.state.option.Straight Enhancer = Straight Enhancer +channel-type.yamahareceiver.tuner_band.label = Tuner Band +channel-type.yamahareceiver.tuner_band.description = Select a DAB Tuner band +channel-type.yamahareceiver.tuner_band.state.option.FM = FM +channel-type.yamahareceiver.tuner_band.state.option.DAB = DAB+ +channel-type.yamahareceiver.volume.label = Volume +channel-type.yamahareceiver.volume.description = Set the volume level +channel-type.yamahareceiver.volumeDB.label = Volume in dB +channel-type.yamahareceiver.volumeDB.description = Set the volume level (dB) diff --git a/bundles/org.openhab.binding.yeelight/src/main/resources/OH-INF/i18n/yeelight.properties b/bundles/org.openhab.binding.yeelight/src/main/resources/OH-INF/i18n/yeelight.properties new file mode 100644 index 0000000000000..e95c9e145fb7d --- /dev/null +++ b/bundles/org.openhab.binding.yeelight/src/main/resources/OH-INF/i18n/yeelight.properties @@ -0,0 +1,45 @@ +# binding + +binding.yeelight.name = Yeelight Binding +binding.yeelight.description = This is the binding for Yeelight products. + +# thing types + +thing-type.yeelight.ceiling.label = Yeelight LED Ceiling +thing-type.yeelight.ceiling.description = Yeelight LED Ceiling lamp +thing-type.yeelight.ceiling1.label = Yeelight LED Ceiling (v1) +thing-type.yeelight.ceiling1.description = Yeelight LED Ceiling lamp with Night Mode +thing-type.yeelight.ceiling4.label = Yeelight LED Ceiling (v4) +thing-type.yeelight.ceiling4.description = Yeelight LED Ceiling with ambient light +thing-type.yeelight.ct_bulb.label = Yeelight White LED Bulb v2 +thing-type.yeelight.ct_bulb.description = Yeelight White LED Bulb v2 +thing-type.yeelight.desklamp.label = Yeelight MI LED Desk Lamp +thing-type.yeelight.desklamp.description = Yeelight MI LED Desk Lamp +thing-type.yeelight.dolphin.label = Yeelight White LED Bulb +thing-type.yeelight.dolphin.description = Yeelight White LED Bulb +thing-type.yeelight.stripe.label = Yeelight Color LED Stripe +thing-type.yeelight.stripe.description = Yeelight Color LED Stripe +thing-type.yeelight.wonder.label = Yeelight Color LED Bulb +thing-type.yeelight.wonder.description = Yeelight Color LED Bulb + +# thing types config + +thing-type.config.yeelight.device.deviceId.label = Device ID +thing-type.config.yeelight.device.deviceId.description = Id of the Yeelight device to connect with. +thing-type.config.yeelight.device.duration.label = Duration +thing-type.config.yeelight.device.duration.description = Duration of transition of events such as on/off, change of brightness and change of color, in milliseconds. + +# channel types + +channel-type.yeelight.backgroundColor.label = Background Color +channel-type.yeelight.backgroundColor.description = The color channel allows to control the color of a light. +channel-type.yeelight.brightness.label = Brightness +channel-type.yeelight.brightness.description = The brightness channel allows to control the brightness of a light. It is also possible to switch the light on and off. +channel-type.yeelight.color.label = Color +channel-type.yeelight.color.description = The color channel allows to control the color of a light. +channel-type.yeelight.colorTemperature.label = Color Temperature +channel-type.yeelight.colorTemperature.description = The CT channel allows to control the CT of a light. +channel-type.yeelight.command.label = Command +channel-type.yeelight.command.description = Send a command directly to the device. For advanced users only. +channel-type.yeelight.nightlight.label = nightlight +channel-type.yeelight.nightlight.description = The nightlight channel allows to switch to nightlight mode. diff --git a/bundles/org.openhab.binding.yioremote/src/main/resources/OH-INF/i18n/yioremote.properties b/bundles/org.openhab.binding.yioremote/src/main/resources/OH-INF/i18n/yioremote.properties new file mode 100644 index 0000000000000..78feab72a2c94 --- /dev/null +++ b/bundles/org.openhab.binding.yioremote/src/main/resources/OH-INF/i18n/yioremote.properties @@ -0,0 +1,30 @@ +# binding + +binding.yioremote.name = YIOremote Binding +binding.yioremote.description = This is the binding for YIOremote. + +# thing types + +thing-type.yioremote.yioRemoteDock.label = YIO Remote Dock +thing-type.yioremote.yioRemoteDock.description = YIOremote Dock Binding Thing + +# thing types config + +thing-type.config.yioremote.yioRemoteDock.accessToken.label = Access Token +thing-type.config.yioremote.yioRemoteDock.accessToken.description = The authentication token for the access currently 0 +thing-type.config.yioremote.yioRemoteDock.host.label = Network Address +thing-type.config.yioremote.yioRemoteDock.host.description = Network address of the YIO Remote Dock + +# channel group types + +channel-group-type.yioremote.input.label = Inputs +channel-group-type.yioremote.input.description = The channels used for Input +channel-group-type.yioremote.output.label = Outputs +channel-group-type.yioremote.output.description = The channels used for Output + +# channel types + +channel-type.yioremote.receiverswitch.label = Receiver Switch +channel-type.yioremote.receiverswitch.description = The switch to enable disable the IR receiving diode/function +channel-type.yioremote.status.label = Status +channel-type.yioremote.status.description = The status of the YIO Dock. If the reciever is on than the recognized IR code will be displayed otherwise the IR send status is displayed of the last IR code send. diff --git a/bundles/org.openhab.binding.zoneminder/src/main/resources/OH-INF/i18n/zoneminder.properties b/bundles/org.openhab.binding.zoneminder/src/main/resources/OH-INF/i18n/zoneminder.properties new file mode 100644 index 0000000000000..650f596b65f60 --- /dev/null +++ b/bundles/org.openhab.binding.zoneminder/src/main/resources/OH-INF/i18n/zoneminder.properties @@ -0,0 +1,113 @@ +# binding + +binding.zoneminder.name = ZoneMinder Binding +binding.zoneminder.description = Binding for ZoneMinder video surveillance system + +# thing types + +thing-type.zoneminder.monitor.label = ZoneMinder Monitor +thing-type.zoneminder.monitor.description = Represents a ZoneMinder monitor +thing-type.zoneminder.monitor.channel.dayEvents.label = Day Events +thing-type.zoneminder.monitor.channel.hourEvents.label = Hour Events +thing-type.zoneminder.monitor.channel.imageUrl.label = Image URL +thing-type.zoneminder.monitor.channel.monthEvents.label = Month Events +thing-type.zoneminder.monitor.channel.totalEvents.label = Total Events +thing-type.zoneminder.monitor.channel.videoUrl.label = Video URL +thing-type.zoneminder.monitor.channel.weekEvents.label = Week Events +thing-type.zoneminder.server.label = ZoneMinder Server +thing-type.zoneminder.server.description = Represents a ZoneMinder server +thing-type.zoneminder.server.channel.imageMonitorId.label = Image Monitor Id +thing-type.zoneminder.server.channel.imageMonitorId.description = Monitor ID for Image URL Channel +thing-type.zoneminder.server.channel.imageUrl.label = Image URL +thing-type.zoneminder.server.channel.videoMonitorId.label = Video Monitor Id +thing-type.zoneminder.server.channel.videoMonitorId.description = Monitor ID for Video URL Channel +thing-type.zoneminder.server.channel.videoUrl.label = Video URL + +# thing types config + +thing-type.config.zoneminder.monitor.alarmDuration.label = Alarm Duration +thing-type.config.zoneminder.monitor.alarmDuration.description = Duration in seconds after which the alarm will be turned off +thing-type.config.zoneminder.monitor.imageRefreshInterval.label = Image Refresh Interval +thing-type.config.zoneminder.monitor.imageRefreshInterval.description = Interval in seconds with which monitor image is refreshed +thing-type.config.zoneminder.monitor.monitorId.label = Monitor Id +thing-type.config.zoneminder.monitor.monitorId.description = Id of the monitor +thing-type.config.zoneminder.server.defaultAlarmDuration.label = Default Alarm Duration +thing-type.config.zoneminder.server.defaultAlarmDuration.description = Duration in seconds after which the alarm will be turned off +thing-type.config.zoneminder.server.defaultImageRefreshInterval.label = Default Image Refresh Interval +thing-type.config.zoneminder.server.defaultImageRefreshInterval.description = Interval in seconds at which monitor image snapshot will be updated +thing-type.config.zoneminder.server.discoveryEnabled.label = Background Discovery Enabled +thing-type.config.zoneminder.server.discoveryEnabled.description = Enable/disable background discovery of monitors +thing-type.config.zoneminder.server.group.auth-info.label = Authentication Information +thing-type.config.zoneminder.server.group.config-info.label = Bridge Configuration +thing-type.config.zoneminder.server.group.url-info.label = ZoneMinder URL Information +thing-type.config.zoneminder.server.host.label = Server +thing-type.config.zoneminder.server.host.description = ZoneMinder server name or IP address +thing-type.config.zoneminder.server.pass.label = Password +thing-type.config.zoneminder.server.pass.description = Password (if authentication enabled in ZoneMinder) +thing-type.config.zoneminder.server.portNumber.label = Port Number +thing-type.config.zoneminder.server.portNumber.description = Port Number (leave blank if Zoneminder installed on default port) +thing-type.config.zoneminder.server.refreshInterval.label = Refresh Interval +thing-type.config.zoneminder.server.refreshInterval.description = Interval in seconds at which monitor status is updated +thing-type.config.zoneminder.server.urlPath.label = URL Path +thing-type.config.zoneminder.server.urlPath.description = URL path (Default is /zm. Use / if Zoneminder installed under the root directory) +thing-type.config.zoneminder.server.useSSL.label = Use https +thing-type.config.zoneminder.server.useSSL.description = Enables use of https for connection to ZoneMinder +thing-type.config.zoneminder.server.user.label = User Name +thing-type.config.zoneminder.server.user.description = User name (if authentication enabled in ZoneMinder) + +# channel types + +channel-type.zoneminder.alarm.label = Alarm +channel-type.zoneminder.alarm.description = Monitor alarm status +channel-type.zoneminder.enable.label = Enabled +channel-type.zoneminder.enable.description = Enable or disable monitor +channel-type.zoneminder.enable.state.option.ON = Enable +channel-type.zoneminder.enable.state.option.OFF = Disable +channel-type.zoneminder.eventAlarmFrames.label = Event Alarm Frames +channel-type.zoneminder.eventAlarmFrames.description = Number of alarm frames in the event +channel-type.zoneminder.eventCause.label = Event Cause +channel-type.zoneminder.eventCause.description = Cause of the event +channel-type.zoneminder.eventEnd.label = Event End +channel-type.zoneminder.eventEnd.description = End date/time of the event +channel-type.zoneminder.eventEnd.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.zoneminder.eventFrames.label = Event Frames +channel-type.zoneminder.eventFrames.description = Number of frames in the event +channel-type.zoneminder.eventId.label = Event Id +channel-type.zoneminder.eventId.description = Id of the event +channel-type.zoneminder.eventLength.label = Event Length +channel-type.zoneminder.eventLength.description = Length of the event in seconds +channel-type.zoneminder.eventName.label = Event Name +channel-type.zoneminder.eventName.description = Name of the event +channel-type.zoneminder.eventNotes.label = Event Notes +channel-type.zoneminder.eventNotes.description = Notes for the event +channel-type.zoneminder.eventStart.label = Event Start +channel-type.zoneminder.eventStart.description = Start date/time of the event +channel-type.zoneminder.eventStart.state.pattern = %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS +channel-type.zoneminder.events.label = Number of Events +channel-type.zoneminder.events.description = Number of events in time period +channel-type.zoneminder.function.label = Function +channel-type.zoneminder.function.description = State of the monitor (e.g. Nodect, Record) +channel-type.zoneminder.function.state.option.None = None +channel-type.zoneminder.function.state.option.Monitor = Monitor +channel-type.zoneminder.function.state.option.Modect = Modect +channel-type.zoneminder.function.state.option.Record = Record +channel-type.zoneminder.function.state.option.Mocord = Mocord +channel-type.zoneminder.function.state.option.Nodect = Nodect +channel-type.zoneminder.id.label = ID +channel-type.zoneminder.id.description = Monitor ID +channel-type.zoneminder.image.label = Image +channel-type.zoneminder.image.description = A single snapshot image +channel-type.zoneminder.name.label = Name +channel-type.zoneminder.name.description = Monitor name +channel-type.zoneminder.state.label = State +channel-type.zoneminder.state.description = Current monitor state +channel-type.zoneminder.state.state.option.UNKNOWN = UNKNOWN +channel-type.zoneminder.state.state.option.IDLE = IDLE +channel-type.zoneminder.state.state.option.PREALARM = PREALARM +channel-type.zoneminder.state.state.option.ALARM = ALARM +channel-type.zoneminder.state.state.option.ALERT = ALERT +channel-type.zoneminder.state.state.option.TAPE = TAPE +channel-type.zoneminder.triggerAlarm.label = Trigger Alarm +channel-type.zoneminder.triggerAlarm.description = Triggers an alarm +channel-type.zoneminder.url.label = URL +channel-type.zoneminder.url.description = URL of image or stream From 66fd364fa85b964e74d34fb9fc13346e08c7c8ca Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Wed, 15 Dec 2021 18:44:18 +0100 Subject: [PATCH 239/361] New Crowdin updates (#11774) * New translations mqttbroker.properties (Hungarian) * New translations exec.properties (Hungarian) * New translations jinja.properties (Hungarian) * New translations js.properties (Hungarian) * New translations regex.properties (Hungarian) * New translations jsonpath.properties (Hungarian) * New translations scale.properties (Hungarian) * New translations xslt.properties (Hungarian) * New translations xpath.properties (Hungarian) Signed-off-by: Michael Schmidt --- .../OH-INF/i18n/mqttbroker_hu.properties | 86 +++++++++++++++++++ .../resources/OH-INF/i18n/exec_hu.properties | 8 ++ .../resources/OH-INF/i18n/js_hu.properties | 8 ++ .../resources/OH-INF/i18n/jinja_hu.properties | 8 ++ .../OH-INF/i18n/jsonpath_hu.properties | 8 ++ .../resources/OH-INF/i18n/regex_hu.properties | 8 ++ .../resources/OH-INF/i18n/scale_hu.properties | 8 ++ .../resources/OH-INF/i18n/xpath_hu.properties | 8 ++ .../resources/OH-INF/i18n/xslt_hu.properties | 8 ++ 9 files changed, 150 insertions(+) create mode 100644 bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_hu.properties create mode 100644 bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec_hu.properties create mode 100644 bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_hu.properties create mode 100644 bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja_hu.properties create mode 100644 bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath_hu.properties create mode 100644 bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex_hu.properties create mode 100644 bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_hu.properties create mode 100644 bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath_hu.properties create mode 100644 bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt_hu.properties diff --git a/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_hu.properties b/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_hu.properties new file mode 100644 index 0000000000000..0b2c2d0f303a3 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt/src/main/resources/OH-INF/i18n/mqttbroker_hu.properties @@ -0,0 +1,86 @@ +# binding + +binding.mqtt.name = MQTT kötés +binding.mqtt.description = MQTT bróker kezelését teszi lehetővé, mellyel MQTT témákat kapcsolhat dolgokhoz és csatornákhoz + +# thing types + +thing-type.mqtt.broker.label = MQTT bróker +thing-type.mqtt.broker.description = Kapcsolat az MQTT brókerhez +thing-type.mqtt.systemBroker.label = Rendszer MQTT bróker +thing-type.mqtt.systemBroker.description = Rendszerbeállított és ezért csak olvasható bróker kapcsolat. A tulajdonságok a beállítások és belső kapcsolat állapotot tükrözik. + +# thing types config + +thing-type.config.mqtt.broker.certificate.label = Tanúsítvány hash +thing-type.config.mqtt.broker.certificate.description = Ha egy **tanúsítvány rögzítés** beállításra került ezzel a hash kóddal ellenőrizzü a kapcsolatot. A kód törlése esetén a következő kapcsolat új tanúsítvány rögzítését kezdeményezi. Ha üres, akkor automatikusan kitöltésre kerül a következő kapcsolódáskor. Példa\: `SHA-256\:83F9171E06A313118889F7D79302BD1B7A2042EE0CFD029ABF8DD06FFA6CD9D3`. +thing-type.config.mqtt.broker.certificatepin.label = Tanúsítvány rögzítése +thing-type.config.mqtt.broker.certificatepin.description = Ha ez a mező és az SSL beállításra kerül, a következő sikeres kapcsolódás esetén a tanúsítvány rögzítésre kerül. Eltérő tanúsítvány esetén a kapcsolat visszautasítára kerül. Ez esetben törölje a **tanúsítványt**, hogy az új lépjen érvénybe. Ez az opció javítja a biztonságot. +thing-type.config.mqtt.broker.clientID.label = Ügyfél azonosító +thing-type.config.mqtt.broker.clientID.description = Rögzített klines azonosító használata. Alapértelmezetten üres, ekkor az ügyfél azonosító generálásra kerül új kapcsolat esetén. +thing-type.config.mqtt.broker.enableDiscovery.label = Felderítés használata +thing-type.config.mqtt.broker.enableDiscovery.description = Ha bekapcsolja, a bróker minden felderítő szolgáltatás számára elérhető. +thing-type.config.mqtt.broker.host.label = Bróker gépnév/IP +thing-type.config.mqtt.broker.host.description = Az MQTT bróker IP címe vagy gépneve +thing-type.config.mqtt.broker.keepAlive.label = Szívverés +thing-type.config.mqtt.broker.keepAlive.description = Életben tartás / szívverés időzítő használata másodpercben. Ennyi ideig várakozhat a kiszolgáló kapcsolat megszakadása esetén. Alacsonyabb érték a bróker felesleges terhelését okozhatja egyéb előny nélkül. +thing-type.config.mqtt.broker.lwtMessage.label = Végakarat üzenet +thing-type.config.mqtt.broker.lwtMessage.description = A végakarat üzenet (Last Will Message). +thing-type.config.mqtt.broker.lwtQos.label = Végakarat kapcsolat minőség (QoS) +thing-type.config.mqtt.broker.lwtQos.description = A végakarat kapcsolatminőség paramétere. +thing-type.config.mqtt.broker.lwtQos.option.0 = Maximum egyszer (0) +thing-type.config.mqtt.broker.lwtQos.option.1 = Legalább egyszer (1) +thing-type.config.mqtt.broker.lwtQos.option.2 = Pontosan egyszer (2) +thing-type.config.mqtt.broker.lwtRetain.label = Végakarat megtartása +thing-type.config.mqtt.broker.lwtRetain.description = Ha igaz a végakarat üzenet meg lesz tartva (alapértelmezetten hamis) +thing-type.config.mqtt.broker.lwtTopic.label = Végakarat témája +thing-type.config.mqtt.broker.lwtTopic.description = Alapértelmezetten üres, mely kikapcsolja a végakarat üzenetet. +thing-type.config.mqtt.broker.password.label = Jelszó +thing-type.config.mqtt.broker.password.description = Az MQTT jelszó +thing-type.config.mqtt.broker.port.label = Bóker port +thing-type.config.mqtt.broker.port.description = A port megadása nem kötelező, ha nincs megadva 1883 vagy 8883 (SSL) értéket vesz fel. +thing-type.config.mqtt.broker.publickey.label = Nyilvános kulcs kódja +thing-type.config.mqtt.broker.publickey.description = Ha egy **nyilvánoskulcs rögzítés** beállításra került ezzel a hash kóddal ellenőrizzü a kapcsolatot. A kód törlése esetén a következő kapcsolat új nyilvános kulcs rögzítését kezdeményezi. Ha üres, akkor automatikusan kitöltésre kerül a következő kapcsolódáskor. Példa\: `SHA-256\:83F9171E06A313118889F7D79302BD1B7A2042EE0CFD029ABF8DD06FFA6CD9D3` +thing-type.config.mqtt.broker.publickeypin.label = Nyilvános kulcs rögzítése +thing-type.config.mqtt.broker.publickeypin.description = Ha ez a mező és az SSL beállításra kerül, a következő sikeres kapcsolódás esetén a bróker nyilvános kulcsa rögzítésre kerül. Eltérő nyilvános kulcs esetén a kapcsolat visszautasítára kerül. Ez esetben törölje a **nyilvános kulcsot**, hogy az új lépjen érvénybe. Ez az opció javítja a biztonságot. +thing-type.config.mqtt.broker.qos.label = Szolgáltatás minőség +thing-type.config.mqtt.broker.qos.option.0 = Maximum egyszer (0) +thing-type.config.mqtt.broker.qos.option.1 = Legalább egyszer (1) +thing-type.config.mqtt.broker.qos.option.2 = Pontosan egyszer (2) +thing-type.config.mqtt.broker.reconnectTime.label = Újracsatlakozási idő +thing-type.config.mqtt.broker.reconnectTime.description = Újracsatlakozási idő ms-ban. Ha a kapcsolat megszakad a kötés ennyi ideig várakozik, mielőtt újabb kapcsolódást indítana. +thing-type.config.mqtt.broker.secure.label = Biztonságos kapcsolat +thing-type.config.mqtt.broker.secure.description = TLS/SSL használata a bróker biztonságos kapcsolódásához. +thing-type.config.mqtt.broker.username.label = Felhasználónév +thing-type.config.mqtt.broker.username.description = Az MQTT felhasználói neve +thing-type.config.mqtt.systemBroker.brokerid.label = Bróker azonosító +thing-type.config.mqtt.systemBroker.brokerid.description = Minden rendszerszintú MQTT brókerhez egyedi bórker azonosító tartozik. +thing-type.config.mqtt.systemBroker.enableDiscovery.label = Felderítés használata +thing-type.config.mqtt.systemBroker.enableDiscovery.description = Ha bekapcsolja a felderítés szolgáltatótk ezt a brókert fogják használni. + +# channel types + +channel-type.mqtt.publishTrigger.label = Üzenet értesítő +channel-type.mqtt.publishTrigger.description = Ez a csatorna aktiválódik, ha a beállított csatornán MQTT üzenet kerül megosztásra. Az esemény törzse tartalmazza az MQTT témán fogadott értéket. + +# channel types config + +channel-type.config.mqtt.publishTrigger.payload.label = Üzenettörzs feltétele +channel-type.config.mqtt.publishTrigger.payload.description = Az MQTT témán érkező értéken teljesülő kiegészítő kiértékelési feltétel a fenti csatorna aktiválásához. +channel-type.config.mqtt.publishTrigger.separator.label = Elválasztó karakter +channel-type.config.mqtt.publishTrigger.separator.description = A csatorna aktiválásának értéke általában csak az érkező MQTT téma értékét tartalmazza. Ha megad egy elválasztó karaktert, pl.\: \#, akkor a a téma és az érték is a csatorna értékébe kerül. Például\: témám\#értéke. +channel-type.config.mqtt.publishTrigger.stateTopic.label = MQTT téma +channel-type.config.mqtt.publishTrigger.stateTopic.description = Ez a csatorna aktiválódik az MQTT téma esetén. Ez a téma tartalmathat joker karaktereket, mint a + és a \# jel. Pl.\: "mind/egy/ik/\#" vagy "érzékelők/+/beállítás". + +actionInputTopicLabel = MQTT téma +actionInputTopicDesc = A téma, melyre értéket küldünk. +actionInputValueLabel = Érték +actionInputValueDesc = Az érték, melyet küldünk +actionInputRetainLabel = Megtartás +actionInputRetainDesc = Üzenet megtartása +actionLabel = MQTT üzenet küldése +actionDesc = Egy megadott MQTT témára küldött üzenet. +offline.notextualconfig = A {0} nevű rendszerkapcsolat nem létezik. +offline.dyninsteadoftextual = A {0} nevű brókerhez kötés alapú kapcsolat léteik, rendszerkapcsolat helyett. +offline.textualinsteadofdny = A {0} nevű brókerhez dinamikus kapcsolat léteik, rendszerkapcsolat helyett. +offline.sharedremoved = Egy másik kötés váratlanul eltávolított a belső bróker kapcsolatot. diff --git a/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec_hu.properties b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec_hu.properties new file mode 100644 index 0000000000000..f09a7588a6d82 --- /dev/null +++ b/bundles/org.openhab.transform.exec/src/main/resources/OH-INF/i18n/exec_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.EXEC.function.label = Parancs +profile.config.transform.EXEC.function.description = A parancssoron végrehajtandó parancs. Tartalmazzon egy %s paramétert mely az állapottal lesz helyettesítve. +profile.config.transform.EXEC.sourceFormat.label = Formázandó állapotérték +profile.config.transform.EXEC.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.EXEC.label = EXEC diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_hu.properties b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_hu.properties new file mode 100644 index 0000000000000..f6090d6877278 --- /dev/null +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.JS.function.label = Javascript fájl neve +profile.config.transform.JS.function.description = A javascript átalakító neve a mappában. Az átalakítandó érték elérhető lesz az "input" nevű változóban. +profile.config.transform.JS.sourceFormat.label = Formázandó állapotérték +profile.config.transform.JS.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.JS.label = JS diff --git a/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja_hu.properties b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja_hu.properties new file mode 100644 index 0000000000000..d65104db53586 --- /dev/null +++ b/bundles/org.openhab.transform.jinja/src/main/resources/OH-INF/i18n/jinja_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.JINJA.function.label = Jinja minta +profile.config.transform.JINJA.function.description = A kiértékelendő minta. Például\: {{ value_json.device.status.temperature }} +profile.config.transform.JINJA.sourceFormat.label = Formázandó állapotérték +profile.config.transform.JINJA.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.JINJA.label = JINJA diff --git a/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath_hu.properties b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath_hu.properties new file mode 100644 index 0000000000000..e5c7485e3fe39 --- /dev/null +++ b/bundles/org.openhab.transform.jsonpath/src/main/resources/OH-INF/i18n/jsonpath_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.JSONPATH.function.label = JSONPath kifejezés +profile.config.transform.JSONPATH.function.description = A kifejezés mely az értékre alkalmazandó. Például\: $.device.status.temperature +profile.config.transform.JSONPATH.sourceFormat.label = Formázandó állapotérték +profile.config.transform.JSONPATH.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.JSONPATH.label = JSONPATH diff --git a/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex_hu.properties b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex_hu.properties new file mode 100644 index 0000000000000..01461e782650c --- /dev/null +++ b/bundles/org.openhab.transform.regex/src/main/resources/OH-INF/i18n/regex_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.REGEX.function.label = Reguláris kifejezés +profile.config.transform.REGEX.function.description = Az átalakítandó értéken alkalmazandó reguláris kifejezés. Tartalmaznia kell egy elkapó csoportot, melynek az eredményét adja vissza. Például\: .*\=(\\d*.\\d*).* kiválasztja a 23.5 részt a temp\=24.5°C szövegből. +profile.config.transform.REGEX.sourceFormat.label = Formázandó állapotérték +profile.config.transform.REGEX.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.REGEX.label = REGEX diff --git a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_hu.properties b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_hu.properties new file mode 100644 index 0000000000000..313bf7d3a0385 --- /dev/null +++ b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.SCALE.function.label = Fájlnév +profile.config.transform.SCALE.function.description = Fájlnév, mely a skálázó értékeket tartalmazza. +profile.config.transform.SCALE.sourceFormat.label = Formázandó állapotérték +profile.config.transform.SCALE.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.SCALE.label = SCALE diff --git a/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath_hu.properties b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath_hu.properties new file mode 100644 index 0000000000000..32c048fd186e0 --- /dev/null +++ b/bundles/org.openhab.transform.xpath/src/main/resources/OH-INF/i18n/xpath_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.XPATH.function.label = XPath kifejezés +profile.config.transform.XPATH.function.description = Az XPath kifejezés, mely az átalakítandó értékre alkalmazzunk. Például\: /*[name()\='PTZStatus']/*[name()\='AbsoluteHigh']/*[name()\='azimuth']/ +profile.config.transform.XPATH.sourceFormat.label = Formázandó állapotérték +profile.config.transform.XPATH.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.XPATH.label = XPATH diff --git a/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt_hu.properties b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt_hu.properties new file mode 100644 index 0000000000000..ac0efebb0135d --- /dev/null +++ b/bundles/org.openhab.transform.xslt/src/main/resources/OH-INF/i18n/xslt_hu.properties @@ -0,0 +1,8 @@ +profile.config.transform.XSLT.function.label = XSL fájlnév +profile.config.transform.XSLT.function.description = Az XSL fájl neve a mappában, mely az átalakító kifejezést tartalmazza. +profile.config.transform.XSLT.sourceFormat.label = Formázandó állapotérték +profile.config.transform.XSLT.sourceFormat.description = Hogyan formázzuk az állapot csatornát, mielőtt átalakítjuk. Pl.\: %s vagy %.1f °C (alapértelmezetten %s). + +# profile type + +profile-type.transform.XSLT.label = XSLT From 370480814c35100390ab1310ad961b5e623be4b9 Mon Sep 17 00:00:00 2001 From: quidam Date: Wed, 15 Dec 2021 18:48:07 +0100 Subject: [PATCH 240/361] [avmfritz] Prevent attempt to set brightness of blinds (#11790) Signed-off-by: Ulrich Mertin Signed-off-by: Michael Schmidt --- .../avmfritz/internal/handler/AVMFritzBaseThingHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java index 698f2a89de3ff..e9942d1224405 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java @@ -158,7 +158,7 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { updateLevelControl(deviceModel.getLevelControlModel()); } else if (deviceModel.isColorLight()) { updateColorLight(deviceModel.getColorControlModel(), deviceModel.getLevelControlModel()); - } else if (deviceModel.isDimmableLight()) { + } else if (deviceModel.isDimmableLight() && !deviceModel.isHANFUNBlinds()) { updateDimmableLight(deviceModel.getLevelControlModel()); } else if (deviceModel.isHANFUNUnit() && deviceModel.isHANFUNOnOff()) { updateSimpleOnOffUnit(deviceModel.getSimpleOnOffUnit()); From 3b1156fdc54c7ded0fa34d3d9bb92826f42de647 Mon Sep 17 00:00:00 2001 From: Nuesel Date: Thu, 16 Dec 2021 08:53:30 +0100 Subject: [PATCH 241/361] iRobot zone support added (#11783) Signed-off-by: Nuesel Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.irobot/README.md | 7 ++-- .../irobot/internal/dto/MQTTProtocol.java | 18 ++++++---- .../internal/handler/RoombaHandler.java | 35 +++++++++++++++++-- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.irobot/README.md b/bundles/org.openhab.binding.irobot/README.md index 9ab3f647b4821..e68bcd8427783 100644 --- a/bundles/org.openhab.binding.irobot/README.md +++ b/bundles/org.openhab.binding.irobot/README.md @@ -150,10 +150,13 @@ Error codes. Data type is string in order to be able to utilize mapping to human You can clean one or many specific regions of a given map by sending the following String to the command channel: ``` - cleanRegions:;,,.. + cleanRegions:;[r=],[r=],z=,...;[] ``` -The easiest way to determine the pmapId and region_ids is to monitor the last_command channel while starting a new mission for the specific region with the iRobot-App. +Some devices support cleaning rooms (aka regions). Additionally, support for cleaning rectangle areas previously defined in the iRobot-App (aka zones) may be available. +If the type string such as `r=` (region) or `z=` (zone) is omnitted, the type defaults to region. + +The easiest way to determine the pmapId, region_ids/zoneids and userPmapvId is to monitor the last_command channel while starting a new mission for the specific region or zone with the iRobot-App. ## Known Problems / Caveats diff --git a/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/dto/MQTTProtocol.java b/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/dto/MQTTProtocol.java index fd9103590756f..a04dd7754453b 100644 --- a/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/dto/MQTTProtocol.java +++ b/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/dto/MQTTProtocol.java @@ -12,9 +12,8 @@ */ package org.openhab.binding.irobot.internal.dto; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; @@ -35,13 +34,20 @@ public static class CleanRoomsRequest extends CommandRequest { public int ordered; @SerializedName("pmap_id") public String pmapId; + @SerializedName("user_pmapv_id") + public String userPmapvId; public List regions; - public CleanRoomsRequest(String cmd, String mapId, String[] regions) { + public CleanRoomsRequest(String cmd, String mapId, String[] pregions, String[] types, String userPmapvId) { super(cmd); ordered = 1; pmapId = mapId; - this.regions = Arrays.stream(regions).map(i -> new Region(i)).collect(Collectors.toList()); + this.userPmapvId = userPmapvId; + + regions = new ArrayList(); + for (int i = 0; (i < pregions.length) && (i < types.length); i++) { + regions.add(new Region(pregions[i], types[i])); + } } public static class Region { @@ -49,9 +55,9 @@ public static class Region { public String regionId; public String type; - public Region(String id) { + public Region(String id, String type) { this.regionId = id; - this.type = "rid"; + this.type = type; } } } diff --git a/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/RoombaHandler.java b/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/RoombaHandler.java index 78d7f4e1ba75b..ae0c02f2ca9b3 100644 --- a/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/RoombaHandler.java +++ b/bundles/org.openhab.binding.irobot/src/main/java/org/openhab/binding/irobot/internal/handler/RoombaHandler.java @@ -189,9 +189,38 @@ public void handleCommand(ChannelUID channelUID, Command command) { String[] params = cmds[1].split(";"); String mapId = params[0]; - String[] regionIds = params[1].split(","); - - MQTTProtocol.Request request = new MQTTProtocol.CleanRoomsRequest("start", mapId, regionIds); + String userPmapvId; + if (params.length >= 3) { + userPmapvId = params[2]; + } else { + userPmapvId = null; + } + + String[] regions = params[1].split(","); + String regionIds[] = new String[regions.length]; + String regionTypes[] = new String[regions.length]; + + for (int i = 0; i < regions.length; i++) { + String[] regionDetails = regions[i].split("="); + + if (regionDetails.length >= 2) { + if (regionDetails[0].equals("r")) { + regionIds[i] = regionDetails[1]; + regionTypes[i] = "rid"; + } else if (regionDetails[0].equals("z")) { + regionIds[i] = regionDetails[1]; + regionTypes[i] = "zid"; + } else { + regionIds[i] = regionDetails[0]; + regionTypes[i] = "rid"; + } + } else { + regionIds[i] = regionDetails[0]; + regionTypes[i] = "rid"; + } + } + MQTTProtocol.Request request = new MQTTProtocol.CleanRoomsRequest("start", mapId, regionIds, + regionTypes, userPmapvId); connection.send(request.getTopic(), gson.toJson(request)); } else { logger.warn("Invalid request: {}", cmd); From 5df1c3ed52a5ff64c9dd0b7c46c261f7a24ed03c Mon Sep 17 00:00:00 2001 From: Matthew Skinner Date: Thu, 16 Dec 2021 18:58:51 +1100 Subject: [PATCH 242/361] Fix Global off blocks lights turning on (#11797) Signed-off-by: Matthew Skinner Signed-off-by: Michael Schmidt --- .../java/org/openhab/binding/wled/internal/WLedHandler.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java index 9a77d7fddff01..c145f1c93f26c 100644 --- a/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java +++ b/bundles/org.openhab.binding.wled/src/main/java/org/openhab/binding/wled/internal/WLedHandler.java @@ -139,6 +139,10 @@ public void handleCommand(ChannelUID channelUID, Command command) { break; case CHANNEL_MASTER_CONTROLS: if (command instanceof OnOffType) { + if (OnOffType.ON.equals(command)) { + // global may be off, but we don't want to switch global off and affect other segments + localApi.setGlobalOn(true); + } localApi.setMasterOn(OnOffType.ON.equals(command), config.segmentIndex); } else if (command instanceof IncreaseDecreaseType) { if (IncreaseDecreaseType.INCREASE.equals(command)) { @@ -159,6 +163,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { localApi.setMasterOn(false, config.segmentIndex); return; } + localApi.setGlobalOn(true); primaryColor = (HSBType) command; if (primaryColor.getSaturation().intValue() < config.saturationThreshold && hasWhite) { localApi.setWhiteOnly((PercentType) command, config.segmentIndex); From 037c743c70cabb7fc4eae0b9475f953c68852149 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 16 Dec 2021 09:03:42 +0100 Subject: [PATCH 243/361] [miio] fix action channel miot for empty input with parameters (#11794) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- .../openhab/binding/miio/internal/handler/MiIoBasicHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java index e51083b71ea6b..f3bd724770b2b 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java @@ -245,7 +245,7 @@ public void handleCommand(ChannelUID channelUID, Command receivedCommand) { value = new JsonPrimitive(command.toString().toLowerCase()); } if (paramType == CommandParameterType.EMPTY) { - value = new JsonArray(); + value = parameters.deepCopy(); } final MiIoDeviceActionCondition miIoDeviceActionCondition = action.getCondition(); if (miIoDeviceActionCondition != null) { From 92469937f28e296d673f457784298045e8f60d14 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Thu, 16 Dec 2021 20:04:40 +0100 Subject: [PATCH 244/361] [samsungtv] Rename German translations file (#11799) While uploading the German translations I noticed the file had a different name. Renaming it prevents us ending up with 2 German translations files once all the texts are translated in German. Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../i18n/{samsung_de.properties => samsungtv_de.properties} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/{samsung_de.properties => samsungtv_de.properties} (100%) diff --git a/bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsung_de.properties b/bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv_de.properties similarity index 100% rename from bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsung_de.properties rename to bundles/org.openhab.binding.samsungtv/src/main/resources/OH-INF/i18n/samsungtv_de.properties From 47c6b6ddb2dcbce6a3428c2599d5748d9e192aa5 Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Thu, 16 Dec 2021 20:06:50 +0100 Subject: [PATCH 245/361] [jsscripting] Add default translations (#11798) Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../src/main/resources/OH-INF/i18n/jsscripting.properties | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/i18n/jsscripting.properties diff --git a/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/i18n/jsscripting.properties b/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/i18n/jsscripting.properties new file mode 100644 index 0000000000000..04b35ae280b34 --- /dev/null +++ b/bundles/org.openhab.automation.jsscripting/src/main/resources/OH-INF/i18n/jsscripting.properties @@ -0,0 +1,8 @@ +automation.config.jsscripting.injectionEnabled.label = Use Built-in Global Variables +automation.config.jsscripting.injectionEnabled.description = Import all variables from the OH scripting library into all rules for common services like items, things, actions, log, etc...
If disabled, the OH scripting library can be imported manually using "require('openhab')" +automation.config.jsscripting.injectionEnabled.option.true = Use Built-in Variables +automation.config.jsscripting.injectionEnabled.option.false = Do Not Use Built-in Variables + +# service + +service.automation.jsscripting.label = JS Scripting From e33b011f0427d13cf22a90fd57e53345651b5fee Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 16 Dec 2021 20:08:41 +0100 Subject: [PATCH 246/361] [miio] Cleanup devices section of readme (#11788) Signed-off-by: Marcel Verpaalen Signed-off-by: Michael Schmidt --- bundles/org.openhab.binding.miio/README.md | 50 +++++++++---------- .../resources/OH-INF/i18n/basic.properties | 16 +++--- .../database/careli.fryer.maf01-miot.json | 1 - .../database/careli.fryer.maf02-miot.json | 1 - .../database/cgllc.airm.cgdn1-miot.json | 3 +- .../database/dmaker.fan.p18-miot.json | 1 - .../database/dmaker.fan.p8-miot.json | 1 - .../database/dreame.vacuum.mc1808-miot.json | 1 - .../database/dreame.vacuum.p2008-miot.json | 1 - .../database/dreame.vacuum.p2009-miot.json | 1 - .../database/viomi.vacuum.v18-miot.json | 1 - .../database/zhimi.airfresh.ua1-miot.json | 7 ++- .../database/zhimi.airpurifier.ma4-miot.json | 1 - .../database/zhimi.airpurifier.mb3-miot.json | 13 +++-- .../database/zhimi.airpurifier.mb4-miot.json | 1 - .../database/zhimi.heater.ma3-miot.json | 1 - 16 files changed, 43 insertions(+), 57 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index 7e4cd02b385a3..4a429d74c082c 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -181,10 +181,10 @@ Currently the miio binding supports more than 310 different models. | Device | ThingType | Device Model | Supported | Remark | |------------------------------|------------------|------------------------|-----------|------------| | AUX Smart Air Conditioner | miio:unsupported | aux.aircondition.v1 | No | | -| Mi Air Frying Pan | miio:basic | [careli.fryer.maf01](#careli-fryer-maf01) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Smart Air Fryer (3.5L) | miio:basic | [careli.fryer.maf02](#careli-fryer-maf02) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-custom-cook","siid":3,"aiid":1,"in":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cooking","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Air Frying Pan | miio:basic | [careli.fryer.maf03](#careli-fryer-maf03) | Yes | Identified manual actions for execution
`action{"did":"air-fryer-start-cook","siid":2,"aiid":1,"in":[]}`
`action{"did":"air-fryer-cancel-cooking","siid":2,"aiid":2,"in":[]}`
`action{"did":"air-fryer-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"custom-start-cook","siid":3,"aiid":1,"in":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`
`action{"did":"custom-resume-cook","siid":3,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Qingping Air Monitor Lite | miio:basic | [cgllc.airm.cgdn1](#cgllc-airm-cgdn1) | Yes | Identified manual actions for execution
`action{"did":"settings-set-start-time","siid":9,"aiid":2,"in":[2.0]}`
`action{"did":"settings-set-end-time","siid":9,"aiid":3,"in":[3.0]}`
`action{"did":"settings-set-frequency","siid":9,"aiid":4,"in":[4.0]}`
`action{"did":"settings-set-screen-off","siid":9,"aiid":5,"in":[5.0]}`
`action{"did":"settings-set-device-off","siid":9,"aiid":6,"in":[6.0]}`
`action{"did":"settings-set-temp-unit","siid":9,"aiid":7,"in":[7.0]}`
Please test and feedback if they are working so they can be linked to a channel. | +| Mi Air Frying Pan | miio:basic | [careli.fryer.maf01](#careli-fryer-maf01) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Air Fryer (3.5L) | miio:basic | [careli.fryer.maf02](#careli-fryer-maf02) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Frying Pan | miio:basic | [careli.fryer.maf03](#careli-fryer-maf03) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Qingping Air Monitor Lite | miio:basic | [cgllc.airm.cgdn1](#cgllc-airm-cgdn1) | Yes | | | Mi Multifunction Air Monitor | miio:basic | [cgllc.airmonitor.b1](#cgllc-airmonitor-b1) | Yes | | | Qingping Air Monitor | miio:basic | [cgllc.airmonitor.s1](#cgllc-airmonitor-s1) | Yes | | | Mi Universal Remote | miio:unsupported | chuangmi.ir.v2 | No | | @@ -211,22 +211,22 @@ Currently the miio binding supports more than 310 different models. | Mi Smart Humidifier | miio:basic | [deerma.humidifier.mjjsq](#deerma-humidifier-mjjsq) | Yes | | | Mi Fresh Air Ventilator A1-150 | miio:basic | [dmaker.airfresh.a1](#dmaker-airfresh-a1) | Yes | | | Mi Fresh Air Ventilator | miio:basic | [dmaker.airfresh.t2017](#dmaker-airfresh-t2017) | Yes | | -| Mi Smart Standing Fan 2 Lite | miio:basic | [dmaker.fan.1c](#dmaker-fan-1c) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Standing Fan 2 Lite | miio:basic | [dmaker.fan.1c](#dmaker-fan-1c) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Standing Fan 1X | miio:basic | [dmaker.fan.p5](#dmaker-fan-p5) | Yes | | -| Mi Smart Standing Fan 1C | miio:basic | [dmaker.fan.p8](#dmaker-fan-p8) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Standing Fan 1C | miio:basic | [dmaker.fan.p8](#dmaker-fan-p8) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Tower Fan | miio:basic | [dmaker.fan.p9](#dmaker-fan-p9) | Yes | | | Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p10](#dmaker-fan-p10) | Yes | | | Mi Smart Standing Fan Pro | miio:basic | [dmaker.fan.p15](#dmaker-fan-p15) | Yes | Identified manual actions for execution
`action{"did":"off-delay-time-toggle","siid":3,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel. | -| Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p18](#dmaker-fan-p18) | Yes | Identified manual actions for execution
`action{"did":"fan-toggle","siid":2,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Robot Vacuum Mop 1C STYTJ01ZHM | miio:basic | [dreame.vacuum.mc1808](#dreame-vacuum-mc1808) | Yes | Identified manual actions for execution
`action{"did":"battery-start-charge","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-start-sweep","siid":3,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":3,"aiid":2,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":26,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":27,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":28,"aiid":1,"in":[]}`
`action{"did":"clean-start-clean","siid":18,"aiid":1,"in":[]}`
`action{"did":"clean-stop-clean","siid":18,"aiid":2,"in":[]}`
`action{"did":"remote-start-remote","siid":21,"aiid":1,"in":[1.0, 2.0]}`
`action{"did":"remote-stop-remote","siid":21,"aiid":2,"in":[]}`
`action{"did":"remote-exit-remote","siid":21,"aiid":3,"in":[]}`
`action{"did":"map-map-req","siid":23,"aiid":1,"in":[2.0]}`
`action{"did":"audio-position","siid":24,"aiid":1,"in":[]}`
`action{"did":"audio-set-voice","siid":24,"aiid":2,"in":[]}`
`action{"did":"audio-play-sound","siid":24,"aiid":3,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel. | -| Dreame Robot Vacuum-Mop F9 | miio:basic | [dreame.vacuum.p2008](#dreame-vacuum-p2008) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"battery-start-charge","siid":3,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":9,"aiid":1,"in":[]}`
`action{"did":"brush-cleaner-reset-brush-life","siid":10,"aiid":1,"in":[]}`
`action{"did":"filter-reset-filter-life","siid":11,"aiid":1,"in":[]}`
`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Dreame Robot Vacuum D9 | miio:basic | [dreame.vacuum.p2009](#dreame-vacuum-p2009) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| +| Mi Smart Standing Fan 2 | miio:basic | [dmaker.fan.p18](#dmaker-fan-p18) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Robot Vacuum Mop 1C STYTJ01ZHM | miio:basic | [dreame.vacuum.mc1808](#dreame-vacuum-mc1808) | Yes | | +| Dreame Robot Vacuum-Mop F9 | miio:basic | [dreame.vacuum.p2008](#dreame-vacuum-p2008) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Dreame Robot Vacuum D9 | miio:basic | [dreame.vacuum.p2009](#dreame-vacuum-p2009) | Yes | | | Dreame Bot W10 | miio:basic | [dreame.vacuum.p2027](#dreame-vacuum-p2027) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Dreame Bot Z10 Pro | miio:basic | [dreame.vacuum.p2028](#dreame-vacuum-p2028) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Trouver Robot LDS Vacuum-Mop Finder | miio:basic | [dreame.vacuum.p2036](#dreame-vacuum-p2036) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| +| Trouver Robot LDS Vacuum-Mop Finder | miio:basic | [dreame.vacuum.p2036](#dreame-vacuum-p2036) | Yes | | | Mi Robot Vacuum-Mop 2 Pro+ | miio:basic | [dreame.vacuum.p2041o](#dreame-vacuum-p2041o) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | MOVA Z500 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2156o](#dreame-vacuum-p2156o) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| MOVA L600 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2157](#dreame-vacuum-p2157) | Yes | Identified manual actions for execution not linked in the database >`action{"did":"vacuum-extend-start-clean","siid":4,"aiid":1,"in":[10.0]}`
`action{"did":"vacuum-extend-stop-clean","siid":4,"aiid":2,"in":[]}`
`action{"did":"map-map-req","siid":6,"aiid":1,"in":[2.0]}`
`action{"did":"map-update-map","siid":6,"aiid":2,"in":[4.0]}`
`action{"did":"audio-position","siid":7,"aiid":1,"in":[]}`
`action{"did":"audio-play-sound","siid":7,"aiid":2,"in":[]}`
`action{"did":"time-delete-timer","siid":8,"aiid":1,"in":[3.0]}`
| +| MOVA L600 Robot Vacuum and Mop Cleaner | miio:basic | [dreame.vacuum.p2157](#dreame-vacuum-p2157) | Yes | | | Dreame Bot D9 Max | miio:basic | [dreame.vacuum.p2259](#dreame-vacuum-p2259) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO ARIES For Bedroom | miio:basic | [huayi.light.ari013](#huayi-light-ari013) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | HUIZUO ARIES For Living Room | miio:basic | [huayi.light.aries](#huayi-light-aries) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -352,7 +352,7 @@ Currently the miio binding supports more than 310 different models. | Viomi Cleaning Robot V-RVCLM21B | miio:basic | [viomi.vacuum.v6](#viomi-vacuum-v6) | Yes | | | Mi Robot Vacuum-Mop P | miio:basic | [viomi.vacuum.v7](#viomi-vacuum-v7) | Yes | | | Mi Robot Vacuum-Mop P | miio:basic | [viomi.vacuum.v8](#viomi-vacuum-v8) | Yes | | -| Viomi S9 | miio:basic | [viomi.vacuum.v18](#viomi-vacuum-v18) | Yes | Identified manual actions for execution
`action{"did":"vacuum-start-sweep","siid":2,"aiid":1,"in":[]}`
`action{"did":"vacuum-stop-sweeping","siid":2,"aiid":2,"in":[]}`
`action{"did":"vacuum-pause","siid":2,"aiid":3,"in":[]}`
`action{"did":"vacuum-start-charge","siid":2,"aiid":4,"in":[]}`
`action{"did":"vacuum-stop-massage","siid":2,"aiid":5,"in":[]}`
`action{"did":"vacuum-start-mop","siid":2,"aiid":6,"in":[]}`
`action{"did":"vacuum-start-only-sweep","siid":2,"aiid":7,"in":[]}`
`action{"did":"vacuum-start-sweep-mop","siid":2,"aiid":8,"in":[]}`
`action{"did":"viomi-vacuum-reset-map","siid":4,"aiid":7,"in":[]}`
`action{"did":"viomi-vacuum-set-calibration","siid":4,"aiid":10,"in":[]}`
`action{"did":"viomi-vacuum-reset-consumable","siid":4,"aiid":11,"in":[35.0]}`
`action{"did":"viomi-vacuum-set-room-clean","siid":4,"aiid":13,"in":[36.0, 37.0, 38.0]}`
`action{"did":"order-del","siid":5,"aiid":2,"in":[1.0]}`
`action{"did":"order-get","siid":5,"aiid":3,"in":[]}`
`action{"did":"point-zone-start-point-clean","siid":6,"aiid":1,"in":[]}`
`action{"did":"point-zone-pause-point-clean","siid":6,"aiid":2,"in":[]}`
`action{"did":"point-zone-start-zone-clean","siid":6,"aiid":5,"in":[]}`
`action{"did":"point-zone-pause-zone-clean","siid":6,"aiid":6,"in":[]}`
`action{"did":"map-upload-by-maptype","siid":7,"aiid":1,"in":[]}`
`action{"did":"map-upload-by-mapid","siid":7,"aiid":2,"in":[]}`
`action{"did":"map-set-cur-map","siid":7,"aiid":3,"in":[2.0, 15.0]}`
`action{"did":"map-del-map","siid":7,"aiid":5,"in":[2.0]}`
`action{"did":"map-rename-map","siid":7,"aiid":7,"in":[2.0, 4.0]}`
`action{"did":"map-arrange-room","siid":7,"aiid":8,"in":[2.0, 5.0, 6.0, 14.0]}`
`action{"did":"map-split-room","siid":7,"aiid":9,"in":[2.0, 5.0, 7.0, 8.0, 14.0]}`
`action{"did":"map-rename-room","siid":7,"aiid":10,"in":[2.0, 7.0, 9.0, 14.0]}`
`action{"did":"map-get-map-list","siid":7,"aiid":11,"in":[]}`
`action{"did":"map-get-cleaning-path","siid":7,"aiid":12,"in":[12.0]}`
`action{"did":"map-set-new-map","siid":7,"aiid":13,"in":[]}`
`action{"did":"map-deal-new-map","siid":7,"aiid":14,"in":[16.0]}`
`action{"did":"voice-find-device","siid":8,"aiid":2,"in":[]}`
`action{"did":"voice-download-voice","siid":8,"aiid":3,"in":[3.0, 7.0, 8.0]}`
`action{"did":"voice-get-downloadstatus","siid":8,"aiid":4,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Viomi S9 | miio:basic | [viomi.vacuum.v18](#viomi-vacuum-v18) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | VIOMI Internet Electric Water Heater 1A (60L) | miio:basic | [viomi.waterheater.e1](#viomi-waterheater-e1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Inverter Air Conditioner (1.5HP) | miio:basic | [xiaomi.aircondition.ma1](#xiaomi-aircondition-ma1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Inverter Air Conditioner (1.5HP, China Energy Label Level 1) | miio:basic | [xiaomi.aircondition.ma2](#xiaomi-aircondition-ma2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -472,16 +472,16 @@ Currently the miio binding supports more than 310 different models. | Mi Water Purifier v4 | miio:basic | [yunmi.waterpurifier.v4](#yunmi-waterpurifier-v4) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Ventilation System | miio:basic | [zhimi.airfresh.va2](#zhimi-airfresh-va2) | Yes | | | Smartmi Fresh Air System (Heating) | miio:basic | [zhimi.airfresh.va4](#zhimi-airfresh-va4) | Yes | | -| Mi Fresh Air Ventilator C1-80 | miio:basic | [zhimi.airfresh.ua1](#zhimi-airfresh-ua1) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[1.0]}`
Please test and feedback if they are working so they can be linked to a channel. | +| Mi Fresh Air Ventilator C1-80 | miio:basic | [zhimi.airfresh.ua1](#zhimi-airfresh-ua1) | Yes | | | Mi PM2.5 Air Quality Monitor | miio:basic | [zhimi.airmonitor.v1](#zhimi-airmonitor-v1) | Yes | | | Mi Air Purifier 2 (mini) | miio:basic | [zhimi.airpurifier.m1](#zhimi-airpurifier-m1) | Yes | | | Mi Air Purifier 2 | miio:basic | [zhimi.airpurifier.m2](#zhimi-airpurifier-m2) | Yes | | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.ma1](#zhimi-airpurifier-ma1) | Yes | | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.ma2](#zhimi-airpurifier-ma2) | Yes | | -| Mi Air Purifier 3 | miio:basic | [zhimi.airpurifier.ma4](#zhimi-airpurifier-ma4) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Purifier 3 | miio:basic | [zhimi.airpurifier.ma4](#zhimi-airpurifier-ma4) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.mb1](#zhimi-airpurifier-mb1) | Yes | | -| Mi Air Purifier 3/3H | miio:basic | [zhimi.airpurifier.mb3](#zhimi-airpurifier-mb3) | Yes | Identified manual actions for execution
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[]}`
`action{"did":"button-toggle","siid":8,"aiid":1,"in":[]}`
`action{"did":"button-toggle-mode","siid":8,"aiid":2,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Air Purifier 3C | miio:basic | [zhimi.airpurifier.mb4](#zhimi-airpurifier-mb4) | Yes | Specified action for filter reset
`action{"did":"filter-reset-filter-life","siid":4,"aiid":1,"in":[3.0]}`
However, this has not been successfully tested yet. | +| Mi Air Purifier 3/3H | miio:basic | [zhimi.airpurifier.mb3](#zhimi-airpurifier-mb3) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Air Purifier 3C | miio:basic | [zhimi.airpurifier.mb4](#zhimi-airpurifier-mb4) | Yes | | | Mi Air Purifier 2S | miio:basic | [zhimi.airpurifier.mc1](#zhimi-airpurifier-mc1) | Yes | | | Mi Air Purifier 2H | miio:basic | [zhimi.airpurifier.mc2](#zhimi-airpurifier-mc2) | Yes | | | Mi Air Purifier Super | miio:basic | [zhimi.airpurifier.sa1](#zhimi-airpurifier-sa1) | Yes | | @@ -505,7 +505,7 @@ Currently the miio binding supports more than 310 different models. | Smartmi Standing Fan 2S | miio:basic | [zhimi.fan.za4](#zhimi-fan-za4) | Yes | | | Smartmi Standing Fan 3 | miio:basic | [zhimi.fan.za5](#zhimi-fan-za5) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Space Heater S | miio:basic | [zhimi.heater.ma2](#zhimi-heater-ma2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | -| Mi Smart Baseboard Heater E | miio:basic | [zhimi.heater.ma3](#zhimi-heater-ma3) | Yes | Identified manual actions for execution
`action{"did":"private-service-toggle-switch","siid":8,"aiid":1,"in":[]}`
Please test and feedback if they are working so they can be linked to a channel.
Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Baseboard Heater E | miio:basic | [zhimi.heater.ma3](#zhimi-heater-ma3) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Mi Smart Space Heater S | miio:basic | [zhimi.heater.mc2](#zhimi-heater-mc2) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Smart Fan | miio:basic | [zhimi.heater.na1](#zhimi-heater-na1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | | Smartmi Smart Fan Heater | miio:basic | [zhimi.heater.nb1](#zhimi-heater-nb1) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | @@ -4587,9 +4587,9 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | physical_controls_locked | Switch | Physical Control Locked - Physical Control Locked | | | alarm | Switch | Alarm - Alarm | | | brightness | Dimmer | Indicator Light - Brightness | | -| motor_a_speed_rpm | Number | Custom Serveice - Motor A Speed Rpm | | -| motor_b_speed_rpm | Number | Custom Serveice - Motor B Speed Rpm | | -| temperature | Number:Temperature | Custom Serveice - Temperature | | +| motor_a_speed_rpm | Number | Custom Service - Motor A Speed Rpm | | +| motor_b_speed_rpm | Number | Custom Service - Motor B Speed Rpm | | +| temperature | Number:Temperature | Custom Service - Temperature | | ### Mi PM2.5 Air Quality Monitor (zhimi.airmonitor.v1) Channels @@ -4818,7 +4818,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | hw-version | Number | Others - Hw Version | | | iic-error-count | Number | Others - Iic Error Count | | | manual-level | Number | Others - Manual Level | Value mapping `["1"="Level1","2"="Level2","3"="Level3"]` | -| country-code | Number | Others - National Code | Value mapping `["91"="印度","44"="分销英文","852"="中国香港","886"="中国台湾","82"="韩国"]` | +| country-code | Number | Others - National Code | Value mapping `["91"="India","44"="UK","852"="Hong Kong","886"="Taiwan","82"="Korea"]` | ### Mi Air Purifier 3C (zhimi.airpurifier.mb4) Channels @@ -10303,9 +10303,9 @@ Number:Dimensionless filter_life_level "Filter - Filter Life Level" (G_airfresh) Switch physical_controls_locked "Physical Control Locked - Physical Control Locked" (G_airfresh) {channel="miio:basic:airfresh:physical_controls_locked"} Switch alarm "Alarm - Alarm" (G_airfresh) {channel="miio:basic:airfresh:alarm"} Dimmer brightness "Indicator Light - Brightness" (G_airfresh) {channel="miio:basic:airfresh:brightness"} -Number motor_a_speed_rpm "Custom Serveice - Motor A Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_a_speed_rpm"} -Number motor_b_speed_rpm "Custom Serveice - Motor B Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_b_speed_rpm"} -Number:Temperature temperature "Custom Serveice - Temperature" (G_airfresh) {channel="miio:basic:airfresh:temperature"} +Number motor_a_speed_rpm "Custom Service - Motor A Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_a_speed_rpm"} +Number motor_b_speed_rpm "Custom Service - Motor B Speed Rpm" (G_airfresh) {channel="miio:basic:airfresh:motor_b_speed_rpm"} +Number:Temperature temperature "Custom Service - Temperature" (G_airfresh) {channel="miio:basic:airfresh:temperature"} ``` ### Mi PM2.5 Air Quality Monitor (zhimi.airmonitor.v1) item file lines diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties index ec7c8d67214a0..2f60bb2123285 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/i18n/basic.properties @@ -1346,11 +1346,11 @@ ch.zhimi.airfresh.ua1-miot.fault = Device Fault ch.zhimi.airfresh.ua1-miot.filter_life_level = Filter - Filter Life Level ch.zhimi.airfresh.ua1-miot.filter_used_time = Filter - Filter Used Time ch.zhimi.airfresh.ua1-miot.heater = Heater -ch.zhimi.airfresh.ua1-miot.motor_a_speed_rpm = Custom Serveice - Motor A Speed Rpm -ch.zhimi.airfresh.ua1-miot.motor_b_speed_rpm = Custom Serveice - Motor B Speed Rpm +ch.zhimi.airfresh.ua1-miot.motor_a_speed_rpm = Custom Service - Motor A Speed Rpm +ch.zhimi.airfresh.ua1-miot.motor_b_speed_rpm = Custom Service - Motor B Speed Rpm ch.zhimi.airfresh.ua1-miot.on = Air Fresh - Switch Status ch.zhimi.airfresh.ua1-miot.physical_controls_locked = Physical Control Locked - Physical Control Locked -ch.zhimi.airfresh.ua1-miot.temperature = Custom Serveice - Temperature +ch.zhimi.airfresh.ua1-miot.temperature = Custom Service - Temperature ch.zhimi.airfresh.va4.aqi = Air Quality Index ch.zhimi.airfresh.va4.averageaqi = Average Air Quality Index ch.zhimi.airfresh.va4.buzzer = Buzzer @@ -2856,11 +2856,11 @@ option.zhimi.airpurifier.mb3-miot.aqi-state-5 = unhealthy option.zhimi.airpurifier.mb3-miot.brightness-0 = Brightest option.zhimi.airpurifier.mb3-miot.brightness-1 = Glimmer option.zhimi.airpurifier.mb3-miot.brightness-2 = Led Closed -option.zhimi.airpurifier.mb3-miot.country-code-44 = 分销英文 -option.zhimi.airpurifier.mb3-miot.country-code-82 = 韩国 -option.zhimi.airpurifier.mb3-miot.country-code-852 = 中国香港 -option.zhimi.airpurifier.mb3-miot.country-code-886 = 中国台湾 -option.zhimi.airpurifier.mb3-miot.country-code-91 = 印度 +option.zhimi.airpurifier.mb3-miot.country-code-44 = UK +option.zhimi.airpurifier.mb3-miot.country-code-82 = Korea +option.zhimi.airpurifier.mb3-miot.country-code-852 = Hong Kong +option.zhimi.airpurifier.mb3-miot.country-code-886 = Taiwan +option.zhimi.airpurifier.mb3-miot.country-code-91 = India option.zhimi.airpurifier.mb3-miot.fan-level-1 = Level1 option.zhimi.airpurifier.mb3-miot.fan-level-2 = Level2 option.zhimi.airpurifier.mb3-miot.fan-level-3 = Level3 diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json index 7526c0b6fee00..e58144e6cf16f 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf01-miot.json @@ -522,7 +522,6 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Switch Off\",\"0\"\u003d\"Not Turn Pot\",\"2\"\u003d\"Turn Pot\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cook\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json index ffa63d674c2c8..b298fd1923651 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/careli.fryer.maf02-miot.json @@ -494,7 +494,6 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Switch Off\",\"0\"\u003d\"Not Turn Pot\",\"2\"\u003d\"Turn Pot\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"air-fryer-start-cook\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-cancel-cooking\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"air-fryer-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"custom-start-custom-cook\",\"siid\":3,\"aiid\":1,\"in\":[1.0, 3.0, 4.0, 5.0, 6.0, 7.0]}`\u003cbr /\u003e`action{\"did\":\"custom-resume-cooking\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json index a2dc869d46cc5..0d875ec687aa1 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/cgllc.airm.cgdn1-miot.json @@ -445,7 +445,6 @@ } ] } - ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"settings-set-start-time\",\"siid\":9,\"aiid\":2,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-end-time\",\"siid\":9,\"aiid\":3,\"in\":[3.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-frequency\",\"siid\":9,\"aiid\":4,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-screen-off\",\"siid\":9,\"aiid\":5,\"in\":[5.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-device-off\",\"siid\":9,\"aiid\":6,\"in\":[6.0]}`\u003cbr /\u003e`action{\"did\":\"settings-set-temp-unit\",\"siid\":9,\"aiid\":7,\"in\":[7.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel." + ] } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json index c46781e1bd1b9..c19b497e125e3 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p18-miot.json @@ -312,7 +312,6 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json index 6faf335758050..08751ca0691d0 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dmaker.fan.p8-miot.json @@ -218,7 +218,6 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"fan-toggle\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json index 7541a72340806..19580cf612428 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.mc1808-miot.json @@ -703,7 +703,6 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":3,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":26,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":27,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":28,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-start-clean\",\"siid\":18,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"clean-stop-clean\",\"siid\":18,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-start-remote\",\"siid\":21,\"aiid\":1,\"in\":[1.0, 2.0]}`\u003cbr /\u003e`action{\"did\":\"remote-stop-remote\",\"siid\":21,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"remote-exit-remote\",\"siid\":21,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":23,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":24,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-set-voice\",\"siid\":24,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":24,\"aiid\":3,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json index 3defb4679c49e..fbbd868180f39 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2008-miot.json @@ -628,7 +628,6 @@ "readmeComment": "Value mapping `[\"0\"\u003d\"Off\",\"1\"\u003d\"On\",\"-1\"\u003d\"Not Enabled\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"battery-start-charge\",\"siid\":3,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":9,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"brush-cleaner-reset-brush-life\",\"siid\":10,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":11,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2009-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2009-miot.json index 9a43984b0b9f0..1741dc36e680f 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2009-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/dreame.vacuum.p2009-miot.json @@ -1007,7 +1007,6 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution not linked in the database \u003e`action{\"did\":\"vacuum-extend-start-clean\",\"siid\":4,\"aiid\":1,\"in\":[10.0]}`\u003cbr /\u003e`action{\"did\":\"vacuum-extend-stop-clean\",\"siid\":4,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-map-req\",\"siid\":6,\"aiid\":1,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-update-map\",\"siid\":6,\"aiid\":2,\"in\":[4.0]}`\u003cbr /\u003e`action{\"did\":\"audio-position\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"audio-play-sound\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"time-delete-timer\",\"siid\":8,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003e", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json index 21d1f1e542a3c..eb335fcc5d4e7 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/viomi.vacuum.v18-miot.json @@ -1531,7 +1531,6 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep\",\"siid\":2,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-sweeping\",\"siid\":2,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-pause\",\"siid\":2,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-charge\",\"siid\":2,\"aiid\":4,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-stop-massage\",\"siid\":2,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-mop\",\"siid\":2,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-only-sweep\",\"siid\":2,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"vacuum-start-sweep-mop\",\"siid\":2,\"aiid\":8,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-map\",\"siid\":4,\"aiid\":7,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-calibration\",\"siid\":4,\"aiid\":10,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-reset-consumable\",\"siid\":4,\"aiid\":11,\"in\":[35.0]}`\u003cbr /\u003e`action{\"did\":\"viomi-vacuum-set-room-clean\",\"siid\":4,\"aiid\":13,\"in\":[36.0, 37.0, 38.0]}`\u003cbr /\u003e`action{\"did\":\"order-del\",\"siid\":5,\"aiid\":2,\"in\":[1.0]}`\u003cbr /\u003e`action{\"did\":\"order-get\",\"siid\":5,\"aiid\":3,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-point-clean\",\"siid\":6,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-point-clean\",\"siid\":6,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-start-zone-clean\",\"siid\":6,\"aiid\":5,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"point-zone-pause-zone-clean\",\"siid\":6,\"aiid\":6,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-maptype\",\"siid\":7,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-upload-by-mapid\",\"siid\":7,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-set-cur-map\",\"siid\":7,\"aiid\":3,\"in\":[2.0, 15.0]}`\u003cbr /\u003e`action{\"did\":\"map-del-map\",\"siid\":7,\"aiid\":5,\"in\":[2.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-map\",\"siid\":7,\"aiid\":7,\"in\":[2.0, 4.0]}`\u003cbr /\u003e`action{\"did\":\"map-arrange-room\",\"siid\":7,\"aiid\":8,\"in\":[2.0, 5.0, 6.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-split-room\",\"siid\":7,\"aiid\":9,\"in\":[2.0, 5.0, 7.0, 8.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-rename-room\",\"siid\":7,\"aiid\":10,\"in\":[2.0, 7.0, 9.0, 14.0]}`\u003cbr /\u003e`action{\"did\":\"map-get-map-list\",\"siid\":7,\"aiid\":11,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-get-cleaning-path\",\"siid\":7,\"aiid\":12,\"in\":[12.0]}`\u003cbr /\u003e`action{\"did\":\"map-set-new-map\",\"siid\":7,\"aiid\":13,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"map-deal-new-map\",\"siid\":7,\"aiid\":14,\"in\":[16.0]}`\u003cbr /\u003e`action{\"did\":\"voice-find-device\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"voice-download-voice\",\"siid\":8,\"aiid\":3,\"in\":[3.0, 7.0, 8.0]}`\u003cbr /\u003e`action{\"did\":\"voice-get-downloadstatus\",\"siid\":8,\"aiid\":4,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json index 00cfc6071ed3a..4d72756e58cd8 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airfresh.ua1-miot.json @@ -215,7 +215,7 @@ "property": "motor-a-speed-rpm", "siid": 8, "piid": 1, - "friendlyName": "Custom Serveice - Motor A Speed Rpm", + "friendlyName": "Custom Service - Motor A Speed Rpm", "channel": "motor_a_speed_rpm", "type": "Number", "stateDescription": { @@ -232,7 +232,7 @@ "property": "motor-b-speed-rpm", "siid": 8, "piid": 2, - "friendlyName": "Custom Serveice - Motor B Speed Rpm", + "friendlyName": "Custom Service - Motor B Speed Rpm", "channel": "motor_b_speed_rpm", "type": "Number", "stateDescription": { @@ -249,7 +249,7 @@ "property": "temperature", "siid": 8, "piid": 5, - "friendlyName": "Custom Serveice - Temperature", + "friendlyName": "Custom Service - Temperature", "channel": "temperature", "type": "Number:Temperature", "unit": "CELSIUS", @@ -268,7 +268,6 @@ ] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[1.0]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json index e4bc266de821c..bfa4075df4ff3 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.ma4-miot.json @@ -1020,7 +1020,6 @@ "readmeComment": "Value mapping `[\"1\"\u003d\"Level1\",\"2\"\u003d\"Level2\",\"3\"\u003d\"Level3\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json index 63813d0b95632..d1125a390a5a4 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb3-miot.json @@ -1033,23 +1033,23 @@ "options": [ { "value": "91", - "label": "印度" + "label": "India" }, { "value": "44", - "label": "分销英文" + "label": "UK" }, { "value": "852", - "label": "中国香港" + "label": "Hong Kong" }, { "value": "886", - "label": "中国台湾" + "label": "Taiwan" }, { "value": "82", - "label": "韩国" + "label": "Korea" } ] }, @@ -1060,10 +1060,9 @@ "parameterType": "NUMBER" } ], - "readmeComment": "Value mapping `[\"91\"\u003d\"印度\",\"44\"\u003d\"分销英文\",\"852\"\u003d\"中国香港\",\"886\"\u003d\"中国台湾\",\"82\"\u003d\"韩国\"]`" + "readmeComment": "Value mapping `[\"91\"\u003d\"India\",\"44\"\u003d\"UK\",\"852\"\u003d\"Hong Kong\",\"886\"\u003d\"Taiwan\",\"82\"\u003d\"Korea\"]`" } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003e`action{\"did\":\"button-toggle-mode\",\"siid\":8,\"aiid\":2,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb4-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb4-miot.json index 272a89602b98c..d35771789ac00 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb4-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.airpurifier.mb4-miot.json @@ -251,7 +251,6 @@ ] } ], - "readmeComment": "Specified action for filter reset \u003cbr /\u003e`action{\"did\":\"filter-reset-filter-life\",\"siid\":4,\"aiid\":1,\"in\":[3.0]}`\u003cbr /\u003eHowever, this has not been successfully tested yet.", "experimental": false } } diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json index 6799cf4dd80e9..1db01bb744dee 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.ma3-miot.json @@ -283,7 +283,6 @@ "actions": [] } ], - "readmeComment": "Identified manual actions for execution\u003cbr /\u003e`action{\"did\":\"private-service-toggle-switch\",\"siid\":8,\"aiid\":1,\"in\":[]}`\u003cbr /\u003ePlease test and feedback if they are working so they can be linked to a channel.", "experimental": true } } From cdaff5322900793b86292c19826ae42457b362fa Mon Sep 17 00:00:00 2001 From: boc-tothefuture Date: Thu, 16 Dec 2021 14:20:22 -0500 Subject: [PATCH 247/361] [chromecast] Added support for next command (#11510) * feat(chromecast): added support for next command Signed-off-by: Brian O'Connell Signed-off-by: Michael Schmidt --- .../org.openhab.binding.chromecast/README.md | 2 +- .../internal/ChromecastCommander.java | 24 +++++++++++++------ .../internal/ChromecastStatusUpdater.java | 8 +++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.binding.chromecast/README.md b/bundles/org.openhab.binding.chromecast/README.md index 2d9fd4b3c0597..1139210721687 100644 --- a/bundles/org.openhab.binding.chromecast/README.md +++ b/bundles/org.openhab.binding.chromecast/README.md @@ -55,7 +55,7 @@ Thing chromecast:audiogroup:bathroom [ ipAddress="192.168.0.23", port=42139] | Channel Type ID | Item Type | Description | |-----------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| control | Player | Player control; currently only supports play/pause and does not correctly update, if the state changes on the device itself | +| control | Player | Player control; currently only supports play/pause/next and does not correctly update, if the state changes on the device itself | | stop | Switch | Send `ON` to this channel: Stops the Chromecast. If this channel is `ON`, the Chromecast is stopped, otherwise it is in another state (see control channel) | | volume | Dimmer | Control the volume, this is also updated if the volume is changed by another app | | mute | Switch | Mute the audio | diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java index 2a031a4bd2def..ef7ad91b3bb33 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastCommander.java @@ -134,13 +134,6 @@ private void handlePlayUri(Command command) { private void handleControl(final Command command) { try { - if (command instanceof NextPreviousType) { - // I can't find a way to control next/previous from the API. The Google app doesn't seem to - // allow it either, so I suspect there isn't a way. - logger.info("{} command not yet implemented", command); - return; - } - Application app = chromeCast.getRunningApp(); statusUpdater.updateStatus(ThingStatus.ONLINE); if (app == null) { @@ -166,6 +159,23 @@ private void handleControl(final Command command) { logger.info("{} command not supported by current media", command); } } + + if (command instanceof NextPreviousType) { + // Next is implemented by seeking to the end of the current media + if (command == NextPreviousType.NEXT) { + + Double duration = statusUpdater.getLastDuration(); + if (duration != null) { + chromeCast.seek(duration.doubleValue() - 5); + } else { + logger.info("{} command failed - unknown media duration", command); + } + } else { + logger.info("{} command not yet implemented", command); + return; + } + } + } catch (final IOException e) { logger.debug("{} command failed: {}", command, e.getMessage()); statusUpdater.updateStatus(ThingStatus.OFFLINE, COMMUNICATION_ERROR, e.getMessage()); diff --git a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastStatusUpdater.java b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastStatusUpdater.java index 8e8581c8daf27..1ce09bf5c69b6 100644 --- a/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastStatusUpdater.java +++ b/bundles/org.openhab.binding.chromecast/src/main/java/org/openhab/binding/chromecast/internal/ChromecastStatusUpdater.java @@ -73,6 +73,9 @@ public class ChromecastStatusUpdater { private @Nullable String appSessionId; private PercentType volume = PercentType.ZERO; + // Null is valid value for last duration + private @Nullable Double lastDuration = null; + public ChromecastStatusUpdater(Thing thing, ChromecastHandler callback) { this.thing = thing; this.callback = callback; @@ -82,6 +85,10 @@ public PercentType getVolume() { return volume; } + public @Nullable Double getLastDuration() { + return lastDuration; + } + public @Nullable String getAppSessionId() { return appSessionId; } @@ -186,6 +193,7 @@ private void updateMediaInfoStatus(final @Nullable Media media) { if (media != null) { metadataType = media.getMetadataType().name(); + lastDuration = media.duration; // duration can be null when a new song is about to play. if (media.duration != null) { duration = new QuantityType<>(media.duration, Units.SECOND); From fd9c3c183ebe2e6fc3f656faf51793d10cccd5f5 Mon Sep 17 00:00:00 2001 From: carlospg79 Date: Fri, 17 Dec 2021 07:57:23 +0100 Subject: [PATCH 248/361] Fixes #8646 - Bugfix for openHAB > 3.1.x (#11776) Signed-off-by: Carlos Primo Signed-off-by: carlospg79 Signed-off-by: Michael Schmidt --- .../lgtvserial/internal/handler/LgTvSerialHandler.java | 6 ++++++ .../internal/protocol/serial/LGSerialCommunicator.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/handler/LgTvSerialHandler.java b/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/handler/LgTvSerialHandler.java index 276657a147013..94c4d3221e4ec 100644 --- a/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/handler/LgTvSerialHandler.java +++ b/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/handler/LgTvSerialHandler.java @@ -170,6 +170,12 @@ public void onFailure(ChannelUID channel, LGSerialResponse response) { if (updateJob == null || updateJob.isCancelled()) { updateJob = scheduler.scheduleWithFixedDelay(eventRunnable, 0, EVENT_REFRESH_INTERVAL, TimeUnit.SECONDS); } + // trigger REFRESH commands for all linked Channels to start polling + getThing().getChannels().forEach(channel -> { + if (isLinked(channel.getUID())) { + channelLinked(channel.getUID()); + } + }); updateStatus(ThingStatus.ONLINE); } diff --git a/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/protocol/serial/LGSerialCommunicator.java b/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/protocol/serial/LGSerialCommunicator.java index b16ed23d94f1d..45b69ba5d275b 100644 --- a/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/protocol/serial/LGSerialCommunicator.java +++ b/bundles/org.openhab.binding.lgtvserial/src/main/java/org/openhab/binding/lgtvserial/internal/protocol/serial/LGSerialCommunicator.java @@ -79,7 +79,7 @@ public synchronized void write(LGSerialCommand command, String rawCommand, Chann int data; int len = 0; int offset = 0; - while ((data = input.read()) > -1) { + while (input.available() > 0 && (data = input.read()) > -1) { if (data == 'x') { String result = new String(buffer, offset, len); if (logger.isDebugEnabled()) { From 9c97537bac534ba5eb0d70dafdfbedc54fb038b3 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Thu, 16 Dec 2021 23:00:44 -0800 Subject: [PATCH 249/361] [jsscripting] Library and Doc updates (#11800) * [jsscripting] Library and Doc updates This updates the documentation, bumps the NPM version library, and implements conversion of JS date types (js-joda) to Java types Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- .../README.md | 618 ++++++++++++++---- .../docs/rule-config.png | Bin 0 -> 157962 bytes .../docs/rule-engines.png | Bin 0 -> 181786 bytes .../docs/rule-script.png | Bin 0 -> 117326 bytes .../docs/settings.png | Bin 0 -> 125391 bytes .../pom.xml | 2 +- .../internal/OpenhabGraalJSScriptEngine.java | 23 +- 7 files changed, 512 insertions(+), 131 deletions(-) create mode 100644 bundles/org.openhab.automation.jsscripting/docs/rule-config.png create mode 100644 bundles/org.openhab.automation.jsscripting/docs/rule-engines.png create mode 100644 bundles/org.openhab.automation.jsscripting/docs/rule-script.png create mode 100644 bundles/org.openhab.automation.jsscripting/docs/settings.png diff --git a/bundles/org.openhab.automation.jsscripting/README.md b/bundles/org.openhab.automation.jsscripting/README.md index 77ae84528f03b..ca04165e78543 100644 --- a/bundles/org.openhab.automation.jsscripting/README.md +++ b/bundles/org.openhab.automation.jsscripting/README.md @@ -1,132 +1,319 @@ # JavaScript Scripting This add-on provides support for JavaScript (ECMAScript 2021+) that can be used as a scripting language within automation rules. -JavaScript scripts provide access to almost all the functionality in an openHAB runtime environment. -- [Creating JavaScript Scripts](#creating-javascript-scripts) -- [Logging](#logging) -- [Core Actions](#core-actions) - - [itemRegistry](#itemregistry) - - [Event Bus Actions](#event-bus-actions) - - [Exec Actions](#exec-actions) - - [HTTP Actions](#http-actions) - - [Timers](#timers) - - [Scripts Actions](#scripts-actions) -- [Cloud Notification Actions](#cloud-notification-actions) -- [Persistence Extensions](#persistence-extensions) -- [Ephemeris Actions](#ephemeris-actions) -- [Types and Units](#types-and-units) +Also included is [openhab-js](https://github.com/openhab/openhab-js/), a fairly high-level ES6 library to support automation in openHAB. It provides convenient access +to common openHAB functionality within rules including items, things, actions, logging and more. -## Creating JavaScript Scripts +- [Configuration](#configuration) +- [UI Based Rules](#ui-based-rules) +- [Scripting Basics](#scripting-basics) + - [require](#require) + - [console](#console) + - [setInterval](#setinterval) + - [setTimeout](#settimeout) + - [scriptLoaded](#scriptloaded) + - [scriptUnLoaded](#scriptunloaded) + - [Paths](#paths) +- [Standard Library](#standard-library) + - [items](#items) + - [actions](#actions) + - [cache](#cache) + - [log](#log) + - [time](#time) +- [File Based Rules](#file-based-rules) + - [JSRule](#jsrule) + - [Rule Builder](#rule-builder) -When this add-on is installed, JavaScript script actions will be run by this add-on and allow ECMAScript 2021+ features. -Alternatively, you can create scripts in the `automation/jsr223` configuration directory. -If you create an empty file called `test.js`, you will see a log line with information similar to: +## Configuration -```text - ... [INFO ] [.a.m.s.r.i.l.ScriptFileWatcher:150 ] - Loading script 'test.js' +This add-on includes by default the [openhab-js](https://github.com/openhab/openhab-js/) NPM library and exports it's namespaces onto the global namespace. This allows the use of `items`, `actions`, `cache` and other objects without the need to explicitly import using `require()`. This functionality can be disabled for users who prefer to manage their own imports via the add-on configuration options. + +![OpenHAB Rule Configuration](./docs/settings.png) + +## UI Based Rules + +The quickest way to add rules is through the openHAB Web UI. + +Advanced users, or users migrating scripts from existing systems may want to use [File Based Rules](#file-based-rules) for managing rules using files in the user configuration directory. + +### Adding Triggers + +Using the openHAB UI, first create a new rule and set a trigger condition + +![OpenHAB Rule Configuration](./docs/rule-config.png) + +### Adding Actions + +Select "Add Action" and then select "ECMAScript 262 Edition 11". Its important this is "Edition 11" or higher, earlier versions will not work. This will bring up a empty script editor where you can enter your javascript. + +![OpenHAB Rule Engines](./docs/rule-engines.png) + +You can now write rules using standard ES6 Javascript along with the included openHAB [standard library](#standard-library). + +![OpenHAB Rule Script](./docs/rule-script.png) + +For example, turning a light on: +```javascript +items.getItem("KitchenLight").sendCommand("ON"); +console.log("Kitchen Light State", items.getItem("KitchenLight").state); +``` + +Sending a notification +```javascript +actions.NotificationAction.sendNotification("romeo@montague.org", "Balcony door is open"); ``` -To enable debug logging, use the [console logging]({{base}}/administration/logging.html) commands to enable debug logging for the automation functionality: +Querying the status of a thing +```javascript +const thingStatusInfo = actions.Things.getThingStatusInfo("zwave:serial_zstick:512"); +console.log("Thing status",thingStatusInfo.getStatus()); +``` + +See [openhab-js](https://openhab.github.io/openhab-js) for a complete list of functionality + +## Scripting Basics + +The openHAB JSScripting runtime attempts to provide a familiar environment to Javascript developers. + +### Require + +Scripts may include standard NPM based libraries by using CommonJS require. The library search path will look in `automation/js/node_modules` in the user configuration directory. + +### Console + +The JSScripting binding supports the standard `console` object for logging. +Script debug logging is enabled by default at the `TRACE` level, but can be configured using the [console logging]({{base}}/administration/logging.html) commands. ```text -log:set DEBUG org.openhab.core.automation +log:set DEBUG org.openhab.automation.script ``` -For more information on the available APIs in scripts see the [JSR223 Scripting]({{base}}/configuration/jsr223.html) documentation. +Supported logging functions include: +- `console.log(obj1 [, obj2, ..., objN])` +- `console.info(obj1 [, obj2, ..., objN])` +- `console.warn(obj1 [, obj2, ..., objN])` +- `console.error(obj1 [, obj2, ..., objN])` +- `console.debug(obj1 [, obj2, ..., objN])` +- `console.trace(obj1 [, obj2, ..., objN])` -The following examples show how to access common openHAB functionalities. +where `obj1 ... objN` is a list of JavaScript objects to output. The string representations of each of these objects are appended together in the order listed and output. -## Logging +see https://developer.mozilla.org/en-US/docs/Web/API/console for more information about console logging. -As a simple example, the following script logs "Hello, World!". -Note that `console.log` will usually not work since the output has no terminal to display the text. -__Please note:__ Support for `console.log` will likely be added together with a logging API in the [helper library](https://github.com/openhab/openhab-js). -The openHAB server uses the [SLF4J](https://www.slf4j.org/) library for logging. +### setTimeout +The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires. ```javascript -let logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + this.ruleUID); -logger.info('Hello world!'); -logger.warn('Successfully logged warning.'); -logger.error('Successfully logged error.'); +var timeoutID = setTimeout(function[, delay, arg1, arg2, ...]); +var timeoutID = setTimeout(function[, delay]); ``` -The script uses the [LoggerFactory](https://www.slf4j.org/apidocs/org/slf4j/Logger.html) to obtain a named logger and then logs a message like: +The global `clearTimeout()` method cancels a timeout previously established by calling `setTimeout()`. -```text - ... [INFO ] [org.openhab.rule. ] - Hello world! - ... [WARN ] [org.openhab.rule. ] - Successfully logged warning. - ... [ERROR] [org.openhab.rule. ] - Successfully logged error. +see https://developer.mozilla.org/en-US/docs/Web/API/setTimeout for more information about setTimeout. + +### setInterval + +The setInterval() method repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. + +```javascript +var intervalID = setInterval(func, [delay, arg1, arg2, ...]); +var intervalID = setInterval(function[, delay]); +``` + +The global `clearInterval()` method cancels a timed, repeating action which was previously established by a call to `setInterval()`. + +NOTE: Timers will not be canceled if a script is deleted or modified, it is up to the user to manage timers. See using the [cache](#cache) namespace as well as [ScriptLoaded](#scriptloaded) and [ScriptUnLoaded](#scriptunloaded) for a convenient way of managing persisted objects, such as timers between reloads or deletions of scripts. + +see https://developer.mozilla.org/en-US/docs/Web/API/setInterval for more information about setInterval. + +### ScriptLoaded + +For file based scripts, this function will be called if found when the script is loaded. + +```javascript +scriptLoaded = function () { + console.log("script loaded"); + loadedDate = Date.now(); +} +``` + +### ScriptUnLoaded + +For file based scripts, this function will be called if found when the script is unloaded. + +```javascript +scriptUnloaded = function () { + console.log("script unloaded"); + //clean up rouge timers + clearInterval(timer); +} ``` -## Core Actions +### Paths + +For [file based rules](#file-based-rules), scripts will be loaded from `automation/js` in the user configuration directory. + +NPM libraries will be loaded from `automation/js/node_modules` in the user configuration directory. + +## Standard Library + +Full documentation for the openHAB JavaScript library can be found at [openhab-js](https://openhab.github.io/openhab-js) + +### Items + +The items namespace allows interactions with openHAB items. + +See [openhab-js : items ](https://openhab.github.io/openhab-js/items.html) for full API documentation -The openHAB services, which are pre-included in the integrated JavaScript engine, must explicitely be imported. +* items : object + * .getItem(name, nullIfMissing) ⇒ Item + * .getItemsByTag(...tagNames) ⇒ Array.<Item> + * .createItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction], [itemMetadata]) + * .addItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction]) + * .removeItem(itemOrItemName) ⇒ Boolean + * .replaceItem(itemName, [itemType], [category], [groups], [label], [tags], [giBaseType], [groupFunction]) + * .safeItemName(s) ⇒ String -__Please note:__ The [helper library](https://github.com/openhab/openhab-js) is on the way and will become the preferred API to work with openHAB. +```javascript +const item = items.getItem("KitchenLight"); +console.log("Kitchen Light State", item.state); +``` + +Calling `getItem(...)` returns an `Item` object with the following properties: + +* Item : object + * .type ⇒ String + * .name ⇒ String + * .label ⇒ String + * .history ⇒ ItemHistory + * .state ⇒ String + * .rawState ⇒ HostState + * .members ⇒ Array.<Item> + * .descendents ⇒ Array.<Item> + * .isUninitialized ⇒ Boolean + * .tags ⇒ Array.<String> + * .getMetadataValue(namespace) ⇒ String + * .updateMetadataValue(namespace, value) ⇒ String + * .upsertMetadataValue(namespace, value) ⇒ Boolean + * .updateMetadataValues(namespaceToValues) + * .sendCommand(value) + * .sendCommandIfDifferent(value) ⇒ Boolean + * .postUpdate(value) + * .addGroups(...groupNamesOrItems) + * .removeGroups(...groupNamesOrItems) + * .addTags(...tagNames) + * .removeTags(...tagNames) ```javascript -let openhab = require('@runtime'); +const item = items.getItem("KitchenLight"); +//send a ON command +item.sendCommand("ON"); +//Post an update +item.postUpdate("OFF"); +//Get state +console.log("KitchenLight state", item.state) ``` -### itemRegistry +calling `item.history...` returns a ItemHistory object with the following functions: + +Note `serviceId` is optional, if omitted, the default persistance service will be used. + +* ItemHistory : object + * .averageSince(timestamp, serviceId) ⇒ Number + * .changedSince(timestamp, serviceId) ⇒ Number + * .deltaSince(timestamp, serviceId) ⇒ Number + * .deviationSince(timestamp, serviceId) ⇒ Number + * .evolutionRate(timestamp, serviceId) ⇒ Number + * .historicState(timestamp, serviceId) ⇒ state + * .lastUpdate(serviceId) ⇒ Date + * .latestState(serviceId) ⇒ state + * .maximumSince(timestamp,serviceId) ⇒ state + * .minimumSince(timestamp,serviceId) ⇒ state + * .persist(serviceId) + * .previousState(skipEqual,serviceId) ⇒ state + * .sumSince(timestamp, serviceId) ⇒ Number + * .updatedSince(timestamp, serviceId) ⇒ Boolean + * .varianceSince(timestamp,serviceId) ⇒ state ```javascript -let state = openhab.itemRegistry.getItem(itemName).getState(); +var yesterday = new Date(new Date().getTime() - (24 * 60 * 60 * 1000)); +var item = items.getItem("KitchenDimmer"); +console.log("KitchenDimmer averageSince", item.history.averageSince(yesterday)); ``` -You can use `toString()` to convert an item's state to string or `toBigDecimal()` to convert to number. +### Actions + +The actions namespace allows interactions with openHAB actions. The following are a list of standard actions. + +Additional actions provided by user installed addons can be accessed using their common name on the actions name space +(example: `actions.Pushsafer.pushsafer(...)`) + +See [openhab-js : actions ](https://openhab.github.io/openhab-js/actions.html) for full API documentation and additional actions. + +#### Audio Actions + +See [openhab-js : actions.Audio ](https://openhab.github.io/openhab-js/actions.html#.Audio) for complete documentation + +### BusEvent -### Event Bus Actions +See [openhab-js : actions.BusEvent ](https://openhab.github.io/openhab-js/actions.html#.BusEvent) for complete documentation + +## Ephemeris Actions + +See [openhab-js : actions.Ephemeris ](https://openhab.github.io/openhab-js/actions.html#.Ephemeris) for complete documentation + +Ephemeris is a way to determine what type of day today or a number of days before or after today is. For example, a way to determine if today is a weekend, a bank holiday, someone’s birthday, trash day, etc. + +Additional information can be found on the [Ephemeris Actions Docs](https://www.openhab.org/docs/configuration/actions.html#ephemeris) as well as the [Ephemeris JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris). ```javascript -openhab.events.sendCommand(itemName, command); -openhab.events.postUpdate(itemName, state); +// Example +let weekend = actions.Ephemeris.isWeekend(); ``` -`command` and `state` can be a string `'string'` or a number depending on the item. +#### Exec Actions -### Exec Actions +See [openhab-js : actions.Exec ](https://openhab.github.io/openhab-js/actions.html#.Exec) for complete documentation Execute a command line. ```javascript -openhab.Exec = Java.type('org.openhab.core.model.script.actions.Exec'); -let Duration = Java.type('java.time.Duration'); // Execute command line. -openhab.Exec.executeCommandLine('echo', 'Hello World!'); +actions.Exec.executeCommandLine('echo', 'Hello World!'); // Execute command line with timeout. -openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); +let Duration = Java.type('java.time.Duration'); +actions.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); // Get response from command line. -let response = openhab.Exec.executeCommandLine('echo', 'Hello World!'); +let response = actions.Exec.executeCommandLine('echo', 'Hello World!'); // Get response from command line with timeout. -response = openhab.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); +response = actions.Exec.executeCommandLine(Duration.ofSeconds(20), 'echo', 'Hello World!'); ``` ### HTTP Actions -For available actions have a look at the [HTTP Actions Docs](https://www.openhab.org/docs/configuration/actions.html#http-actions). +See [openhab-js : actions.HTTP ](https://openhab.github.io/openhab-js/actions.html#.HTTP) for complete documentation ```javascript -openhab.HTTP = Java.type('org.openhab.core.model.script.actions.HTTP'); - // Example GET Request -var response = openhab.HTTP.sendHttpGetRequest(''); +var response = actions.HTTP.sendHttpGetRequest(''); ``` Replace `` with the request url. -### Timers +### ScriptExecution Actions + +See [openhab-js : actions.ScriptExecution ](https://openhab.github.io/openhab-js/actions.html#.ScriptExecution) for complete documentation + ```javascript -let ZonedDateTime = Java.type('java.time.ZonedDateTime'); -let now = ZonedDateTime.now(); -openhab.ScriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution'); +let now = time.ZonedDateTime.now(); // Function to run when the timer goes off. function timerOver () { @@ -134,7 +321,7 @@ function timerOver () { } // Create the Timer. -this.myTimer = openhab.ScriptExecution.createTimer(now.plusSeconds(10), timerOver); +this.myTimer = actions.ScriptExecution.createTimer(now.plusSeconds(10), timerOver); // Cancel the timer. this.myTimer.cancel(); @@ -145,106 +332,279 @@ let active = this.myTimer.isActive(); // Reschedule the timer. this.myTimer.reschedule(now.plusSeconds(5)); ``` +### Semantics Actions -### Scripts Actions +See [openhab-js : actions.Semantics ](https://openhab.github.io/openhab-js/actions.html#.Semantics) for complete documentation -Call scripts created in the UI (Settings -> Scripts) with or without parameters. +### Things Actions -```javascript -openhab.scriptExtension = Java.type('org.openhab.core.automation.module.script.ScriptExtensionProvider'); -let bundleContext = Java.type('org.osgi.framework.FrameworkUtil').getBundle(openhab.scriptExtension.class).getBundleContext(); -openhab.RuleManager = bundleContext.getService(bundleContext.getServiceReference('org.openhab.core.automation.RuleManager')); +See [openhab-js : actions.Things ](https://openhab.github.io/openhab-js/actions.html#.Things) for complete documentation -// Simple call. -openhab.RuleManager.runNow(''); +### Voice Actions -// Advanced call with arguments. -let map = new java.util.HashMap(); -map.put('identifier1', 'value1'); -map.put('identifier2', 'value2'); -// Second argument is whether to consider the conditions, third is a Map (a way to pass data). -openhab.RuleManager.runNow('', true, map); -``` +See [openhab-js : actions.Voice ](https://openhab.github.io/openhab-js/actions.html#.Voice) for complete documentation -Replace `` with your script's (unique-)id. +### Cloud Notification Actions -## Cloud Notification Actions +(optional action if openhab-cloud is installed) Notification actions may be placed in Rules to send alerts to mobile devices registered with an [openHAB Cloud instance](https://github.com/openhab/openhab-cloud) such as [myopenHAB.org](https://myopenhab.org/). For available actions have a look at the [Cloud Notification Actions Docs](https://www.openhab.org/docs/configuration/actions.html#cloud-notification-actions). ```javascript -openhab.NotificationAction = Java.type('org.openhab.io.openhabcloud.NotificationAction') - // Example -openhab.NotificationAction.sendNotification('', ''); // to a single myopenHAB user identified by e-mail -openhab.NotificationAction.sendBroadcastNotification(''); // to all myopenHAB users +actions.NotificationAction.sendNotification('', ''); // to a single myopenHAB user identified by e-mail +actions.NotificationAction.sendBroadcastNotification(''); // to all myopenHAB users ``` Replace `` with the e-mail address of the user. Replace `` with the notification text. -## Persistence Extensions +### Cache + +The cache namespace provides a default cache that can be use to set and retrieve objects that will be persisted between reloads of scripts. + +See [openhab-js : cache ](https://openhab.github.io/openhab-js/cache.html) for full API documentation + +* cache : object + * .get(key, defaultSupplier) ⇒ Object | null + * .put(key, value) ⇒ Previous Object | null + * .remove(key) ⇒ Previous Object | null -For available commands have a look at [Persistence Extensions in Scripts ans Rules](https://www.openhab.org/docs/configuration/persistence.html#persistence-extensions-in-scripts-and-rules). +The `defaultSupplier` provided function will return a default value if a specified key is not already associated with a value -For deeper information have a look at the [Persistence Extensions JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/persistence/extensions/persistenceextensions). +**Example** *(Get a previously set value with a default value (times = 0))* +```js +let counter = cache.get("counter", () => ({ "times": 0 })); +console.log("Count",counter.times++); +``` + +**Example** *(Get a previously set object)* +```js +let counter = cache.get("counter"); +if(counter == null){ + counter = {times: 0}; + cache.put("counter", counter); +} +console.log("Count",counter.times++); +``` +### Log + +By default the JS Scripting binding supports console logging like `console.log()` and `console.debug()` to the openHAB +default log. Additionally scripts may create their own native openHAB logs using the log namespace ```javascript -openhab.PersistenceExtensions = Java.type('org.openhab.core.persistence.extensions.PersistenceExtensions'); -let ZonedDateTime = Java.type('java.time.ZonedDateTime'); -let now = ZonedDateTime.now(); +let logger = log('my_logger'); -// Example -var avg = openhab.PersistenceExtensions.averageSince(itemRegistry.getItem(''), now.minusMinutes(5), "influxdb"); +//prints "Hello World!" +logger.debug("Hello {}!", "world"); ``` -Replace `` with the persistence service to use. -Replace `` with the itemname. +### Time -## Ephemeris Actions +openHAB internally makes extensive use of the `java.time` package. openHAB-JS exports the excellent [JS-Joda](#https://js-joda.github.io/js-joda/) library via the `time` namespace, which is a native Javascript port of the same API standard used in Java for `java.time`. Anywhere that a native Java `ZonedDateTime` or `Duration` is required, the runtime will automatically convert a JS-Joda `ZonedDateTime` or `Duration` to its Java counterpart. -Ephemeris is a way to determine what type of day today or a number of days before or after today is. For example, a way to determine if today is a weekend, a bank holiday, someone’s birthday, trash day, etc. +Examples: +```javascript +var now = time.ZonedDateTime.now(); +var yesterday = time.ZonedDateTime.now().minusHours(24); -For available actions, have a look at the [Ephemeris Actions Docs](https://www.openhab.org/docs/configuration/actions.html#ephemeris). +var item = items.getItem("Kitchen"); +console.log("averageSince", item.history.averageSince(yesterday)); +``` + +```javascript +actions.Exec.executeCommandLine(time.Duration.ofSeconds(20), 'echo', 'Hello World!'); +``` + +See [JS-Joda](#https://js-joda.github.io/js-joda/) for more examples and complete API usage. + +## File Based Rules + +The JSScripting binding will load scripts from `automation/js` in the user configuration directory. The system will automatically reload scripts when changes are detected to files. Local variable state is not persisted among reloads, see using the [cache](#cache) for a connivent way to persist objects. + +File based rules can be created in 2 different ways: using [JSRule](#jsrule) or the [Rule Builder](#rule-builder). + +See [openhab-js : rules ](https://openhab.github.io/openhab-js/rules.html) for full API documentation -For deeper information have a look at the [Ephemeris JavaDoc](https://www.openhab.org/javadoc/latest/org/openhab/core/model/script/actions/ephemeris). +### JSRule + +JSRules provides a simple, declarative syntax for defining rules that will be executed based on a trigger condition ```javascript -openhab.Ephemeris = Java.type('org.openhab.core.model.script.actions.Ephemeris'); +const email = "juliet@capulet.org" + +rules.JSRule({ + name: "Balcony Lights ON at 5pm", + description: "Light will turn on when it's 5:00pm", + triggers: [triggers.GenericCronTrigger("0 0 17 * * ?")], + execute: data => { + items.getItem("BalconyLights").sendCommand("ON"); + actions.NotificationAction.sendNotification(email, "Balcony lights are ON"); + } +}); +``` + +Multiple triggers can be added, some example triggers include: + +```javascript +triggers.ChannelEventTrigger('astro:sun:local:rise#event', 'START') + +triggers.ItemStateChangeTrigger('my_item', 'OFF', 'ON') + +triggers.ItemStateUpdateTrigger('my_item', 'OFF') + +triggers.ItemCommandTrigger('my_item', 'OFF') + +triggers.GroupStateChangeTrigger('my_group', 'OFF', 'ON') + +triggers.GroupStateUpdateTrigger('my_group', 'OFF') + +triggers.GroupCommandTrigger('my_group', 'OFF') + +triggers.ThingStatusUpdateTrigger('some:thing:uuid','OFFLINE') + +triggers.ThingStatusChangeTrigger('some:thing:uuid','ONLINE','OFFLINE') + +triggers.SystemStartlevelTrigger(40) //Rules loaded + +triggers.SystemStartlevelTrigger(50) //Rule engine started + +triggers.SystemStartlevelTrigger(70) //User interfaces started + +triggers.SystemStartlevelTrigger(80) //Things initialized + +triggers.SystemStartlevelTrigger(100) //Startup Complete + +triggers.GenericCronTrigger('0 30 16 * * ? *') + +triggers.TimeOfDayTrigger('19:00') -// Example -let weekend = openhab.Ephemeris.isWeekend(); ``` -## Types and Units +See [openhab-js : triggers ](https://openhab.github.io/openhab-js/triggers.html) in the API documentation for a full list of all triggers. + +### Rule Builder + +The Rule Builder provides a convenient API to write rules in a high-level, readable style using a builder pattern. -Import types from openHAB Core for type conversion and more. -Import Units from openHAB Core for unit conversion and more. +Rules are started by calling `rules.when()` and can chain together [triggers](#rule-builder-triggers), +[conditions](#rule-builder-conditions) and [operations](#rule-builder-operations) in the following pattern: ```javascript -openhab.typeOrUnit = Java.type('org.openhab.core.library.types.typeOrUnit'); +rules.when().triggerType()...if().conditionType().then().operationType()...build(name,description); +``` -// Example -openhab.HSBType = Java.type('org.openhab.core.library.types.HSBType'); -let hsb = openhab.HSBType.fromRGB(4, 6, 9); -``` - -Available types are: -* `QuantityType` -* `StringListType` -* `RawType` -* `DateTimeType` -* `DecimalType` -* `HSBType` -* `PercentType` -* `PointType` -* `StringType` - -Available untis are: -* `SIUnits` -* `ImperialUnits` -* `MetricPrefix` -* `Units` -* `BinaryPrefix` +Rule are completed by calling `.build(name,description)` , if name or description are omitted, a generated value will be used. + +A simple example of this would look like: + +```javascript +rules.when().item("F1_Light").changed().then().send("changed").toItem("F2_Light").build("My Rule", "My First Rule"); +``` + +Operations and conditions can also optionally take functions: + +```javascript +rules.when().item("F1_light").changed().then(event => { + console.log(event); +}).build("Test Rule", "My Test Rule"); +``` +see [Examples](#rule-builder-examples) for further patterns + +#### Rule Builder Triggers + +* `when()` +* `or()` + * `.channel(channelName)` Specifies a channel event as a source for the rule to fire. + * `.triggered(event)` Trigger on a specific event name + * `.cron(cronExpression)` Specifies a cron schedule for the rule to fire. + * `.item(itemName)` Specifies an item as the source of changes to trigger a rule. + * `.for(duration)` + * `.from(state)` + * `.to(state)` + * `.fromOff()` + * `.toOn()` + * `.receivedCommand()` + * `.receivedUpdate()` + * `.memberOf(groupName)` + * `.for(duration)` + * `.from(state)` + * `.to(state)` + * `.fromOff()` + * `.toOn()` + * `.receivedCommand()` + * `.receivedUpdate()` + * `.system()` + * `.ruleEngineStarted()` + * `.rulesLoaded()` + * `.startupComplete()` + * `.thingsInitialized()` + * `.userInterfacesStarted()` + * `.startLevel(level)` + * `.thing(thingName)` + * `changed()` + * `updated()` + * `from(state)` + * `to(state)` + +Additionally all the above triggers have the following functions: +* `.if()` or `.if(fn)` -> a [rule condition](#rule-builder-conditions) +* `.then()` or `.then(fn)` -> a [rule operation](#rule-builder-operations) +* `.or()` -> a [rule trigger](#rule-builder-triggers) (chain additional triggers) + +#### Rule Builder Conditions + +* `if(optionalFunction)` + * `.stateOfItem(state)` + +#### Rule Builder Operations +* `then(optionalFunction)` + * `.build(name, description)` + * `.copyAndSendState()` + * `.copyState()` + * `.inGroup(groupName)` + * `.postIt()` + * `.postUpdate(state)` + * `.send(command)` + * `.sendIt()` + * `.sendOff()` + * `.sendOn()` + * `.sendToggle()` + +#### Rule Builder Examples + +```javascript +//Basic rule, when the BedroomLight1 is changed, run a custom function +rules.when().item('BedroomLight1').changed().then(e => { + console.log("BedroomLight1 state", e.newState) +}.build(); + +//turn on the kitchen light at SUNSET +rules.when().timeOfDay("SUNSET").then().sendOn().toItem("KitchenLight").build("Sunset Rule","turn on the kitchen light +at SUNSET"); + +//turn off the kitchen light at 9PM +rules.when().cron("0 0 21 * * ?").then().sendOff().toItem("KitchenLight").build("9PM Rule", "turn off the kitchen light +at 9PM"); + +//set the colour of the hall light to pink at 9PM +rules.when().cron("0 0 21 * * ?").then().send("300,100,100").toItem("HallLight").build("Pink Rule", "set the colour of +the hall light to pink at 9PM"); + +//when the switch S1 status changes to ON, then turn on the HallLight +rules.when().item('S1').changed().toOn().then(sendOn().toItem('HallLight')).build("S1 Rule"); + +//when the HallLight colour changes pink, if the function fn returns true, then toggle the state of the OutsideLight +rules.when().item('HallLight').changed().to("300,100,100").if(fn).then().sendToggle().toItem('OutsideLight').build(); + +//and some rules which can be toggled by the items created in the 'gRules' Group: + +//when the HallLight receives a command, send the same command to the KitchenLight +rules.when().item('HallLight').receivedCommand().then().sendIt().toItem('KitchenLight').build("Hall Light", ""); + +//when the HallLight is updated to ON, make sure that BedroomLight1 is set to the same state as the BedroomLight2 +rules.when().item('HallLight').receivedUpdate().then().copyState().fromItem('BedroomLight1').toItem('BedroomLight2').build(); + +``` diff --git a/bundles/org.openhab.automation.jsscripting/docs/rule-config.png b/bundles/org.openhab.automation.jsscripting/docs/rule-config.png new file mode 100644 index 0000000000000000000000000000000000000000..e26c6a07cd11601e59035c20743695d7d3eb07c4 GIT binary patch literal 157962 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 literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.jsscripting/pom.xml b/bundles/org.openhab.automation.jsscripting/pom.xml index aad7fb28b6fd9..af6b049e298d2 100644 --- a/bundles/org.openhab.automation.jsscripting/pom.xml +++ b/bundles/org.openhab.automation.jsscripting/pom.xml @@ -25,7 +25,7 @@ 21.3.0 6.2.1 ${project.version} - openhab@1.2.0 + openhab@1.2.1 diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index f4939baa0f08b..d9a9e60916f10 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -25,6 +25,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.FileAttribute; +import java.time.Duration; +import java.time.ZonedDateTime; import java.util.Collections; import java.util.Map; import java.util.Set; @@ -38,6 +40,8 @@ import org.eclipse.jdt.annotation.Nullable; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Engine; +import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.Value; import org.openhab.automation.jsscripting.internal.fs.DelegatingFileSystem; import org.openhab.automation.jsscripting.internal.fs.PrefixedSeekableByteChannel; import org.openhab.automation.jsscripting.internal.fs.ReadOnlySeekableByteArrayChannel; @@ -77,10 +81,27 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi public OpenhabGraalJSScriptEngine(@Nullable String injectionCode) { super(null); // delegate depends on fields not yet initialised, so we cannot set it immediately this.globalScript = GLOBAL_REQUIRE + (injectionCode != null ? injectionCode : ""); + + // Custom translate JS Objects - > Java Objects + HostAccess hostAccess = HostAccess.newBuilder(HostAccess.ALL) + // Translate JS-Joda ZonedDateTime to java.time.ZonedDateTime + .targetTypeMapping(Value.class, ZonedDateTime.class, (v) -> v.hasMember("withFixedOffsetZone"), v -> { + return ZonedDateTime + .parse(v.invokeMember("withFixedOffsetZone").invokeMember("toString").asString()); + }, HostAccess.TargetMappingPrecedence.LOW) + + // Translate JS-Joda Duration to java.time.Duration + .targetTypeMapping(Value.class, Duration.class, + // picking two members to check as Duration has many common function names + (v) -> v.hasMember("minusDuration") && v.hasMember("toNanos"), v -> { + return Duration.ofNanos(v.invokeMember("toNanos").asLong()); + }, HostAccess.TargetMappingPrecedence.LOW) + .build(); + delegate = GraalJSScriptEngine.create( Engine.newBuilder().allowExperimentalOptions(true).option("engine.WarnInterpreterOnly", "false") .build(), - Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true) + Context.newBuilder("js").allowExperimentalOptions(true).allowAllAccess(true).allowHostAccess(hostAccess) .option("js.commonjs-require-cwd", JSDependencyTracker.LIB_PATH) .option("js.nashorn-compat", "true") // to ease migration .option("js.ecmascript-version", "2021") // nashorn compat will enforce es5 compatibility, we From 8b320dc34669fb12e9e10a1ef9893a50237f0b48 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Fri, 17 Dec 2021 08:14:38 +0100 Subject: [PATCH 250/361] New Crowdin updates (#11795) * New translations js.properties (German) * New translations scale.properties (German) * New translations exec.properties (German) * New translations mpd.properties (German) * New translations qbus.properties (Dutch) * New translations tankerkoenig.properties (German) * New translations js.properties (German) * New translations tankerkoenig.properties (German) Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/exec_de.properties | 30 ++++---- .../resources/OH-INF/i18n/mpd_de.properties | 11 ++- .../resources/OH-INF/i18n/qbus_nl.properties | 75 ++++++++----------- .../OH-INF/i18n/tankerkoenig_de.properties | 48 ++++++------ .../resources/OH-INF/i18n/js_de.properties | 8 ++ .../resources/OH-INF/i18n/scale_de.properties | 8 ++ 6 files changed, 98 insertions(+), 82 deletions(-) create mode 100644 bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties create mode 100644 bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties diff --git a/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec_de.properties b/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec_de.properties index 81e50ae540b68..7f6441326a7e2 100644 --- a/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec_de.properties +++ b/bundles/org.openhab.binding.exec/src/main/resources/OH-INF/i18n/exec_de.properties @@ -1,33 +1,35 @@ -############### # binding + binding.exec.name = Exec Binding binding.exec.description = Binding zur Ausführung von Befehlen und zur Verarbeitung des Rückgabewerts -############### # thing types + thing-type.exec.command.label = Befehl thing-type.exec.command.description = Befehl zur Ausführung und Verarbeitung des Rückgabewertes -# thing type configuration +# thing types config + +thing-type.config.exec.command.autorun.label = Autorun +thing-type.config.exec.command.autorun.description = Wenn aktiv, dann wird der Befehl jedes Mal ausgeführt, wenn sich der Eingabewert ändert thing-type.config.exec.command.command.label = Befehl thing-type.config.exec.command.command.description = Der auszuführende Befehl -thing-type.config.exec.command.transform.label = Transformation -thing-type.config.exec.command.transform.description = Transformation des Rückgabewertes des Befehls, z.B. REGEX((.*)) liefert den Rückgabewert unverändert thing-type.config.exec.command.interval.label = Intervall thing-type.config.exec.command.interval.description = Intervall in Sekunden, in welchem der Befehl ausgeführt wird thing-type.config.exec.command.timeout.label = Timeout thing-type.config.exec.command.timeout.description = Timeout in Sekunden, nach dem die Ausführung des Befehls abgebrochen wird -thing-type.config.exec.command.autorun.label = Autorun -thing-type.config.exec.command.autorun.description = Wenn aktiv, dann wird der Befehl jedes Mal ausgeführt, wenn sich der Eingabewert ändert +thing-type.config.exec.command.transform.label = Transformation +thing-type.config.exec.command.transform.description = Transformation des Rückgabewertes des Befehls, z.B. REGEX((.*)) liefert den Rückgabewert unverändert + +# channel types -# channel type -channel-type.exec.output.label = Rückgabewert -channel-type.exec.output.description = Rückgabewert der Befehlsausführung -channel-type.exec.input.label = Eingabewert -channel-type.exec.input.description = Eingabewert, der als zweiter Parameter an den Befehl übergeben wird channel-type.exec.exit.label = Rückgabestatus channel-type.exec.exit.description = Dokumentiert die erfolgreiche Ausführung +channel-type.exec.input.label = Eingabewert +channel-type.exec.input.description = Eingabewert, der als zweiter Parameter an den Befehl übergeben wird +channel-type.exec.lastexecution.label = Zeitpunkt der letzten Ausführung +channel-type.exec.lastexecution.description = Datum und Uhrzeit der letzten Ausführung des Befehls im Format yyyy-MM-dd'T'HH\:mm\:ss.SSSZ +channel-type.exec.output.label = Rückgabewert +channel-type.exec.output.description = Rückgabewert der Befehlsausführung channel-type.exec.run.label = Ausführung channel-type.exec.run.description = Steht während der Befehlsausführung auf ON; durch Setzen auf ON wird der Befehl sofort ausgeführt -channel-type.exec.lastexecution.label = Zeitpunkt der letzten Ausführung -channel-type.exec.lastexecution.description = Datum und Uhrzeit der letzten Ausführung des Befehls im Format yyyy-MM-dd'T'HH:mm:ss.SSSZ diff --git a/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd_de.properties b/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd_de.properties index c44157c055fa6..efbc6eed08e85 100644 --- a/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd_de.properties +++ b/bundles/org.openhab.binding.mpd/src/main/resources/OH-INF/i18n/mpd_de.properties @@ -1,19 +1,24 @@ +# binding + binding.mpd.name = MPD Binding binding.mpd.description = Das MPD Binding erlaubt es Music Player Daemons zu steuern. # thing types + thing-type.mpd.mpd.label = Music Player Daemon thing-type.mpd.mpd.description = Music Player Daemon -# thing type config description +# thing types config + thing-type.config.mpd.mpd.ipAddress.label = IP-Adresse thing-type.config.mpd.mpd.ipAddress.description = Lokale IP-Adresse oder Hostname des Music Player Daemons. -thing-type.config.mpd.mpd.port.label = Port -thing-type.config.mpd.mpd.port.description = Port des Music Player Daemons. thing-type.config.mpd.mpd.password.label = Passwort thing-type.config.mpd.mpd.password.description = Passwort zur Authentifizierung am Music Player Daemon. +thing-type.config.mpd.mpd.port.label = Port +thing-type.config.mpd.mpd.port.description = Port des Music Player Daemons. # channel types + channel-type.mpd.currentalbum.label = Album channel-type.mpd.currentalbum.description = Zeigt das Album des aktuellen Stücks an. channel-type.mpd.currentname.label = Aktueller Name diff --git a/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus_nl.properties b/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus_nl.properties index c1e57f9cd1066..d9f8602d46008 100644 --- a/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus_nl.properties +++ b/bundles/org.openhab.binding.qbus/src/main/resources/OH-INF/i18n/qbus_nl.properties @@ -1,74 +1,60 @@ # binding + binding.qbus.name = Qbus Binding binding.qbus.description = Deze binding maakt via een server applicate verbinding met de Qbus controller. # thing types + thing-type.qbus.bridge.label = Qbus Bridge thing-type.qbus.bridge.description = De Qbus Bridge Maakt Verbinding Met de Qbus Server. -thing-type.config.qbus.bridge.addr.label = IP Adres of Host Naam -thing-type.config.qbus.bridge.addr.description = IP adres van de Qbus server, meestal 'localhost' -thing-type.config.qbus.bridge.sn.label = Serienummer van de Controller -thing-type.config.qbus.bridge.sn.description = Serienummer van de CTD controller -thing-type.config.qbus.bridge.port.label = Poort -thing-type.config.qbus.bridge.port.description = Communicatiepoort van de Qbus server (standaard: 8447) -thing-type.config.qbus.bridge.serverCheck.label = Server Connectie -thing-type.config.qbus.bridge.serverCheck.description = Ingestelde timer, bij het verlopen van de timer zal de communicatie met de Qbus server gecontroleerd worden en indien nodig herstart. - +thing-type.qbus.co2.label = CO2 +thing-type.qbus.co2.description = Alle CO2 Uitgangen +thing-type.qbus.dimmer.label = Dimmer +thing-type.qbus.dimmer.description = Alle Dimbare Uitgangen thing-type.qbus.onOff.label = Aan/uit thing-type.qbus.onOff.description = Alle Bistabiel-Mono-Timer-Interval uitgangen -thing-type.config.qbus.onOff.bistabielId.label = Qbus ID -thing-type.config.qbus.onOff.bistabielId.description = Identificatienummer van de uitgang (zie SMIII) - +thing-type.qbus.rollershutter.label = Rolluik +thing-type.qbus.rollershutter.description = Alle Rolluik (ROL02P) Uitgangen +thing-type.qbus.rollershutter_slats.label = Rolluik (met lamellen) +thing-type.qbus.rollershutter_slats.description = Alle schermen met lamellen (ROL02P) uitgang thing-type.qbus.scene.label = Sfeer thing-type.qbus.scene.description = Alle sferen -thing-type.config.qbus.scene.sceneId.label = Qbus ID -thing-type.config.qbus.scene.sceneId.description = Identificatienummer van de sfeer (zie SMIII) +thing-type.qbus.thermostat.label = Thermostaat +thing-type.qbus.thermostat.description = Alle thermostaten -thing-type.qbus.co2.label = CO2 -thing-type.qbus.co2.description = Alle CO2 Uitgangen +# thing types config + +thing-type.config.qbus.bridge.addr.label = IP Adres of Host Naam +thing-type.config.qbus.bridge.addr.description = IP adres van de Qbus server, meestal 'localhost' +thing-type.config.qbus.bridge.port.label = Poort +thing-type.config.qbus.bridge.port.description = Communicatiepoort van de Qbus server (standaard\: 8447) +thing-type.config.qbus.bridge.serverCheck.label = Server Connectie +thing-type.config.qbus.bridge.serverCheck.description = Ingestelde timer, bij het verlopen van de timer zal de communicatie met de Qbus server gecontroleerd worden en indien nodig herstart. +thing-type.config.qbus.bridge.sn.label = Serienummer van de Controller +thing-type.config.qbus.bridge.sn.description = Serienummer van de CTD controller thing-type.config.qbus.co2.co2Id.label = Qbus ID thing-type.config.qbus.co2.co2Id.description = Identificatienummer van de uitgang (zie SMIII) - -thing-type.qbus.dimmer.label = Dimmer -thing-type.qbus.dimmer.description = Alle Dimbare Uitgangen thing-type.config.qbus.dimmer.dimmerId.label = Qbus ID thing-type.config.qbus.dimmer.dimmerId.description = Identificatienummer van de uitgang (zie SMIII) thing-type.config.qbus.dimmer.step.label = Stappenwaarde thing-type.config.qbus.dimmer.step.description = Waarde gebruikt voor het dimmen in stappen (standaard 10%) - -thing-type.qbus.rollershutter.label = Rolluik -thing-type.qbus.rollershutter.description = Alle Rolluik (ROL02P) Uitgangen +thing-type.config.qbus.onOff.bistabielId.label = Qbus ID +thing-type.config.qbus.onOff.bistabielId.description = Identificatienummer van de uitgang (zie SMIII) thing-type.config.qbus.rollershutter.rolId.label = Qbus ID thing-type.config.qbus.rollershutter.rolId.description = Identificatienummer van de uitgang (zie SMIII) - -thing-type.qbus.rollershutter_slats.label = Rolluik (met lamellen) -thing-type.qbus.rollershutter_slats.description = Alle schermen met lamellen (ROL02P) uitgang thing-type.config.qbus.rollershutter_slats.rolId.label = Qbus ID thing-type.config.qbus.rollershutter_slats.rolId.description = Identificatienummer van de uitgang (zie SMIII) - -thing-type.qbus.thermostat.label = Thermostaat -thing-type.qbus.thermostat.description = Alle thermostaten +thing-type.config.qbus.scene.sceneId.label = Qbus ID +thing-type.config.qbus.scene.sceneId.description = Identificatienummer van de sfeer (zie SMIII) thing-type.config.qbus.thermostat.thermostatId.label = Qbus ID thing-type.config.qbus.thermostat.thermostatId.description = Identificatienummer van de uitgang (zie SMIII) -channel-type.qbus.scene.label = Sfeer -channel-type.qbus.scene.description = Bediening van de sfeer +# channel types channel-type.qbus.co2.label = CO2 channel-type.qbus.co2.description = Uitlezing van de CO2 waarde - -channel-type.qbus.switch.label = Schakelaar -channel-type.qbus.switch.description = Schakelaar bediening van de uitgangen - -channel-type.qbus.brightness.label = Helderheid -channel-type.qbus.brightness.description = Helderheid bediening van de uitgangen - channel-type.qbus.measured.label = Gemeten Temperatuur channel-type.qbus.measured.description = Uitlezing van de gemeten Temperatuur - -channel-type.qbus.setpoint.label = Ingestelde Temperatuur -channel-type.qbus.setpoint.description = Ingestelde temperatuur bediening van de uitgangen - channel-type.qbus.mode.label = Ingesteld Regime channel-type.qbus.mode.description = Regime bediening van de uitgangen channel-type.qbus.mode.state.option.0 = Manueel @@ -76,10 +62,11 @@ channel-type.qbus.mode.state.option.1 = Vorst channel-type.qbus.mode.state.option.2 = Economisch channel-type.qbus.mode.state.option.3 = Comfort channel-type.qbus.mode.state.option.4 = Nacht - channel-type.qbus.rollershutter.label = Rolluik Bediening channel-type.qbus.rollershutter.description = Rolluik bediening van de uitgangen - +channel-type.qbus.scene.label = Sfeer +channel-type.qbus.scene.description = Bediening van de sfeer +channel-type.qbus.setpoint.label = Ingestelde Temperatuur +channel-type.qbus.setpoint.description = Ingestelde temperatuur bediening van de uitgangen channel-type.qbus.slats.label = Lamellen Bediening channel-type.qbus.slats.description = Lamellen bediening van de uitgangen - diff --git a/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig_de.properties b/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig_de.properties index fc1c4c18d86e0..d0155d5ef6252 100644 --- a/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig_de.properties +++ b/bundles/org.openhab.binding.tankerkoenig/src/main/resources/OH-INF/i18n/tankerkoenig_de.properties @@ -1,29 +1,35 @@ # binding + binding.tankerkoenig.name = Tankerkönig Binding -binding.tankerkoenig.description = Das Tankerkönig Binding ermöglicht es über die Tankerkoenig.de API Spritpreise von deutschen Tankstellen abzurufen. +binding.tankerkoenig.description = Das Tankerkönig Binding ermöglicht es Spritpreise von deutschen Tankstellen abzurufen. # thing types -thing-type.tankerkoenig.webservice.label = Tankerkönig Webservice -thing-type.tankerkoenig.webservice.description = Der Tankerkönig Werbservice ermöglicht es die Spritpreise von 1 bis 10 Tankstellen abzufragen. -thing-type.config.tankerkoenig.webservice.apikey.label=API-Key -thing-type.config.tankerkoenig.webservice.apikey.description=Tankerkönig API-Key. Der Schlüssel ist auf der Tankerkönig Webseite erhältlich. -thing-type.config.tankerkoenig.webservice.refresh.label=Aktualisierungsintervall -thing-type.config.tankerkoenig.webservice.refresh.description=Spezifiziert das Aktualisierungsintervall in Minuten. Minimum 5 Minuten. -thing-type.config.tankerkoenig.webservice.modeOpeningTime.label=Öffnungszeiten -thing-type.config.tankerkoenig.webservice.modeOpeningTime.description=Im Mode Öffnungszeiten werden nur die zur Zeit geöffneten Tankstellen abgefragt. -thing-type.tankerkoenig.station.label=Tankstelle -thing-type.tankerkoenig.station.description=Stellt die Informationen zu den E5-, E10-, und Diesel-Preisen einer Tankstelle bereit. -thing-type.config.tankerkoenig.station.locationid.label=Tankstellen-ID -thing-type.config.tankerkoenig.station.locationid.description=Tankstellen-ID. Die ID ist auf der Tankerkönig Webseite erhältlich. + +thing-type.tankerkoenig.station.label = Tankstelle +thing-type.tankerkoenig.station.description = Fasst Spritpreise für E5, E10 und Diesel einer Tankstelle zusammen. +thing-type.tankerkoenig.webservice.label = Tankerkönig Konto +thing-type.tankerkoenig.webservice.description = Ermöglicht den Zugriff auf die Tankerkönig API. + +# thing types config + +thing-type.config.tankerkoenig.station.locationid.label = ID der Tankstelle +thing-type.config.tankerkoenig.station.locationid.description = ID zur Identifikation der Tankstelle. Die ID ist auf der Tankerkönig Webseite erhältlich. +thing-type.config.tankerkoenig.webservice.apikey.label = API Schlüssel +thing-type.config.tankerkoenig.webservice.apikey.description = API Schlüssel für den Zugriff auf die Tankerkönig API. Der API Schlüssel ist auf der Tankerkönig Webseite erhältlich. +thing-type.config.tankerkoenig.webservice.modeOpeningTime.label = Öffnungszeiten +thing-type.config.tankerkoenig.webservice.modeOpeningTime.description = Bei Aktivierung des Öffnungszeitenmodus werden nur die Tankstellen abgefragt, die zur aktuellen Uhrzeit geöffnet haben. +thing-type.config.tankerkoenig.webservice.refresh.label = Aktualisierungsintervall +thing-type.config.tankerkoenig.webservice.refresh.description = Intervall zur Aktualisierung der Tankerkönig API (in min). + # channel types + channel-type.tankerkoenig.diesel.label = Diesel -channel-type.tankerkoenig.e5.label = E5 +channel-type.tankerkoenig.diesel.description = Preis für Diesel. channel-type.tankerkoenig.e10.label = E10 -channel-type.tankerkoenig.station_open.label = Öffnungs-Status +channel-type.tankerkoenig.e10.description = Preis für E10. +channel-type.tankerkoenig.e5.label = E5 +channel-type.tankerkoenig.e5.description = Preis für E5. channel-type.tankerkoenig.holiday.label = Feiertag - -channel-type.tankerkoenig.diesel.description = Diesel-Preis -channel-type.tankerkoenig.e5.description= E5-Preis -channel-type.tankerkoenig.e10.description = E10-Preis -channel-type.tankerkoenig.station_open.description = Gemeldeter Öffnungs-Status -channel-type.tankerkoenig.holiday.description = ON, wenn Heute ein Feiertag ist +channel-type.tankerkoenig.holiday.description = Zeigt an, ob der heutige Tag ein Feiertag ist. +channel-type.tankerkoenig.station_open.label = Geöffnet/Geschlossen +channel-type.tankerkoenig.station_open.description = Zeigt an, ob die Tankstelle geöffnet oder geschlossen hat. diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties new file mode 100644 index 0000000000000..e9ef1d765eb85 --- /dev/null +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties @@ -0,0 +1,8 @@ +profile.config.transform.JS.function.label = Dateiname +profile.config.transform.JS.function.description = Datei mit dem JavaScript Code. Der Item State wird in der Variable `input` an das Skript übergeben. +profile.config.transform.JS.sourceFormat.label = State Format +profile.config.transform.JS.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). + +# profile type + +profile-type.transform.JS.label = JavaScript diff --git a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties new file mode 100644 index 0000000000000..dba04daf57a1d --- /dev/null +++ b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties @@ -0,0 +1,8 @@ +profile.config.transform.SCALE.function.label = Dateiname +profile.config.transform.SCALE.function.description = Datei mit den Skala-Informationen. +profile.config.transform.SCALE.sourceFormat.label = State Format +profile.config.transform.SCALE.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). + +# profile type + +profile-type.transform.SCALE.label = SCALE From 479ecd41f355d814ed9514c084fdd94d457bd072 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Fri, 17 Dec 2021 08:08:35 -0800 Subject: [PATCH 251/361] [jsscripting] Support non unix file paths (#11804) Fixes #11801 Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- .../jsscripting/internal/OpenhabGraalJSScriptEngine.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index d9a9e60916f10..c3bdce81a46b4 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -14,6 +14,7 @@ import static org.openhab.core.automation.module.script.ScriptEngineFactory.*; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.channels.SeekableByteChannel; @@ -65,7 +66,7 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi private static final String GLOBAL_REQUIRE = "require(\"@jsscripting-globals\");"; private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__"; // final CommonJS search path for our library - private static final Path LOCAL_NODE_PATH = Paths.get("/node_modules"); + private static final Path LOCAL_NODE_PATH = Paths.get(File.separator + "node_modules"); // these fields start as null because they are populated on first use private @NonNullByDefault({}) String engineIdentifier; From 5a286f77323ab489dae597d2f45b0e77d212f56e Mon Sep 17 00:00:00 2001 From: jlaur Date: Fri, 17 Dec 2021 19:16:13 +0100 Subject: [PATCH 252/361] [danfossairunit] Remove deprecated channel main#manual_fan_speed when unlinked (#11668) * Remove deprecated channel if unlinked. Signed-off-by: Jacob Laursen Signed-off-by: Michael Schmidt --- .../handler/DanfossAirUnitHandler.java | 18 ++++++++++++++++++ .../OH-INF/i18n/danfossairunit.properties | 4 ++-- .../resources/OH-INF/thing/thing-types.xml | 12 ++++-------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/handler/DanfossAirUnitHandler.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/handler/DanfossAirUnitHandler.java index 6b69008c99927..f94e7932dcba3 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/handler/DanfossAirUnitHandler.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/handler/DanfossAirUnitHandler.java @@ -23,12 +23,14 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.danfossairunit.internal.Channel; +import org.openhab.binding.danfossairunit.internal.ChannelGroup; import org.openhab.binding.danfossairunit.internal.DanfossAirUnit; import org.openhab.binding.danfossairunit.internal.DanfossAirUnitCommunicationController; import org.openhab.binding.danfossairunit.internal.DanfossAirUnitConfiguration; import org.openhab.binding.danfossairunit.internal.DanfossAirUnitWriteAccessor; import org.openhab.binding.danfossairunit.internal.UnexpectedResponseValueException; import org.openhab.binding.danfossairunit.internal.ValueCache; +import org.openhab.core.thing.ChannelGroupUID; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -96,6 +98,7 @@ public void initialize() { updateStatus(ThingStatus.UNKNOWN); config = getConfigAs(DanfossAirUnitConfiguration.class); valueCache = new ValueCache(config.updateUnchangedValuesEveryMillis); + removeDeprecatedChannels(); try { var localCommunicationController = new DanfossAirUnitCommunicationController( InetAddress.getByName(config.host), TCP_PORT); @@ -119,6 +122,21 @@ public void initialize() { } } + private void removeDeprecatedChannels() { + ChannelGroupUID mainChannelGroupUid = new ChannelGroupUID(thing.getUID(), ChannelGroup.MAIN.getGroupName()); + ChannelUID manualFanSpeedChannelUid = new ChannelUID(mainChannelGroupUid, + Channel.CHANNEL_MANUAL_FAN_SPEED.getChannelName()); + if (this.isLinked(manualFanSpeedChannelUid)) { + ChannelUID manualFanStepChannelUid = new ChannelUID(mainChannelGroupUid, + Channel.CHANNEL_MANUAL_FAN_STEP.getChannelName()); + logger.warn("Channel '{}' is deprecated, please use '{}' instead.", manualFanSpeedChannelUid, + manualFanStepChannelUid); + } else { + logger.debug("Removing deprecated unlinked channel '{}'.", manualFanSpeedChannelUid); + updateThing(editThing().withoutChannel(manualFanSpeedChannelUid).build()); + } + } + private void updateAllChannels() { DanfossAirUnit localAirUnit = this.airUnit; if (localAirUnit == null) { diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/i18n/danfossairunit.properties b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/i18n/danfossairunit.properties index 02fe397076e9b..7777616d2b1c3 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/i18n/danfossairunit.properties +++ b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/i18n/danfossairunit.properties @@ -24,6 +24,8 @@ channel-group-type.danfossairunit.humidity.channel.humidity.description = Curren channel-group-type.danfossairunit.main.label = Mode and Fan Speeds channel-group-type.danfossairunit.main.channel.boost.label = Boost channel-group-type.danfossairunit.main.channel.boost.description = Enables fan boost +channel-group-type.danfossairunit.main.channel.manual_fan_speed.label = Manual Fan Speed +channel-group-type.danfossairunit.main.channel.manual_fan_speed.description = Deprecated, please use Manual Fan Step instead. This channel will be removed in a later version. channel-group-type.danfossairunit.main.channel.night_cooling.label = Night Cooling channel-group-type.danfossairunit.main.channel.night_cooling.description = Enables night cooling channel-group-type.danfossairunit.recuperator.label = Recuperator @@ -60,8 +62,6 @@ channel-type.danfossairunit.extractFanStep.description = Current step setting of channel-type.danfossairunit.filterPeriod.label = Filter Period channel-type.danfossairunit.filterPeriod.description = Number of months between filter replacements channel-type.danfossairunit.humidity.label = Humidity -channel-type.danfossairunit.manualFanSpeed.label = Manual Fan Speed -channel-type.danfossairunit.manualFanSpeed.description = Deprecated, please use Manual Fan Step instead. This channel will be removed in a later version. channel-type.danfossairunit.manualFanStep.label = Manual Fan Step channel-type.danfossairunit.manualFanStep.description = Controls 10-step setting of the fan when operation mode is manual channel-type.danfossairunit.mode.label = Mode diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml index b526e27bb4184..3873c72cd89fc 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml @@ -50,7 +50,10 @@ - + + + Deprecated, please use Manual Fan Step instead. This channel will be removed in a later version. + @@ -157,13 +160,6 @@ Fan - - Dimmer - - Deprecated, please use Manual Fan Step instead. This channel will be removed in a later version. - Fan - - Number From 8b1171b0f2e7ad5863e03457bce367fa7b9702f6 Mon Sep 17 00:00:00 2001 From: Dan Cunningham Date: Fri, 17 Dec 2021 11:34:25 -0800 Subject: [PATCH 253/361] [jsscripting] Support non unix file paths (#11805) Lets try this again, Fixes #11801 Signed-off-by: Dan Cunningham Signed-off-by: Michael Schmidt --- .../internal/OpenhabGraalJSScriptEngine.java | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java index c3bdce81a46b4..7f0d4b15a9fb8 100644 --- a/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java +++ b/bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java @@ -14,7 +14,6 @@ import static org.openhab.core.automation.module.script.ScriptEngineFactory.*; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.channels.SeekableByteChannel; @@ -66,7 +65,7 @@ public class OpenhabGraalJSScriptEngine extends InvocationInterceptingScriptEngi private static final String GLOBAL_REQUIRE = "require(\"@jsscripting-globals\");"; private static final String REQUIRE_WRAPPER_NAME = "__wraprequire__"; // final CommonJS search path for our library - private static final Path LOCAL_NODE_PATH = Paths.get(File.separator + "node_modules"); + private static final Path NODE_DIR = Paths.get("node_modules"); // these fields start as null because they are populated on first use private @NonNullByDefault({}) String engineIdentifier; @@ -116,10 +115,11 @@ public SeekableByteChannel newByteChannel(Path path, Set o if (scriptDependencyListener != null) { scriptDependencyListener.accept(path.toString()); } + if (path.toString().endsWith(".js")) { SeekableByteChannel sbc = null; - if (path.startsWith(LOCAL_NODE_PATH)) { - InputStream is = getClass().getResourceAsStream(path.toString()); + if (isRootNodePath(path)) { + InputStream is = getClass().getResourceAsStream(nodeFileToResource(path)); if (is == null) { throw new IOException("Could not read " + path.toString()); } @@ -137,8 +137,8 @@ public SeekableByteChannel newByteChannel(Path path, Set o @Override public void checkAccess(Path path, Set modes, LinkOption... linkOptions) throws IOException { - if (path.startsWith(LOCAL_NODE_PATH)) { - if (getClass().getResource(path.toString()) == null) { + if (isRootNodePath(path)) { + if (getClass().getResource(nodeFileToResource(path)) == null) { throw new NoSuchFileException(path.toString()); } } else { @@ -149,7 +149,7 @@ public void checkAccess(Path path, Set modes, @Override public Map readAttributes(Path path, String attributes, LinkOption... options) throws IOException { - if (path.startsWith(LOCAL_NODE_PATH)) { + if (isRootNodePath(path)) { return Collections.singletonMap("isRegularFile", true); } return super.readAttributes(path, attributes, options); @@ -157,7 +157,7 @@ public Map readAttributes(Path path, String attributes, @Override public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException { - if (path.startsWith(LOCAL_NODE_PATH)) { + if (isRootNodePath(path)) { return path; } return super.toRealPath(path, linkOptions); @@ -210,4 +210,24 @@ protected void beforeInvocation() { LOGGER.error("Could not inject global script", e); } } + + /** + * Tests if this is a root node directory, `/node_modules`, `C:\node_modules`, etc... + * + * @param path + * @return + */ + private boolean isRootNodePath(Path path) { + return path.startsWith(path.getRoot().resolve(NODE_DIR)); + } + + /** + * Converts a root node path to a class resource path for loading local modules + * + * @param path + * @return + */ + private String nodeFileToResource(Path path) { + return "/" + NODE_DIR + "/" + path.getFileName(); + } } From 3798edb46a28bad95b336ea9c3f6434ddccb069f Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Sat, 18 Dec 2021 13:01:38 +0100 Subject: [PATCH 254/361] Upgrade to Karaf 4.3.4 (#11750) * Syncs the karaf.version so the new Maven plugin is used * Resolves itest runbundles for the new runtime dependencies Signed-off-by: Wouter Born Signed-off-by: Michael Schmidt --- .../itest.bndrun | 10 +++++----- .../itest.bndrun | 12 ++++++------ .../itest.bndrun | 18 +++++++++--------- .../org.openhab.binding.hue.tests/itest.bndrun | 12 ++++++------ .../org.openhab.binding.max.tests/itest.bndrun | 10 +++++----- .../itest.bndrun | 18 +++++++++--------- .../itest.bndrun | 10 +++++----- .../itest.bndrun | 16 ++++++++-------- .../org.openhab.binding.ntp.tests/itest.bndrun | 10 +++++----- .../itest.bndrun | 10 +++++----- .../itest.bndrun | 10 +++++----- .../itest.bndrun | 12 ++++++------ .../itest.bndrun | 10 +++++----- pom.xml | 2 +- 14 files changed, 80 insertions(+), 80 deletions(-) diff --git a/itests/org.openhab.binding.astro.tests/itest.bndrun b/itests/org.openhab.binding.astro.tests/itest.bndrun index b4924f7fdb13a..a6d2108c732a6 100644 --- a/itests/org.openhab.binding.astro.tests/itest.bndrun +++ b/itests/org.openhab.binding.astro.tests/itest.bndrun @@ -17,8 +17,6 @@ Fragment-Host: org.openhab.binding.astro org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -36,8 +34,6 @@ Fragment-Host: org.openhab.binding.astro org.openhab.core.io.console;version='[3.2.0,3.2.1)',\ org.openhab.core.storage.json;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -50,4 +46,8 @@ Fragment-Host: org.openhab.binding.astro net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun index b44c40a905aec..4cfd20b82dc8f 100644 --- a/itests/org.openhab.binding.avmfritz.tests/itest.bndrun +++ b/itests/org.openhab.binding.avmfritz.tests/itest.bndrun @@ -24,8 +24,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ @@ -50,7 +48,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.openhab.core.io.net;version='[3.2.0,3.2.1)',\ org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ @@ -62,8 +59,6 @@ Fragment-Host: org.openhab.binding.avmfritz org.eclipse.jetty.websocket.api;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -75,4 +70,9 @@ Fragment-Host: org.openhab.binding.avmfritz net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.feed.tests/itest.bndrun b/itests/org.openhab.binding.feed.tests/itest.bndrun index e377d99eedfac..9fbe9a95391c9 100644 --- a/itests/org.openhab.binding.feed.tests/itest.bndrun +++ b/itests/org.openhab.binding.feed.tests/itest.bndrun @@ -28,8 +28,6 @@ Fragment-Host: org.openhab.binding.feed org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ @@ -54,7 +52,6 @@ Fragment-Host: org.openhab.binding.feed org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -63,11 +60,6 @@ Fragment-Host: org.openhab.binding.feed org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.xml;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -75,4 +67,12 @@ Fragment-Host: org.openhab.binding.feed junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ junit-platform-launcher;version='[1.8.1,1.8.2)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-jetty;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-runtime;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-spi;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.hue.tests/itest.bndrun b/itests/org.openhab.binding.hue.tests/itest.bndrun index dc760309aa28e..f397046749715 100644 --- a/itests/org.openhab.binding.hue.tests/itest.bndrun +++ b/itests/org.openhab.binding.hue.tests/itest.bndrun @@ -28,8 +28,6 @@ Fragment-Host: org.openhab.binding.hue org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ @@ -58,7 +56,6 @@ Fragment-Host: org.openhab.binding.hue org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ @@ -70,8 +67,6 @@ Fragment-Host: org.openhab.binding.hue org.eclipse.jetty.websocket.api;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -79,4 +74,9 @@ Fragment-Host: org.openhab.binding.hue junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ junit-platform-launcher;version='[1.8.1,1.8.2)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.max.tests/itest.bndrun b/itests/org.openhab.binding.max.tests/itest.bndrun index 20cc682b43f2a..5d08badf993e2 100644 --- a/itests/org.openhab.binding.max.tests/itest.bndrun +++ b/itests/org.openhab.binding.max.tests/itest.bndrun @@ -27,8 +27,6 @@ Fragment-Host: org.openhab.binding.max org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.apache.commons.lang3;version='[3.12.0,3.12.1)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -50,7 +48,6 @@ Fragment-Host: org.openhab.binding.max org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -58,7 +55,6 @@ Fragment-Host: org.openhab.binding.max org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -66,4 +62,8 @@ Fragment-Host: org.openhab.binding.max junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ junit-platform-launcher;version='[1.8.1,1.8.2)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun index 9daae00cf5d7b..12b3c1bf60cc4 100644 --- a/itests/org.openhab.binding.mielecloud.tests/itest.bndrun +++ b/itests/org.openhab.binding.mielecloud.tests/itest.bndrun @@ -29,8 +29,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -56,7 +54,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ @@ -69,11 +66,6 @@ Fragment-Host: org.openhab.binding.mielecloud org.eclipse.jetty.websocket.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.xml;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-runtime;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -85,4 +77,12 @@ Fragment-Host: org.openhab.binding.mielecloud net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-jetty;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-runtime;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-spi;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.modbus.tests/itest.bndrun b/itests/org.openhab.binding.modbus.tests/itest.bndrun index 9521f950d3bd7..a6e051607bd38 100644 --- a/itests/org.openhab.binding.modbus.tests/itest.bndrun +++ b/itests/org.openhab.binding.modbus.tests/itest.bndrun @@ -28,8 +28,6 @@ Fragment-Host: org.openhab.binding.modbus org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -53,7 +51,6 @@ Fragment-Host: org.openhab.binding.modbus org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ org.openhab.core.transform;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -61,7 +58,6 @@ Fragment-Host: org.openhab.binding.modbus org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -75,4 +71,8 @@ Fragment-Host: org.openhab.binding.modbus org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.nest.tests/itest.bndrun b/itests/org.openhab.binding.nest.tests/itest.bndrun index 880e5865b7302..c6b07e317eb08 100644 --- a/itests/org.openhab.binding.nest.tests/itest.bndrun +++ b/itests/org.openhab.binding.nest.tests/itest.bndrun @@ -20,7 +20,6 @@ Fragment-Host: org.openhab.binding.nest org.eclipse.equinox.event;version='[1.4.300,1.4.301)',\ org.osgi.service.event;version='[1.4.0,1.4.1)',\ org.osgi.service.jaxrs;version='[1.0.0,1.0.1)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ org.hamcrest;version='[2.2.0,2.2.1)',\ org.opentest4j;version='[1.2.0,1.2.1)',\ jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\ @@ -29,7 +28,6 @@ Fragment-Host: org.openhab.binding.nest org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ org.apache.aries.javax.jax.rs-api;version='[1.0.1,1.0.2)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ @@ -67,7 +65,6 @@ Fragment-Host: org.openhab.binding.nest org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ @@ -80,10 +77,6 @@ Fragment-Host: org.openhab.binding.nest org.eclipse.jetty.websocket.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.xml;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-jetty;version='[7.3.19,7.3.20)',\ - org.ops4j.pax.web.pax-web-spi;version='[7.3.19,7.3.20)',\ com.fasterxml.woodstox.woodstox-core;version='[6.2.6,6.2.7)',\ org.apache.cxf.cxf-core;version='[3.4.5,3.4.6)',\ org.apache.cxf.cxf-rt-frontend-jaxrs;version='[3.4.5,3.4.6)',\ @@ -104,4 +97,11 @@ Fragment-Host: org.openhab.binding.nest org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ - org.apache.aries.jax.rs.whiteboard;version='[2.0.0,2.0.1)' + org.apache.aries.jax.rs.whiteboard;version='[2.0.0,2.0.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-jetty;version='[7.3.23,7.3.24)',\ + org.ops4j.pax.web.pax-web-spi;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.ntp.tests/itest.bndrun b/itests/org.openhab.binding.ntp.tests/itest.bndrun index 8d661f047d8c9..31d2b1628e481 100644 --- a/itests/org.openhab.binding.ntp.tests/itest.bndrun +++ b/itests/org.openhab.binding.ntp.tests/itest.bndrun @@ -27,8 +27,6 @@ Fragment-Host: org.openhab.binding.ntp org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -50,7 +48,6 @@ Fragment-Host: org.openhab.binding.ntp org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -58,7 +55,6 @@ Fragment-Host: org.openhab.binding.ntp org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -70,4 +66,8 @@ Fragment-Host: org.openhab.binding.ntp net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun index 5099700998820..bcbc9bd1a89f8 100644 --- a/itests/org.openhab.binding.systeminfo.tests/itest.bndrun +++ b/itests/org.openhab.binding.systeminfo.tests/itest.bndrun @@ -28,8 +28,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -51,7 +49,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -59,7 +56,6 @@ Fragment-Host: org.openhab.binding.systeminfo org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ com.sun.jna;version='[5.9.0,5.9.1)',\ com.sun.jna.platform;version='[5.9.0,5.9.1)',\ si-units;version='[2.1.0,2.1.1)',\ @@ -73,4 +69,8 @@ Fragment-Host: org.openhab.binding.systeminfo net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.tradfri.tests/itest.bndrun b/itests/org.openhab.binding.tradfri.tests/itest.bndrun index 2f4651e75f6a4..f28e15746a65b 100644 --- a/itests/org.openhab.binding.tradfri.tests/itest.bndrun +++ b/itests/org.openhab.binding.tradfri.tests/itest.bndrun @@ -30,8 +30,6 @@ Fragment-Host: org.openhab.binding.tradfri org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -55,7 +53,6 @@ Fragment-Host: org.openhab.binding.tradfri org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -63,7 +60,6 @@ Fragment-Host: org.openhab.binding.tradfri org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -76,4 +72,8 @@ Fragment-Host: org.openhab.binding.tradfri org.mockito.junit-jupiter;version='[4.1.0,4.1.1)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.binding.wemo.tests/itest.bndrun b/itests/org.openhab.binding.wemo.tests/itest.bndrun index c0824764f417c..16e186198461e 100644 --- a/itests/org.openhab.binding.wemo.tests/itest.bndrun +++ b/itests/org.openhab.binding.wemo.tests/itest.bndrun @@ -27,8 +27,6 @@ Fragment-Host: org.openhab.binding.wemo org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ org.objectweb.asm;version='[9.1.0,9.1.1)',\ org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\ org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\ @@ -58,7 +56,6 @@ Fragment-Host: org.openhab.binding.wemo org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.core.thing;version='[3.2.0,3.2.1)',\ org.openhab.core.thing.xml;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ @@ -70,8 +67,6 @@ Fragment-Host: org.openhab.binding.wemo org.eclipse.jetty.websocket.api;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.client;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.websocket.common;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ - org.ops4j.pax.web.pax-web-api;version='[7.3.19,7.3.20)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -83,4 +78,9 @@ Fragment-Host: org.openhab.binding.wemo net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\ org.mockito.mockito-core;version='[4.1.0,4.1.1)',\ org.objenesis;version='[3.2.0,3.2.1)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.ops4j.pax.web.pax-web-api;version='[7.3.23,7.3.24)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun index 2e0949a1697fb..c1bcb8f591acf 100644 --- a/itests/org.openhab.persistence.mapdb.tests/itest.bndrun +++ b/itests/org.openhab.persistence.mapdb.tests/itest.bndrun @@ -26,8 +26,6 @@ Fragment-Host: org.openhab.persistence.mapdb org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\ org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\ com.google.gson;version='[2.8.6,2.8.7)',\ - org.osgi.util.function;version='[1.1.0,1.1.1)',\ - org.osgi.util.promise;version='[1.1.1,1.1.2)',\ jakarta.annotation-api;version='[2.0.0,2.0.1)',\ jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\ javax.measure.unit-api;version='[2.1.2,2.1.3)',\ @@ -41,7 +39,6 @@ Fragment-Host: org.openhab.persistence.mapdb org.openhab.core.test;version='[3.2.0,3.2.1)',\ org.openhab.persistence.mapdb;version='[3.2.0,3.2.1)',\ org.openhab.persistence.mapdb.tests;version='[3.2.0,3.2.1)',\ - org.apache.felix.scr;version='[2.1.28,2.1.29)',\ org.eclipse.jetty.http;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.io;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.security;version='[9.4.43,9.4.44)',\ @@ -49,7 +46,6 @@ Fragment-Host: org.openhab.persistence.mapdb org.eclipse.jetty.servlet;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util;version='[9.4.43,9.4.44)',\ org.eclipse.jetty.util.ajax;version='[9.4.43,9.4.44)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.0.10,2.0.11)',\ si-units;version='[2.1.0,2.1.1)',\ si.uom.si-quantity;version='[2.1.0,2.1.1)',\ junit-jupiter-api;version='[5.8.1,5.8.2)',\ @@ -57,4 +53,8 @@ Fragment-Host: org.openhab.persistence.mapdb junit-platform-commons;version='[1.8.1,1.8.2)',\ junit-platform-engine;version='[1.8.1,1.8.2)',\ junit-platform-launcher;version='[1.8.1,1.8.2)',\ - biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)' + biz.aQute.tester.junit-platform;version='[6.1.0,6.1.1)',\ + org.apache.felix.scr;version='[2.1.30,2.1.31)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.0.12,2.0.13)',\ + org.osgi.util.function;version='[1.2.0,1.2.1)',\ + org.osgi.util.promise;version='[1.2.0,1.2.1)' diff --git a/pom.xml b/pom.xml index 019425708f24b..4ac86a7cbee2e 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 3.7.2 2.2.1 2.12.5 - 4.3.3 + 4.3.4 4.1.68.Final 3.14.9 0.12.0 From c992c644e0e043cdc6bfdb12985250a882511d6c Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Sun, 19 Dec 2021 12:14:34 +0100 Subject: [PATCH 255/361] New Crowdin updates (#11807) * New translations avmfritz.properties (German) * New translations js.properties (German) * New translations scale.properties (German) * New translations openweathermap.properties (French) * New translations astro.properties (French) * New translations hue.properties (French) * New translations powermax.properties (French) Signed-off-by: Michael Schmidt --- .../resources/OH-INF/i18n/astro_fr.properties | 2 +- .../OH-INF/i18n/avmfritz_de.properties | 2 +- .../resources/OH-INF/i18n/hue_fr.properties | 2 +- .../OH-INF/i18n/openweathermap_fr.properties | 511 +++++++++++------- .../OH-INF/i18n/powermax_fr.properties | 2 +- .../resources/OH-INF/i18n/js_de.properties | 2 +- .../resources/OH-INF/i18n/scale_de.properties | 2 +- 7 files changed, 314 insertions(+), 209 deletions(-) diff --git a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties index 32fc35e2c4d8f..50a62df91944c 100644 --- a/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties +++ b/bundles/org.openhab.binding.astro/src/main/resources/OH-INF/i18n/astro_fr.properties @@ -190,7 +190,7 @@ channel-type.astro.distanceDate.description = La date et l'heure lorsque la dist channel-type.astro.distance.label = Distance channel-type.astro.distance.description = La distance de l'objet channel-type.astro.rangeEvent.label = Événement Période -channel-type.astro.rangeEvent.description = L'évènement d'une période +channel-type.astro.rangeEvent.description = Les évènements associés à la période channel-type.astro.sunEclipseEvent.label = Événement Eclipse Solaire channel-type.astro.sunEclipseEvent.description = Événement d'éclipse solaire channel-type.astro.phaseEvent.label = Événement Phase Lunaire diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties index 54e43c5c4877b..3fe87cbdac8c7 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz_de.properties @@ -1,7 +1,7 @@ # binding binding.avmfritz.name = AVM FRITZ\! Binding -binding.avmfritz.description = Dieses Binding integriert AVM FRITZ\! Geräte (z.B DECT 100/200/210/300/301, Comet DECT, Powerline 546E). +binding.avmfritz.description = Dieses Binding integriert AVM FRITZ\! Geräte (z.B. DECT 100/200/210/300/301, Comet DECT, Powerline 546E). # thing types diff --git a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties index 03536be4ab6e0..d635a671a8efe 100644 --- a/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties +++ b/bundles/org.openhab.binding.hue/src/main/resources/OH-INF/i18n/hue_fr.properties @@ -54,7 +54,7 @@ thing-type.config.hue.bridge.pollingInterval.description = Le nombre de secondes thing-type.config.hue.bridge.port.label = Port thing-type.config.hue.bridge.port.description = Port du pont de connexion hue. thing-type.config.hue.bridge.sensorPollingInterval.label = Intervalle d'interrogation du capteur -thing-type.config.hue.bridge.sensorPollingInterval.description = Millisecondes entre chaque récupération des valeurs de capteur depuis le pont de connexion Hue. Une valeur plus élevée signifie plus de délai pour les valeurs de capteur, mais une valeur trop faible peut causer une congestion sur le pont de connexion Hue. Utilisez 0 pour désactiver l'interrogation des capteurs. La valeur par défaut est 500. +thing-type.config.hue.bridge.sensorPollingInterval.description = Millisecondes entre chaque récupération des valeurs de capteur depuis le pont de connexion Hue. Une valeur plus élevée signifie plus de délai entre chaque récupération des valeurs de capteur, mais une valeur trop faible peut causer une congestion sur le pont de connexion Hue. Utilisez 0 pour désactiver l'interrogation des capteurs. La valeur par défaut est 500. thing-type.config.hue.bridge.userName.label = Nom d'utilisateur thing-type.config.hue.bridge.userName.description = Le nom d'un utilisateur enregistré sur le pont de connexion hue, autorisant un accès à l'API. thing-type.config.hue.group.groupId.label = ID du groupe diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_fr.properties b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_fr.properties index 9e8c25a277e9d..8b809eeb2d62a 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_fr.properties +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_fr.properties @@ -1,261 +1,366 @@ # binding + binding.openweathermap.name = Extension OpenWeatherMap binding.openweathermap.description = L'extension OpenWeatherMap fournit la météo actuelle et les prévisions dans votre ville. -# bridge types -thing-type.openweathermap.weather-api.label = Compte OpenWeatherMap -thing-type.openweathermap.weather-api.description = Fournit un accès à l'API d'OpenWeatherMap. +# thing types -# bridge types config -bridge-type.config.openweathermap.weather-api.apikey.label = Clé API -bridge-type.config.openweathermap.weather-api.apikey.description = Clé pour accéder à l'API d'OpenWeatherMap. +thing-type.openweathermap.air-pollution.label = Pollution Air +thing-type.openweathermap.air-pollution.description = Fournit des données de pollution de l'air à partir de l'API OpenWeatherMap. +thing-type.openweathermap.onecall-history.label = Données Historisées API One Call +thing-type.openweathermap.onecall-history.description = Fournit des données météo historisées à partir de l'API OpenWeatherMap one call. +thing-type.openweathermap.onecall.label = Météo et Prévisions API One Call +thing-type.openweathermap.onecall.description = Fournit les données météo et les prévisions actuelles à partir de l'API OpenWeatherMap one call. +thing-type.openweathermap.onecall.group.forecastDay2.label = Prévisions dans 2 jours API one call +thing-type.openweathermap.onecall.group.forecastDay2.description = Il s'agit des prévisions météo dans deux jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastDay3.label = Prévisions dans 3 jours API one call +thing-type.openweathermap.onecall.group.forecastDay3.description = Il s'agit des prévisions météo dans trois jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastDay4.label = Prévisions dans 4 jours API one call +thing-type.openweathermap.onecall.group.forecastDay4.description = Il s'agit des prévisions météo dans quatre jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastDay5.label = Prévisions dans 5 jours API one call +thing-type.openweathermap.onecall.group.forecastDay5.description = Il s'agit des prévisions météo dans cinq jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastDay6.label = Prévisions dans 6 jours API one call +thing-type.openweathermap.onecall.group.forecastDay6.description = Il s'agit des prévisions météo dans six jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastDay7.label = Prévisions dans 7 jours API one call +thing-type.openweathermap.onecall.group.forecastDay7.description = Il s'agit des prévisions météo dans sept jours à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastToday.label = Prévisions pour aujourd'hui API one call +thing-type.openweathermap.onecall.group.forecastToday.description = Il s'agit des prévisions météo pour aujourd'hui à partir de l'API one call. +thing-type.openweathermap.onecall.group.forecastTomorrow.label = Prévisions pour demain API one call +thing-type.openweathermap.onecall.group.forecastTomorrow.description = Il s'agit des prévisions météo pour demain à partir de l'API one call. +thing-type.openweathermap.uvindex.label = Indice UV +thing-type.openweathermap.uvindex.description = Fournit les données d'indice UV de l'API OpenWeatherMap. +thing-type.openweathermap.uvindex.group.forecastDay2.label = Indice UV dans 2 jours +thing-type.openweathermap.uvindex.group.forecastDay2.description = Il s'agit des prévisions d'indice UV dans deux jours. +thing-type.openweathermap.uvindex.group.forecastDay3.label = Indice UV dans 3 jours +thing-type.openweathermap.uvindex.group.forecastDay3.description = Il s'agit des prévisions d'indice UV dans trois jours. +thing-type.openweathermap.uvindex.group.forecastDay4.label = Indice UV dans 4 jours +thing-type.openweathermap.uvindex.group.forecastDay4.description = Il s'agit des prévisions d'indice UV dans quatre jours. +thing-type.openweathermap.uvindex.group.forecastDay5.label = Indice UV dans 5 jours +thing-type.openweathermap.uvindex.group.forecastDay5.description = Il s'agit des prévisions d'indice UV dans cinq jours. +thing-type.openweathermap.uvindex.group.forecastTomorrow.label = Indice UV pour demain +thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Il s'agit des prévisions d'indice UV pour demain. +thing-type.openweathermap.weather-and-forecast.label = Météo Actuelle et Prévisions +thing-type.openweathermap.weather-and-forecast.description = Fournit les données météorologiques actuelles et les prévisions de l'API OpenWeatherMap. +thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Prévisions dans 2 jours +thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Il s'agit des prévisions météorologiques dans deux jours. +thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Prévisions dans 3 jours +thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Il s'agit des prévisions météorologiques dans trois jours. +thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Prévisions dans 4 jours +thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Il s'agit des prévisions météorologiques dans quatre jours. +thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Prévisions dans 5 jours +thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Il s'agit des prévisions météorologiques dans cinq jours. +thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Prévisions dans 3 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Il s'agit des prévisions météorologiques pour les 3 prochaines heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Prévisions dans 6 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Il s'agit des prévisions météorologiques dans 6 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Prévisions dans 9 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Il s'agit des prévisions météorologiques dans 9 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Prévisions dans 12 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Il s'agit des prévisions météorologiques dans 12 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Prévisions dans 15 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Il s'agit des prévisions météorologiques dans 15 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Prévisions dans 18 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Il s'agit des prévisions météorologiques dans 18 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Prévisions dans 21 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Il s'agit des prévisions météorologiques dans 21 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Prévisions dans 24 heures +thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Il s'agit des prévisions météorologiques dans 24 heures. +thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Prévisions pour aujourd'hui +thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Il s'agit des prévisions météorologiques pour aujourd'hui. +thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Prévisions pour demain +thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Il s'agit des prévisions météorologiques pour demain. +thing-type.openweathermap.weather-api.label = Compte OpenWeatherMap +thing-type.openweathermap.weather-api.description = Fournit un accès à l'API OpenWeatherMap. -bridge-type.config.openweathermap.weather-api.refreshInterval.label = Intervalle d'actualisation -bridge-type.config.openweathermap.weather-api.refreshInterval.description = Spécifie l'intervalle d'actualisation (en minutes). +# thing types config +bridge-type.config.openweathermap.weather-api.apikey.label = Clé API +bridge-type.config.openweathermap.weather-api.apikey.description = Clé pour accéder à l'API OpenWeatherMap. bridge-type.config.openweathermap.weather-api.language.label = Langue -bridge-type.config.openweathermap.weather-api.language.description = Langue à utiliser par l'API d'OpenWeatherMap. +bridge-type.config.openweathermap.weather-api.language.description = Langue à utiliser par l'API OpenWeatherMap. +bridge-type.config.openweathermap.weather-api.language.option.af = Afrikaans +bridge-type.config.openweathermap.weather-api.language.option.al = Albanais bridge-type.config.openweathermap.weather-api.language.option.ar = Arabe +bridge-type.config.openweathermap.weather-api.language.option.az = Azerbaïdjanais +bridge-type.config.openweathermap.weather-api.language.option.eu = Basque bridge-type.config.openweathermap.weather-api.language.option.bg = Bulgare bridge-type.config.openweathermap.weather-api.language.option.ca = Catalan +bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinois - Simplifié +bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinois - Traditionnel +bridge-type.config.openweathermap.weather-api.language.option.hr = Croate bridge-type.config.openweathermap.weather-api.language.option.cz = Tchèque -bridge-type.config.openweathermap.weather-api.language.option.de = Allemand -bridge-type.config.openweathermap.weather-api.language.option.el = Grec +bridge-type.config.openweathermap.weather-api.language.option.da = Danois +bridge-type.config.openweathermap.weather-api.language.option.nl = Néerlandais bridge-type.config.openweathermap.weather-api.language.option.en = Anglais -bridge-type.config.openweathermap.weather-api.language.option.es = Espagnol -bridge-type.config.openweathermap.weather-api.language.option.fa = Persan (Farsi) bridge-type.config.openweathermap.weather-api.language.option.fi = Finlandais bridge-type.config.openweathermap.weather-api.language.option.fr = Français bridge-type.config.openweathermap.weather-api.language.option.gl = Galicien -bridge-type.config.openweathermap.weather-api.language.option.hr = Croate +bridge-type.config.openweathermap.weather-api.language.option.de = Allemand +bridge-type.config.openweathermap.weather-api.language.option.el = Grec +bridge-type.config.openweathermap.weather-api.language.option.he = Hébreu +bridge-type.config.openweathermap.weather-api.language.option.hi = Hindi bridge-type.config.openweathermap.weather-api.language.option.hu = Hongrois +bridge-type.config.openweathermap.weather-api.language.option.id = Indonésien bridge-type.config.openweathermap.weather-api.language.option.it = Italien bridge-type.config.openweathermap.weather-api.language.option.ja = Japonais bridge-type.config.openweathermap.weather-api.language.option.kr = Coréen bridge-type.config.openweathermap.weather-api.language.option.la = Letton bridge-type.config.openweathermap.weather-api.language.option.lt = Lituanien bridge-type.config.openweathermap.weather-api.language.option.mk = Macédonien -bridge-type.config.openweathermap.weather-api.language.option.nl = Néerlandais +bridge-type.config.openweathermap.weather-api.language.option.no = Norvégien +bridge-type.config.openweathermap.weather-api.language.option.fa = Persan (Farsi) bridge-type.config.openweathermap.weather-api.language.option.pl = Polonais +bridge-type.config.openweathermap.weather-api.language.option.pt_br = Portugais, Brésil bridge-type.config.openweathermap.weather-api.language.option.pt = Portugais bridge-type.config.openweathermap.weather-api.language.option.ro = Roumain bridge-type.config.openweathermap.weather-api.language.option.ru = Russe -bridge-type.config.openweathermap.weather-api.language.option.se = Suédois +bridge-type.config.openweathermap.weather-api.language.option.sr = Serbe bridge-type.config.openweathermap.weather-api.language.option.sk = Slovaque bridge-type.config.openweathermap.weather-api.language.option.sl = Slovène +bridge-type.config.openweathermap.weather-api.language.option.es = Espagnol +bridge-type.config.openweathermap.weather-api.language.option.se = Suédois +bridge-type.config.openweathermap.weather-api.language.option.th = Thaï bridge-type.config.openweathermap.weather-api.language.option.tr = Turc -bridge-type.config.openweathermap.weather-api.language.option.ua = Ukrainien +bridge-type.config.openweathermap.weather-api.language.option.uk = Ukrainien bridge-type.config.openweathermap.weather-api.language.option.vi = Vietnamien -bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinois - Simplifié -bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinois - Traditionnel - -# thing types -thing-type.openweathermap.weather-and-forecast.label = Météo actuelle et prévisions -thing-type.openweathermap.weather-and-forecast.description = Fournit les données météorologiques actuelles et les prévisions de l'API d'OpenWeatherMap. - -thing-type.openweathermap.uvindex.label = Indice UV -thing-type.openweathermap.uvindex.description = Fournit les données d'indice UV de l'API d'OpenWeatherMap. - -# thing types config -thing-type.config.openweathermap.weather-and-forecast.location.label = Localisation -thing-type.config.openweathermap.weather-and-forecast.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). - -thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Nombre d'heures -thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Nombre d'heures pour les prévisions horaires. - -thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Nombre de jours -thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Nombre de jours pour les prévisions quotidiennes. - -thing-type.config.openweathermap.uvindex.location.label = Localisation -thing-type.config.openweathermap.uvindex.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). - +bridge-type.config.openweathermap.weather-api.language.option.zu = Zoulou +bridge-type.config.openweathermap.weather-api.refreshInterval.label = Intervalle d'actualisation +bridge-type.config.openweathermap.weather-api.refreshInterval.description = Spécifie l'intervalle d'actualisation (en minutes). +thing-type.config.openweathermap.air-pollution.forecastHours.label = Nombre d'heures +thing-type.config.openweathermap.air-pollution.forecastHours.description = Nombre d'heures pour les prévisions de pollution de l'air. +thing-type.config.openweathermap.air-pollution.location.label = Localisation +thing-type.config.openweathermap.air-pollution.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). +thing-type.config.openweathermap.onecall-history.historyDay.label = Jours d’historique +thing-type.config.openweathermap.onecall-history.historyDay.description = Nombre relatif de jours dans le passé pour les données historiques. +thing-type.config.openweathermap.onecall-history.location.label = Localisation +thing-type.config.openweathermap.onecall-history.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). +thing-type.config.openweathermap.onecall.forecastDays.label = Nombre de jours +thing-type.config.openweathermap.onecall.forecastDays.description = Nombre de jours pour les prévisions quotidiennes, y compris aujourd'hui. +thing-type.config.openweathermap.onecall.forecastHours.label = Nombre d'heures +thing-type.config.openweathermap.onecall.forecastHours.description = Nombre d'heures pour les prévisions horaires. +thing-type.config.openweathermap.onecall.forecastMinutes.label = Nombre de minutes +thing-type.config.openweathermap.onecall.forecastMinutes.description = Nombre de minutes pour les prévisions de précipitations à la minute. +thing-type.config.openweathermap.onecall.location.label = Localisation +thing-type.config.openweathermap.onecall.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). +thing-type.config.openweathermap.onecall.numberOfAlerts.label = Nombre d'alertes +thing-type.config.openweathermap.onecall.numberOfAlerts.description = Nombre d'alertes à présenter. thing-type.config.openweathermap.uvindex.forecastDays.label = Nombre de jours thing-type.config.openweathermap.uvindex.forecastDays.description = Nombre de jours pour les prévisions d'indice UV. +thing-type.config.openweathermap.uvindex.location.label = Localisation +thing-type.config.openweathermap.uvindex.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). +thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Nombre de jours +thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Nombre de jours pour les prévisions quotidiennes. +thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Nombre d'heures +thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Nombre d'heures pour les prévisions horaires. +thing-type.config.openweathermap.weather-and-forecast.location.label = Localisation +thing-type.config.openweathermap.weather-and-forecast.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude). # channel group types -channel-group-type.openweathermap.station.label = Station météo -channel-group-type.openweathermap.station.description = Représente une station météo. - -channel-group-type.openweathermap.weather.label = Météo actuelle -channel-group-type.openweathermap.weather.description = Représente la météo actuelle. - -channel-group-type.openweathermap.hourlyForecast.label = Prévisions à 3 heures -channel-group-type.openweathermap.hourlyForecast.description = Prévisions météorologiques à 5 jours par tranches de 3 heures. +channel-group-type.openweathermap.airPollution.label = Pollution actuelle de l'air +channel-group-type.openweathermap.airPollution.description = Il s'agit de la pollution actuelle de l'air. +channel-group-type.openweathermap.airPollutionForecast.label = Prévision de pollution de l'air +channel-group-type.openweathermap.airPollutionForecast.description = Il s'agit de la pollution prévisionnelle de l'air. channel-group-type.openweathermap.dailyForecast.label = Prévisions quotidiennes -channel-group-type.openweathermap.dailyForecast.description = Prévisions météorologiques quotidiennes à 16 jours. - +channel-group-type.openweathermap.dailyForecast.description = Il s'agit des prévisions météorologiques quotidiennes à 16 jours. +channel-group-type.openweathermap.hourlyForecast.label = Prévisions à 3 heures +channel-group-type.openweathermap.hourlyForecast.description = Il s'agit des prévisions météorologiques à 5 jours par tranches de 3 heures. +channel-group-type.openweathermap.oneCallAlerts.label = Alertes météo +channel-group-type.openweathermap.oneCallAlerts.description = Alertes météorologiques émis pour l'emplacement demandé. +channel-group-type.openweathermap.oneCallCurrent.label = Météo actuelle API one call +channel-group-type.openweathermap.oneCallCurrent.description = Données de la météo actuelle à partir de l'API one call. +channel-group-type.openweathermap.oneCallDaily.label = Prévisions quotidiennes API one call +channel-group-type.openweathermap.oneCallDaily.description = Prévisions météo quotidiennes fournies par l’API one call. +channel-group-type.openweathermap.oneCallHistory.label = Météo historisée API one call +channel-group-type.openweathermap.oneCallHistory.description = Données météo historisées à partir de l'API one call à un instant donné du jour. +channel-group-type.openweathermap.oneCallHistoryHours.label = Météo historisée à l'heure API one call +channel-group-type.openweathermap.oneCallHistoryHours.description = Données météorologiques historisées à l'heure à partir de ll'API one call. +channel-group-type.openweathermap.oneCallHourly.label = Prévisions horaires API one call +channel-group-type.openweathermap.oneCallHourly.description = Prévisions météo horaires fournies par l’API one call. +channel-group-type.openweathermap.oneCallMinutely.label = Prévisions minutes API one call +channel-group-type.openweathermap.oneCallMinutely.description = Prévisions météo à la minute fournies par l’API one call. +channel-group-type.openweathermap.station.label = Station météo +channel-group-type.openweathermap.station.description = Il s'agit d'une station météo. +channel-group-type.openweathermap.station.channel.location.description = L'emplacement de la station météo ou de la ville en coordonnées géographiques (latitude / longitude / altitude). channel-group-type.openweathermap.uvindex.label = Indice UV actuel -channel-group-type.openweathermap.uvindex.description = Représente l'indice UV actuel. - -channel-group-type.openweathermap.uvindexForecast.label = Indice UV pour aujourd'hui -channel-group-type.openweathermap.uvindexForecast.description = Représente les prévisions l'indice UV pour aujourd'hui. - -# channel groups -thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Prévisions dans 3 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Représente les prévisions météorologiques pour les 3 prochaines heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Prévisions dans 6 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Représente les prévisions météorologiques dans 6 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Prévisions dans 9 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Représente les prévisions météorologiques dans 9 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Prévisions dans 12 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Représente les prévisions météorologiques dans 12 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Prévisions dans 15 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Représente les prévisions météorologiques dans 15 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Prévisions dans 18 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Représente les prévisions météorologiques dans 18 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Prévisions dans 21 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Représente les prévisions météorologiques dans 21 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Prévisions dans 24 heures -thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Représente les prévisions météorologiques dans 24 heures. - -thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Prévisions pour aujourd'hui -thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Représente les prévisions météorologiques pour aujourd'hui. - -thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Prévisions pour demain -thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Représente les prévisions météorologiques pour demain. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Prévisions dans 2 jours -thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Représente les prévisions météorologiques dans deux jours. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Prévisions dans 3 jours -thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Représente les prévisions météorologiques dans trois jours. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Prévisions dans 4 jours -thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Représente les prévisions météorologiques dans quatre jours. - -thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Prévisions dans 5 jours -thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Représente les prévisions météorologiques dans cinq jours. - -thing-type.openweathermap.uvindex.group.forecastTomorrow.label = Indice UV pour demain -thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Représente les prévisions l'indice UV pour demain. - -thing-type.openweathermap.uvindex.group.forecastDay2.label = Indice UV dans 2 jours -thing-type.openweathermap.uvindex.group.forecastDay2.description = Représente les prévisions l'indice UV dans deux jours. - -thing-type.openweathermap.uvindex.group.forecastDay3.label = Indice UV dans 3 jours -thing-type.openweathermap.uvindex.group.forecastDay3.description = Représente les prévisions l'indice UV dans trois jours. - -thing-type.openweathermap.uvindex.group.forecastDay4.label = Indice UV dans 4 jours -thing-type.openweathermap.uvindex.group.forecastDay4.description = Représente les prévisions l'indice UV dans quatre jours. - -thing-type.openweathermap.uvindex.group.forecastDay5.label = Indice UV dans 5 jours -thing-type.openweathermap.uvindex.group.forecastDay5.description = Représente les prévisions l'indice UV dans cinq jours. +channel-group-type.openweathermap.uvindex.description = Il s'agit de l'indice UV actuel. +channel-group-type.openweathermap.uvindexForecast.label = Indice UV prévu aujourd'hui +channel-group-type.openweathermap.uvindexForecast.description = Il s'agit de l'indice UV prévu pour aujourd'hui. +channel-group-type.openweathermap.weather.label = Météo actuelle +channel-group-type.openweathermap.weather.description = Il s'agit de la météo actuelle. # channel types -channel-type.openweathermap.station-id.label = Id station -channel-type.openweathermap.station-id.description = L'identifiant de la station météo ou de la ville. - -channel-type.openweathermap.station-name.label = Nom station -channel-type.openweathermap.station-name.description = Le nom de la station météo ou de la ville. - -channel-group-type.openweathermap.station.channel.location.label = Localisation -channel-group-type.openweathermap.station.channel.location.description = L'emplacement de la station météo ou de la ville en coordonnées géographiques (latitude / longitude / altitude). - -channel-type.openweathermap.time-stamp.label = Heure d'observation -channel-type.openweathermap.time-stamp.description = La date et l'heure d'observation de la météo. -channel-type.openweathermap.time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS -channel-type.openweathermap.hourly-forecast-time-stamp.label = Heure des prévisions -channel-type.openweathermap.hourly-forecast-time-stamp.description = La date et l'heure des prévisions. -channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS - -channel-type.openweathermap.daily-forecast-time-stamp.label = Date des prévisions +channel-type.openweathermap.air-quality-index.label = Indice Qualité Air +channel-type.openweathermap.air-quality-index.description = Indice actuel de qualité de l'air. +channel-type.openweathermap.air-quality-index.state.option.1 = Bon +channel-type.openweathermap.air-quality-index.state.option.2 = Acceptable +channel-type.openweathermap.air-quality-index.state.option.3 = Modéré +channel-type.openweathermap.air-quality-index.state.option.4 = Mauvais +channel-type.openweathermap.air-quality-index.state.option.5 = Très mauvais +channel-type.openweathermap.alert-description.label = Description +channel-type.openweathermap.alert-description.description = Une description détaillée de l'alerte. +channel-type.openweathermap.alert-event.label = Type +channel-type.openweathermap.alert-event.description = Type de l'alerte, par exemple GEL. +channel-type.openweathermap.alert-expires.label = Valide Jusque +channel-type.openweathermap.alert-expires.description = Date et heure de fin de l'alerte. +channel-type.openweathermap.alert-expires.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.alert-onset.label = Valide à Partir De +channel-type.openweathermap.alert-onset.description = Date et heure de début de l'alerte. +channel-type.openweathermap.alert-onset.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.alert-source.label = Source +channel-type.openweathermap.alert-source.description = Source de l'alerte. +channel-type.openweathermap.ammonia.label = Ammoniac +channel-type.openweathermap.ammonia.description = Concentration actuelle en ammoniac. +channel-type.openweathermap.apparent-day.label = Température Ressentie Journée +channel-type.openweathermap.apparent-day.description = Température ressentie prévue dans la journée. +channel-type.openweathermap.apparent-evening.label = Température Ressentie Soirée +channel-type.openweathermap.apparent-evening.description = Température ressentie prévue dans la soirée. +channel-type.openweathermap.apparent-morning.label = Température Ressentie Matinée +channel-type.openweathermap.apparent-morning.description = Température ressentie prévue dans la matinée. +channel-type.openweathermap.apparent-night.label = Température Ressentie Nuit +channel-type.openweathermap.apparent-night.description = Température ressentie prévue dans la nuit. +channel-type.openweathermap.apparent-temperature.label = Température Ressentie +channel-type.openweathermap.apparent-temperature.description = Température ressentie actuelle. +channel-type.openweathermap.carbon-monoxide.label = Monoxyde Carbone +channel-type.openweathermap.carbon-monoxide.description = Concentration actuelle en monoxyde de carbone. +channel-type.openweathermap.cloudiness.label = Nébulosité +channel-type.openweathermap.cloudiness.description = La nébulosité actuelle. +channel-type.openweathermap.condition-icon-id.label = Id Icône +channel-type.openweathermap.condition-icon-id.description = L'identifiant de l'icône représentant les conditions météorologiques. +channel-type.openweathermap.condition-icon.label = Icône +channel-type.openweathermap.condition-icon.description = L'icône représentant les conditions météorologiques. +channel-type.openweathermap.condition-id.label = Id Conditions Météorologiques +channel-type.openweathermap.condition-id.description = L'identifiant des conditions météorologiques. +channel-type.openweathermap.condition.label = Conditions Météorologiques +channel-type.openweathermap.condition.description = Les conditions météorologiques actuelles. +channel-type.openweathermap.daily-forecast-time-stamp.label = Date Prévisions channel-type.openweathermap.daily-forecast-time-stamp.description = La date des prévisions. channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td/%1$tm/%1$tY - -channel-type.openweathermap.condition.label = Conditions météorologiques -channel-type.openweathermap.condition.description = Les conditions météorologiques actuelles. - -channel-type.openweathermap.forecasted-condition.label = Conditions météorologiques prévues +channel-type.openweathermap.day-temperature.label = Température Journée +channel-type.openweathermap.day-temperature.description = Température extérieure prévue pour la journée. +channel-type.openweathermap.dew-point.label = Température Point Rosée +channel-type.openweathermap.dew-point.description = Température prévue du point de rosée. +channel-type.openweathermap.evening-temperature.label = Température Soirée +channel-type.openweathermap.evening-temperature.description = Température extérieure prévue pour la soirée. +channel-type.openweathermap.forecasted-air-quality-index.label = Indice Qualité Air Prévu +channel-type.openweathermap.forecasted-air-quality-index.description = Indice de qualité de l'air prévu. +channel-type.openweathermap.forecasted-air-quality-index.state.option.1 = Bon +channel-type.openweathermap.forecasted-air-quality-index.state.option.2 = Acceptable +channel-type.openweathermap.forecasted-air-quality-index.state.option.3 = Modéré +channel-type.openweathermap.forecasted-air-quality-index.state.option.4 = Mauvais +channel-type.openweathermap.forecasted-air-quality-index.state.option.5 = Très mauvais +channel-type.openweathermap.forecasted-ammonia.label = Ammoniac Prévu +channel-type.openweathermap.forecasted-ammonia.description = Concentration prévisionnelle en ammoniac. +channel-type.openweathermap.forecasted-apparent-temperature.label = Température Ressentie Prévue +channel-type.openweathermap.forecasted-apparent-temperature.description = Température ressentie prévue. +channel-type.openweathermap.forecasted-atmospheric-humidity.label = Humidité Atmosphérique Prévue +channel-type.openweathermap.forecasted-atmospheric-humidity.description = L'humidité relative atmosphérique prévue. +channel-type.openweathermap.forecasted-barometric-pressure.label = Pression Barométrique Prévue +channel-type.openweathermap.forecasted-barometric-pressure.description = La pression barométrique prévue. +channel-type.openweathermap.forecasted-carbon-monoxide.label = Monoxyde Carbone Prévu +channel-type.openweathermap.forecasted-carbon-monoxide.description = Concentration prévisionnelle en monoxyde de carbone. +channel-type.openweathermap.forecasted-cloudiness.label = Nébulosité Prévue +channel-type.openweathermap.forecasted-cloudiness.description = La nébulosité prévue. +channel-type.openweathermap.forecasted-condition.label = Conditions Météorologiques Prévues channel-type.openweathermap.forecasted-condition.description = Les conditions météorologiques prévues. - -channel-type.openweathermap.condition-id.label = Id conditions météorologiques -channel-type.openweathermap.condition-id.description = L'identifiant des conditions météorologiques. - -channel-type.openweathermap.condition-icon.label = Icône -channel-type.openweathermap.condition-icon.description = L'icône représentant les conditions météorologiques. - -channel-type.openweathermap.condition-icon-id.label = Id icône -channel-type.openweathermap.condition-icon-id.description = L'identifiant de l'icône représentant les conditions météorologiques. - -channel-type.openweathermap.forecasted-outdoor-temperature.label = Température prévue -channel-type.openweathermap.forecasted-outdoor-temperature.description = La température extérieure prévue. - -channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Température minimale -channel-type.openweathermap.forecasted-min-outdoor-temperature.description = La température extérieure minimale prévue. - -channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Température maximale +channel-type.openweathermap.forecasted-gust-speed.label = Vitesse Prévue Rafales Vent +channel-type.openweathermap.forecasted-gust-speed.description = La vitesse prévue des rafales de vent. +channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Température Maximale channel-type.openweathermap.forecasted-max-outdoor-temperature.description = La température extérieure maximale prévue. - -channel-type.openweathermap.forecasted-barometric-pressure.label = Pression barométrique prévue -channel-type.openweathermap.forecasted-barometric-pressure.description = La pression barométrique prévue. - -channel-type.openweathermap.forecasted-atmospheric-humidity.label = Humidité atmosphérique prévue -channel-type.openweathermap.forecasted-atmospheric-humidity.description = L'humidité relative atmosphérique prévue. - -channel-type.openweathermap.forecasted-wind-speed.label = Vitesse prévue du vent -channel-type.openweathermap.forecasted-wind-speed.description = La vitesse prévue du vent. - -channel-type.openweathermap.forecasted-wind-direction.label = Direction prévue du vent +channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Température Minimale +channel-type.openweathermap.forecasted-min-outdoor-temperature.description = La température extérieure minimale prévue. +channel-type.openweathermap.forecasted-nitrogen-dioxide.label = Dioxyde Azote Prévu +channel-type.openweathermap.forecasted-nitrogen-dioxide.description = Concentration prévisionnelle en dioxyde d'azote. +channel-type.openweathermap.forecasted-nitrogen-monoxide.label = Monoxyde Azote Prévu +channel-type.openweathermap.forecasted-nitrogen-monoxide.description = Concentration prévisionnelle en monoxyde d'azote. +channel-type.openweathermap.forecasted-outdoor-temperature.label = Température Prévue +channel-type.openweathermap.forecasted-outdoor-temperature.description = La température extérieure prévue. +channel-type.openweathermap.forecasted-ozone.label = Ozone Prévu +channel-type.openweathermap.forecasted-ozone.description = Concentration prévisionnelle en ozone. +channel-type.openweathermap.forecasted-particulate-matter-10.label = Densité Particules PM10 +channel-type.openweathermap.forecasted-particulate-matter-10.description = Densité actuelle en particules de moins de 10 μm de diamètre. +channel-type.openweathermap.forecasted-particulate-matter-2dot5.label = Prévision Densité Particules PM2.5 +channel-type.openweathermap.forecasted-particulate-matter-2dot5.description = Prévision de densité en particules de moins de 2,5 μm de diamètre. +channel-type.openweathermap.forecasted-rain.label = Pluie Prévue +channel-type.openweathermap.forecasted-rain.description = La quantité prévue de pluie. +channel-type.openweathermap.forecasted-snow.label = Neige Prévue +channel-type.openweathermap.forecasted-snow.description = La quantité prévue de neige. +channel-type.openweathermap.forecasted-sulphur-dioxide.label = Dioxyde Soufre Prévu +channel-type.openweathermap.forecasted-sulphur-dioxide.description = Concentration prévue en dioxyde de soufre. +channel-type.openweathermap.forecasted-uvindex.label = Indice UV Prévu +channel-type.openweathermap.forecasted-uvindex.description = L'indice UV prévu. +channel-type.openweathermap.forecasted-wind-direction.label = Direction Vent Prévue channel-type.openweathermap.forecasted-wind-direction.description = La direction prévue du vent exprimée sous forme d'angle. - -channel-type.openweathermap.gust-speed.label = Vitesse des rafales de vent +channel-type.openweathermap.forecasted-wind-speed.label = Vitesse Vent Prévue +channel-type.openweathermap.forecasted-wind-speed.description = La vitesse prévue du vent. +channel-type.openweathermap.gust-speed.label = Vitesse Rafales Vent channel-type.openweathermap.gust-speed.description = La vitesse actuelle des rafales de vent. - -channel-type.openweathermap.forecasted-gust-speed.label = Vitesse prévue des rafales de vent -channel-type.openweathermap.forecasted-gust-speed.description = La vitesse prévue des rafales de vent. - -channel-type.openweathermap.cloudiness.label = Nébulosité -channel-type.openweathermap.cloudiness.description = La nébulosité actuelle. - -channel-type.openweathermap.forecasted-cloudiness.label = Nébulosité prévue -channel-type.openweathermap.forecasted-cloudiness.description = La nébulosité prévue. - -channel-type.openweathermap.visibility.label = Distance de visibilité -channel-type.openweathermap.visibility.description = La distance de visibilité. - +channel-type.openweathermap.hourly-forecast-time-stamp.label = Heure Prévisions +channel-type.openweathermap.hourly-forecast-time-stamp.description = La date et l'heure des prévisions. +channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.morning-temperature.label = Température Matinée +channel-type.openweathermap.morning-temperature.description = Température extérieure prévue pour la matinée. +channel-type.openweathermap.night-temperature.label = Température Nuit +channel-type.openweathermap.night-temperature.description = Température extérieure prévue pour la nuit. +channel-type.openweathermap.nitrogen-dioxide.label = Dioxyde Azote +channel-type.openweathermap.nitrogen-dioxide.description = Concentration actuelle en dioxyde d'azote. +channel-type.openweathermap.nitrogen-monoxide.label = Monoxyde Azote +channel-type.openweathermap.nitrogen-monoxide.description = Concentration actuelle en monoxyde d'azote. +channel-type.openweathermap.ozone.label = Ozone +channel-type.openweathermap.ozone.description = Concentration actuelle en ozone. +channel-type.openweathermap.particulate-matter-10.label = Prévision Densité Particules PM10 +channel-type.openweathermap.particulate-matter-10.description = Prévision de densité en particules de moins de 10 μm de diamètre. +channel-type.openweathermap.particulate-matter-2dot5.label = Densité Particules PM2.5 +channel-type.openweathermap.particulate-matter-2dot5.description = Densité actuelle en particules de moins de 2.5 μm de diamètre. +channel-type.openweathermap.precip-probability.label = Probabilité de précipitations +channel-type.openweathermap.precip-probability.description = Probabilité prévisionnelle de précipitations. +channel-type.openweathermap.precipitation.label = Précipitations +channel-type.openweathermap.precipitation.description = Volume des précipitations de la période associée. channel-type.openweathermap.rain.label = Pluie channel-type.openweathermap.rain.description = La quantité de pluie dans la dernière heure. - -channel-type.openweathermap.forecasted-rain.label = Pluie prévue -channel-type.openweathermap.forecasted-rain.description = La quantité prévue de pluie. - channel-type.openweathermap.snow.label = Neige channel-type.openweathermap.snow.description = La quantité de neige dans la dernière heure. - -channel-type.openweathermap.forecasted-snow.label = Neige prévue -channel-type.openweathermap.forecasted-snow.description = La quantité prévue de neige. - +channel-type.openweathermap.station-id.label = Id Station +channel-type.openweathermap.station-id.description = L'identifiant de la station météo ou de la ville. +channel-type.openweathermap.station-name.label = Nom Station +channel-type.openweathermap.station-name.description = Le nom de la station météo ou de la ville. +channel-type.openweathermap.sulphur-dioxide.label = Dioxyde Soufre +channel-type.openweathermap.sulphur-dioxide.description = Concentration actuelle en dioxyde de soufre. +channel-type.openweathermap.sunrise.label = Heure Lever Soleil +channel-type.openweathermap.sunrise.description = Heure de lever du soleil pour la journée donnée. +channel-type.openweathermap.sunrise.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.sunset.label = Heure Coucher Soleil +channel-type.openweathermap.sunset.description = Heure de coucher du soleil pour la journée donnée. +channel-type.openweathermap.sunset.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS +channel-type.openweathermap.time-stamp.label = Heure Observation +channel-type.openweathermap.time-stamp.description = La date et l'heure d'observation de la météo. +channel-type.openweathermap.time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH\:%1$tM\:%1$tS channel-type.openweathermap.uvindex.label = Indice UV channel-type.openweathermap.uvindex.description = L'indice UV actuel. - -channel-type.openweathermap.forecasted-uvindex.label = Indice UV prévu -channel-type.openweathermap.forecasted-uvindex.description = L'indice UV prévu. +channel-type.openweathermap.visibility.label = Distance Visibilité +channel-type.openweathermap.visibility.description = La distance de visibilité. # thing status -offline.conf-error-missing-apikey = Le paramètre 'apikey' doit être configuré. -offline.conf-error-invalid-apikey = Clé API invalide. Veuillez consulter https://openweathermap.org/faq#error401 pour plus d''informations. -offline.conf-error-not-supported-refreshInterval = Le paramètre 'refreshInterval' doit être au moins de 1 minute. -offline.conf-error-not-supported-language = Le paramètre 'language' choisi n''est pas supporté. - -offline.conf-error-missing-location = Le paramètre 'location' doit être configuré. -offline.conf-error-parsing-location = Le paramètre 'location' n''a pas pu être séparé en latitude et en longitude. -offline.conf-error-not-supported-number-of-hours = Le paramètre 'forecastHours' doit être compris entre 0 et 120 - par incrément de 3. -offline.conf-error-not-supported-number-of-days = Le paramètre 'forecastDays' doit être compris entre 0 et 16. -offline.conf-error-not-supported-uvindex-number-of-days = Le paramètre 'forecastDays' doit être compris entre 1 et 8. -offline.conf-error-not-supported-onecall-number-of-minutes = Le paramètre 'forecastMinutes' doit être compris entre 0 et 60. -offline.conf-error-not-supported-onecall-number-of-hours = Le paramètre 'forecastHours' doit être compris entre 0 et 48. -offline.conf-error-not-supported-onecall-number-of-days = Le paramètre 'forecastDays' doit être compris entre 0 et 7. +offline.conf-error-missing-apikey = Le paramètre 'clé API' doit être configuré. +offline.conf-error-invalid-apikey = Clé API invalide. Veuillez consulter https\://openweathermap.org/faq\#error401 pour plus d'informations. +offline.conf-error-not-supported-refreshInterval = Le paramètre 'intervalle actualisation' doit être au moins de 1 minute. +offline.conf-error-not-supported-language = Le paramètre 'langue' choisi n'est pas supporté. +offline.conf-error-missing-location = Le paramètre 'localisation' doit être configuré. +offline.conf-error-parsing-location = Le paramètre 'localisation' n'a pas pu être séparé en latitude et en longitude. +offline.conf-error-not-supported-number-of-hours = Le paramètre 'nombre heures' doit être compris entre 0 et 120 - par incrément de 3. +offline.conf-error-not-supported-number-of-days = Le paramètre 'nombre de jours' doit être compris entre 0 et 16. +offline.conf-error-not-supported-uvindex-number-of-days = Le paramètre 'nombre de jours' doit être compris entre 1 et 8. +offline.conf-error-not-supported-air-pollution-number-of-hours = Le paramètre 'nombre heures' doit être compris entre 1 et 120 - incrément 3. +offline.conf-error-not-supported-onecall-number-of-minutes = Le paramètre 'nombre de minutes' doit être compris entre 0 et 60. +offline.conf-error-not-supported-onecall-number-of-hours = Le paramètre 'nombre heures' doit être compris entre 0 et 48. +offline.conf-error-not-supported-onecall-number-of-days = Le paramètre 'nombre de jours' doit être compris entre 0 et 7. +offline.conf-error-not-supported-onecall-number-of-alerts = Le paramètre 'nombre alertes' doit être supérieur ou égal à 0. # discovery result -discovery.weather-and-forecast.local.label = Météo locale et prévisions -discovery.air-pollution.local.label = Indice UV local + +discovery.weather-and-forecast.local.label = Météo Locale +discovery.air-pollution.local.label = Pollution Air Locale +discovery.onecall.local.label = Météo Locale (API one call) +discovery.onecall-history.local.label = Données Historique Locales (API one call) diff --git a/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties b/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties index 6ee434a02c32e..b9949a4456029 100644 --- a/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties +++ b/bundles/org.openhab.binding.powermax/src/main/resources/OH-INF/i18n/powermax_fr.properties @@ -104,7 +104,7 @@ channel-type.powermax.tripped.description = Si la zone est déclenchée ou non. channel-type.powermax.trouble.label = Panne Détectée channel-type.powermax.trouble.description = Si une panne est détectée ou non. channel-type.powermax.update_event_logs.label = Mettre à Jour Journal Événements -channel-type.powermax.update_event_logs.description = Déclencher la mise à jour le journal des événements. +channel-type.powermax.update_event_logs.description = Déclencher la mise à jour du journal des événements. channel-type.powermax.with_zones_bypassed.label = Avec Zones Isolées channel-type.powermax.with_zones_bypassed.description = Si au moins une zone est isolée. channel-type.powermax.x10_status.label = État Appareil X10 diff --git a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties index e9ef1d765eb85..52d1b3873def4 100644 --- a/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties +++ b/bundles/org.openhab.transform.javascript/src/main/resources/OH-INF/i18n/js_de.properties @@ -1,7 +1,7 @@ profile.config.transform.JS.function.label = Dateiname profile.config.transform.JS.function.description = Datei mit dem JavaScript Code. Der Item State wird in der Variable `input` an das Skript übergeben. profile.config.transform.JS.sourceFormat.label = State Format -profile.config.transform.JS.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). +profile.config.transform.JS.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B. %s oder %.1f °C, Standard ist %s). # profile type diff --git a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties index dba04daf57a1d..f1c56388617cb 100644 --- a/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties +++ b/bundles/org.openhab.transform.scale/src/main/resources/OH-INF/i18n/scale_de.properties @@ -1,7 +1,7 @@ profile.config.transform.SCALE.function.label = Dateiname profile.config.transform.SCALE.function.description = Datei mit den Skala-Informationen. profile.config.transform.SCALE.sourceFormat.label = State Format -profile.config.transform.SCALE.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B %s oder %.1f °C, Standard ist %s). +profile.config.transform.SCALE.sourceFormat.description = Format, welches auf den State des Channels angewendet.wird, bevor das Mapping erfolgt (z.B. %s oder %.1f °C, Standard ist %s). # profile type From 9bb1141dc495d2f4fc7dadff9ccf4275980307f9 Mon Sep 17 00:00:00 2001 From: openhab-bot Date: Mon, 20 Dec 2021 00:30:46 +0000 Subject: [PATCH 256/361] [unleash-maven-plugin] Preparation for next development cycle. Signed-off-by: Michael Schmidt --- bom/openhab-addons/pom.xml | 6 ++---- bom/openhab-core-index/pom.xml | 6 ++---- bom/pom.xml | 15 +++++---------- bom/runtime-index/pom.xml | 6 ++---- bom/test-index/pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../org.openhab.automation.jrubyscripting/pom.xml | 6 ++---- .../org.openhab.automation.jsscripting/pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../org.openhab.automation.pidcontroller/pom.xml | 6 ++---- bundles/org.openhab.automation.pwm/pom.xml | 6 ++---- bundles/org.openhab.binding.adorne/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.airq/pom.xml | 6 ++---- bundles/org.openhab.binding.airquality/pom.xml | 6 ++---- bundles/org.openhab.binding.airvisualnode/pom.xml | 6 ++---- bundles/org.openhab.binding.alarmdecoder/pom.xml | 6 ++---- bundles/org.openhab.binding.allplay/pom.xml | 6 ++---- .../org.openhab.binding.amazondashbutton/pom.xml | 6 ++---- .../org.openhab.binding.amazonechocontrol/pom.xml | 6 ++---- .../org.openhab.binding.ambientweather/pom.xml | 6 ++---- bundles/org.openhab.binding.amplipi/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.anel/pom.xml | 6 ++---- bundles/org.openhab.binding.astro/pom.xml | 6 ++---- bundles/org.openhab.binding.atlona/pom.xml | 6 ++---- bundles/org.openhab.binding.autelis/pom.xml | 6 ++---- bundles/org.openhab.binding.automower/pom.xml | 6 ++---- bundles/org.openhab.binding.avmfritz/pom.xml | 6 ++---- bundles/org.openhab.binding.benqprojector/pom.xml | 6 ++---- bundles/org.openhab.binding.bigassfan/pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.am43/pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.bluez/pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.blukii/pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.generic/pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.govee/pom.xml | 6 ++---- .../org.openhab.binding.bluetooth.roaming/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.bluetooth/pom.xml | 6 ++---- .../org.openhab.binding.bmwconnecteddrive/pom.xml | 6 ++---- bundles/org.openhab.binding.boschindego/pom.xml | 6 ++---- bundles/org.openhab.binding.boschshc/pom.xml | 6 ++---- .../org.openhab.binding.bosesoundtouch/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.bsblan/pom.xml | 6 ++---- .../org.openhab.binding.bticinosmarther/pom.xml | 6 ++---- bundles/org.openhab.binding.buienradar/pom.xml | 6 ++---- bundles/org.openhab.binding.caddx/pom.xml | 6 ++---- bundles/org.openhab.binding.cbus/pom.xml | 6 ++---- bundles/org.openhab.binding.chromecast/pom.xml | 6 ++---- bundles/org.openhab.binding.cm11a/pom.xml | 6 ++---- bundles/org.openhab.binding.comfoair/pom.xml | 6 ++---- bundles/org.openhab.binding.coolmasternet/pom.xml | 6 ++---- bundles/org.openhab.binding.coronastats/pom.xml | 6 ++---- bundles/org.openhab.binding.daikin/pom.xml | 6 ++---- bundles/org.openhab.binding.dali/pom.xml | 6 ++---- .../org.openhab.binding.danfossairunit/pom.xml | 6 ++---- bundles/org.openhab.binding.darksky/pom.xml | 6 ++---- bundles/org.openhab.binding.dbquery/pom.xml | 6 ++---- bundles/org.openhab.binding.deconz/pom.xml | 6 ++---- bundles/org.openhab.binding.denonmarantz/pom.xml | 6 ++---- bundles/org.openhab.binding.deutschebahn/pom.xml | 6 ++---- bundles/org.openhab.binding.digiplex/pom.xml | 6 ++---- bundles/org.openhab.binding.digitalstrom/pom.xml | 6 ++---- .../org.openhab.binding.dlinksmarthome/pom.xml | 6 ++---- bundles/org.openhab.binding.dmx/pom.xml | 6 ++---- bundles/org.openhab.binding.dominoswiss/pom.xml | 6 ++---- bundles/org.openhab.binding.doorbird/pom.xml | 6 ++---- bundles/org.openhab.binding.draytonwiser/pom.xml | 6 ++---- bundles/org.openhab.binding.dscalarm/pom.xml | 6 ++---- bundles/org.openhab.binding.dsmr/pom.xml | 6 ++---- bundles/org.openhab.binding.dwdpollenflug/pom.xml | 6 ++---- bundles/org.openhab.binding.dwdunwetter/pom.xml | 6 ++---- bundles/org.openhab.binding.ecobee/pom.xml | 6 ++---- bundles/org.openhab.binding.ecotouch/pom.xml | 6 ++---- bundles/org.openhab.binding.ekey/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.energenie/pom.xml | 6 ++---- bundles/org.openhab.binding.enigma2/pom.xml | 6 ++---- bundles/org.openhab.binding.enocean/pom.xml | 6 ++---- bundles/org.openhab.binding.enphase/pom.xml | 6 ++---- bundles/org.openhab.binding.enturno/pom.xml | 6 ++---- .../org.openhab.binding.epsonprojector/pom.xml | 6 ++---- bundles/org.openhab.binding.etherrain/pom.xml | 6 ++---- bundles/org.openhab.binding.evohome/pom.xml | 6 ++---- bundles/org.openhab.binding.exec/pom.xml | 6 ++---- bundles/org.openhab.binding.feed/pom.xml | 6 ++---- bundles/org.openhab.binding.feican/pom.xml | 6 ++---- bundles/org.openhab.binding.fmiweather/pom.xml | 6 ++---- bundles/org.openhab.binding.folderwatcher/pom.xml | 6 ++---- bundles/org.openhab.binding.folding/pom.xml | 6 ++---- bundles/org.openhab.binding.foobot/pom.xml | 6 ++---- bundles/org.openhab.binding.freebox/pom.xml | 6 ++---- bundles/org.openhab.binding.fronius/pom.xml | 6 ++---- .../org.openhab.binding.fsinternetradio/pom.xml | 6 ++---- bundles/org.openhab.binding.ftpupload/pom.xml | 6 ++---- bundles/org.openhab.binding.gardena/pom.xml | 6 ++---- bundles/org.openhab.binding.gce/pom.xml | 6 ++---- .../org.openhab.binding.generacmobilelink/pom.xml | 6 ++---- bundles/org.openhab.binding.globalcache/pom.xml | 6 ++---- bundles/org.openhab.binding.goecharger/pom.xml | 6 ++---- bundles/org.openhab.binding.gpio/pom.xml | 6 ++---- bundles/org.openhab.binding.gpstracker/pom.xml | 6 ++---- bundles/org.openhab.binding.gree/pom.xml | 6 ++---- bundles/org.openhab.binding.groheondus/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.harmonyhub/pom.xml | 6 ++---- .../org.openhab.binding.haywardomnilogic/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.hdanywhere/pom.xml | 6 ++---- bundles/org.openhab.binding.hdpowerview/pom.xml | 6 ++---- bundles/org.openhab.binding.helios/pom.xml | 6 ++---- .../org.openhab.binding.heliosventilation/pom.xml | 6 ++---- bundles/org.openhab.binding.heos/pom.xml | 6 ++---- bundles/org.openhab.binding.homeconnect/pom.xml | 6 ++---- bundles/org.openhab.binding.homematic/pom.xml | 6 ++---- bundles/org.openhab.binding.homewizard/pom.xml | 6 ++---- bundles/org.openhab.binding.hpprinter/pom.xml | 6 ++---- bundles/org.openhab.binding.http/pom.xml | 6 ++---- bundles/org.openhab.binding.hue/pom.xml | 6 ++---- bundles/org.openhab.binding.hydrawise/pom.xml | 6 ++---- bundles/org.openhab.binding.hyperion/pom.xml | 6 ++---- bundles/org.openhab.binding.iammeter/pom.xml | 6 ++---- bundles/org.openhab.binding.iaqualink/pom.xml | 6 ++---- bundles/org.openhab.binding.icalendar/pom.xml | 6 ++---- bundles/org.openhab.binding.icloud/pom.xml | 6 ++---- bundles/org.openhab.binding.ihc/pom.xml | 6 ++---- .../org.openhab.binding.innogysmarthome/pom.xml | 6 ++---- bundles/org.openhab.binding.insteon/pom.xml | 6 ++---- bundles/org.openhab.binding.intesis/pom.xml | 6 ++---- bundles/org.openhab.binding.ipcamera/pom.xml | 6 ++---- bundles/org.openhab.binding.ipobserver/pom.xml | 6 ++---- bundles/org.openhab.binding.ipp/pom.xml | 6 ++---- bundles/org.openhab.binding.irobot/pom.xml | 6 ++---- bundles/org.openhab.binding.irtrans/pom.xml | 6 ++---- bundles/org.openhab.binding.ism8/pom.xml | 6 ++---- bundles/org.openhab.binding.jablotron/pom.xml | 6 ++---- bundles/org.openhab.binding.jeelink/pom.xml | 6 ++---- bundles/org.openhab.binding.kaleidescape/pom.xml | 6 ++---- bundles/org.openhab.binding.keba/pom.xml | 6 ++---- bundles/org.openhab.binding.km200/pom.xml | 6 ++---- bundles/org.openhab.binding.knx/pom.xml | 6 ++---- bundles/org.openhab.binding.kodi/pom.xml | 6 ++---- bundles/org.openhab.binding.konnected/pom.xml | 6 ++---- .../org.openhab.binding.kostalinverter/pom.xml | 6 ++---- bundles/org.openhab.binding.kvv/pom.xml | 6 ++---- bundles/org.openhab.binding.lametrictime/pom.xml | 6 ++---- bundles/org.openhab.binding.lcn/pom.xml | 6 ++---- bundles/org.openhab.binding.leapmotion/pom.xml | 6 ++---- bundles/org.openhab.binding.lghombot/pom.xml | 6 ++---- bundles/org.openhab.binding.lgtvserial/pom.xml | 6 ++---- bundles/org.openhab.binding.lgwebos/pom.xml | 6 ++---- bundles/org.openhab.binding.lifx/pom.xml | 6 ++---- bundles/org.openhab.binding.linky/pom.xml | 6 ++---- bundles/org.openhab.binding.linuxinput/pom.xml | 6 ++---- bundles/org.openhab.binding.lirc/pom.xml | 6 ++---- bundles/org.openhab.binding.logreader/pom.xml | 6 ++---- bundles/org.openhab.binding.loxone/pom.xml | 6 ++---- bundles/org.openhab.binding.luftdateninfo/pom.xml | 6 ++---- bundles/org.openhab.binding.lutron/pom.xml | 6 ++---- .../org.openhab.binding.luxtronikheatpump/pom.xml | 6 ++---- bundles/org.openhab.binding.magentatv/pom.xml | 6 ++---- bundles/org.openhab.binding.mail/pom.xml | 6 ++---- bundles/org.openhab.binding.max/pom.xml | 6 ++---- bundles/org.openhab.binding.mcp23017/pom.xml | 6 ++---- bundles/org.openhab.binding.mecmeter/pom.xml | 6 ++---- bundles/org.openhab.binding.melcloud/pom.xml | 6 ++---- bundles/org.openhab.binding.meteoalerte/pom.xml | 6 ++---- bundles/org.openhab.binding.meteoblue/pom.xml | 6 ++---- bundles/org.openhab.binding.meteostick/pom.xml | 6 ++---- bundles/org.openhab.binding.miele/pom.xml | 6 ++---- bundles/org.openhab.binding.mielecloud/pom.xml | 6 ++---- bundles/org.openhab.binding.mihome/pom.xml | 6 ++---- bundles/org.openhab.binding.miio/pom.xml | 6 ++---- bundles/org.openhab.binding.mikrotik/pom.xml | 6 ++---- bundles/org.openhab.binding.milight/pom.xml | 6 ++---- bundles/org.openhab.binding.millheat/pom.xml | 6 ++---- bundles/org.openhab.binding.minecraft/pom.xml | 6 ++---- bundles/org.openhab.binding.modbus.e3dc/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.modbus.sbc/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.modbus.studer/pom.xml | 6 ++---- .../org.openhab.binding.modbus.sunspec/pom.xml | 6 ++---- bundles/org.openhab.binding.modbus/pom.xml | 6 ++---- .../org.openhab.binding.monopriceaudio/pom.xml | 6 ++---- bundles/org.openhab.binding.mpd/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.mqtt.generic/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.mqtt.homie/pom.xml | 6 ++---- bundles/org.openhab.binding.mqtt/pom.xml | 6 ++---- bundles/org.openhab.binding.myq/pom.xml | 6 ++---- bundles/org.openhab.binding.mystrom/pom.xml | 6 ++---- bundles/org.openhab.binding.nanoleaf/pom.xml | 6 ++---- bundles/org.openhab.binding.neato/pom.xml | 6 ++---- bundles/org.openhab.binding.neeo/pom.xml | 6 ++---- bundles/org.openhab.binding.neohub/pom.xml | 6 ++---- bundles/org.openhab.binding.nest/pom.xml | 6 ++---- bundles/org.openhab.binding.netatmo/pom.xml | 6 ++---- bundles/org.openhab.binding.network/pom.xml | 6 ++---- .../org.openhab.binding.networkupstools/pom.xml | 6 ++---- bundles/org.openhab.binding.nibeheatpump/pom.xml | 6 ++---- bundles/org.openhab.binding.nibeuplink/pom.xml | 6 ++---- bundles/org.openhab.binding.nikobus/pom.xml | 6 ++---- .../org.openhab.binding.nikohomecontrol/pom.xml | 6 ++---- bundles/org.openhab.binding.novafinedust/pom.xml | 6 ++---- bundles/org.openhab.binding.ntp/pom.xml | 6 ++---- bundles/org.openhab.binding.nuki/pom.xml | 6 ++---- bundles/org.openhab.binding.nuvo/pom.xml | 6 ++---- bundles/org.openhab.binding.nzwateralerts/pom.xml | 6 ++---- bundles/org.openhab.binding.oceanic/pom.xml | 6 ++---- bundles/org.openhab.binding.ojelectronics/pom.xml | 6 ++---- bundles/org.openhab.binding.omnikinverter/pom.xml | 6 ++---- bundles/org.openhab.binding.omnilink/pom.xml | 6 ++---- bundles/org.openhab.binding.onebusaway/pom.xml | 6 ++---- bundles/org.openhab.binding.onewire/pom.xml | 6 ++---- bundles/org.openhab.binding.onewiregpio/pom.xml | 6 ++---- bundles/org.openhab.binding.onkyo/pom.xml | 6 ++---- bundles/org.openhab.binding.opengarage/pom.xml | 6 ++---- bundles/org.openhab.binding.opensprinkler/pom.xml | 6 ++---- .../org.openhab.binding.openthermgateway/pom.xml | 6 ++---- bundles/org.openhab.binding.openuv/pom.xml | 6 ++---- .../org.openhab.binding.openweathermap/pom.xml | 6 ++---- bundles/org.openhab.binding.openwebnet/pom.xml | 6 ++---- bundles/org.openhab.binding.oppo/pom.xml | 6 ++---- bundles/org.openhab.binding.orbitbhyve/pom.xml | 6 ++---- bundles/org.openhab.binding.orvibo/pom.xml | 6 ++---- bundles/org.openhab.binding.paradoxalarm/pom.xml | 6 ++---- bundles/org.openhab.binding.pentair/pom.xml | 6 ++---- bundles/org.openhab.binding.phc/pom.xml | 6 ++---- bundles/org.openhab.binding.pilight/pom.xml | 6 ++---- bundles/org.openhab.binding.pioneeravr/pom.xml | 6 ++---- bundles/org.openhab.binding.pixometer/pom.xml | 6 ++---- bundles/org.openhab.binding.pjlinkdevice/pom.xml | 6 ++---- bundles/org.openhab.binding.playstation/pom.xml | 6 ++---- bundles/org.openhab.binding.plclogo/pom.xml | 6 ++---- bundles/org.openhab.binding.plugwise/pom.xml | 6 ++---- bundles/org.openhab.binding.plugwiseha/pom.xml | 6 ++---- bundles/org.openhab.binding.powermax/pom.xml | 6 ++---- .../org.openhab.binding.proteusecometer/pom.xml | 6 ++---- bundles/org.openhab.binding.pulseaudio/pom.xml | 6 ++---- bundles/org.openhab.binding.pushbullet/pom.xml | 6 ++---- bundles/org.openhab.binding.pushover/pom.xml | 6 ++---- bundles/org.openhab.binding.pushsafer/pom.xml | 6 ++---- bundles/org.openhab.binding.qbus/pom.xml | 6 ++---- .../org.openhab.binding.radiothermostat/pom.xml | 6 ++---- bundles/org.openhab.binding.regoheatpump/pom.xml | 6 ++---- bundles/org.openhab.binding.remoteopenhab/pom.xml | 6 ++---- bundles/org.openhab.binding.renault/pom.xml | 6 ++---- bundles/org.openhab.binding.resol/pom.xml | 6 ++---- bundles/org.openhab.binding.revogi/pom.xml | 6 ++---- bundles/org.openhab.binding.rfxcom/pom.xml | 6 ++---- bundles/org.openhab.binding.rme/pom.xml | 6 ++---- bundles/org.openhab.binding.robonect/pom.xml | 6 ++---- bundles/org.openhab.binding.roku/pom.xml | 6 ++---- bundles/org.openhab.binding.rotel/pom.xml | 6 ++---- bundles/org.openhab.binding.russound/pom.xml | 6 ++---- bundles/org.openhab.binding.sagercaster/pom.xml | 6 ++---- bundles/org.openhab.binding.samsungtv/pom.xml | 6 ++---- bundles/org.openhab.binding.satel/pom.xml | 6 ++---- bundles/org.openhab.binding.semsportal/pom.xml | 6 ++---- bundles/org.openhab.binding.senechome/pom.xml | 6 ++---- bundles/org.openhab.binding.seneye/pom.xml | 6 ++---- bundles/org.openhab.binding.sensebox/pom.xml | 6 ++---- bundles/org.openhab.binding.sensibo/pom.xml | 6 ++---- bundles/org.openhab.binding.serial/pom.xml | 6 ++---- bundles/org.openhab.binding.serialbutton/pom.xml | 6 ++---- bundles/org.openhab.binding.shelly/pom.xml | 6 ++---- bundles/org.openhab.binding.siemensrds/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.sinope/pom.xml | 6 ++---- bundles/org.openhab.binding.sleepiq/pom.xml | 6 ++---- .../org.openhab.binding.smaenergymeter/pom.xml | 6 ++---- bundles/org.openhab.binding.smartmeter/pom.xml | 6 ++---- bundles/org.openhab.binding.smartthings/pom.xml | 6 ++---- bundles/org.openhab.binding.smhi/pom.xml | 6 ++---- bundles/org.openhab.binding.sncf/pom.xml | 6 ++---- bundles/org.openhab.binding.snmp/pom.xml | 6 ++---- bundles/org.openhab.binding.solaredge/pom.xml | 6 ++---- bundles/org.openhab.binding.solarlog/pom.xml | 6 ++---- bundles/org.openhab.binding.solarwatt/pom.xml | 6 ++---- bundles/org.openhab.binding.somfymylink/pom.xml | 6 ++---- bundles/org.openhab.binding.somfytahoma/pom.xml | 6 ++---- bundles/org.openhab.binding.sonos/pom.xml | 6 ++---- bundles/org.openhab.binding.sonyaudio/pom.xml | 6 ++---- bundles/org.openhab.binding.sonyprojector/pom.xml | 6 ++---- bundles/org.openhab.binding.souliss/pom.xml | 6 ++---- bundles/org.openhab.binding.spotify/pom.xml | 6 ++---- bundles/org.openhab.binding.squeezebox/pom.xml | 6 ++---- bundles/org.openhab.binding.surepetcare/pom.xml | 6 ++---- bundles/org.openhab.binding.synopanalyzer/pom.xml | 6 ++---- bundles/org.openhab.binding.systeminfo/pom.xml | 6 ++---- bundles/org.openhab.binding.tacmi/pom.xml | 6 ++---- bundles/org.openhab.binding.tado/pom.xml | 6 ++---- bundles/org.openhab.binding.tankerkoenig/pom.xml | 6 ++---- bundles/org.openhab.binding.tapocontrol/pom.xml | 6 ++---- bundles/org.openhab.binding.telegram/pom.xml | 6 ++---- bundles/org.openhab.binding.teleinfo/pom.xml | 6 ++---- bundles/org.openhab.binding.tellstick/pom.xml | 6 ++---- bundles/org.openhab.binding.tesla/pom.xml | 6 ++---- bundles/org.openhab.binding.tibber/pom.xml | 6 ++---- bundles/org.openhab.binding.tivo/pom.xml | 6 ++---- bundles/org.openhab.binding.touchwand/pom.xml | 6 ++---- .../org.openhab.binding.tplinksmarthome/pom.xml | 6 ++---- bundles/org.openhab.binding.tr064/pom.xml | 6 ++---- bundles/org.openhab.binding.tradfri/pom.xml | 6 ++---- bundles/org.openhab.binding.twitter/pom.xml | 6 ++---- bundles/org.openhab.binding.unifi/pom.xml | 6 ++---- bundles/org.openhab.binding.unifiedremote/pom.xml | 6 ++---- bundles/org.openhab.binding.upb/pom.xml | 6 ++---- bundles/org.openhab.binding.upnpcontrol/pom.xml | 6 ++---- bundles/org.openhab.binding.urtsi/pom.xml | 6 ++---- bundles/org.openhab.binding.valloxmv/pom.xml | 6 ++---- bundles/org.openhab.binding.vdr/pom.xml | 6 ++---- bundles/org.openhab.binding.vektiva/pom.xml | 6 ++---- bundles/org.openhab.binding.velbus/pom.xml | 6 ++---- bundles/org.openhab.binding.velux/pom.xml | 6 ++---- .../org.openhab.binding.venstarthermostat/pom.xml | 6 ++---- bundles/org.openhab.binding.ventaair/pom.xml | 6 ++---- bundles/org.openhab.binding.verisure/pom.xml | 6 ++---- bundles/org.openhab.binding.vigicrues/pom.xml | 6 ++---- bundles/org.openhab.binding.vitotronic/pom.xml | 6 ++---- bundles/org.openhab.binding.volvooncall/pom.xml | 6 ++---- bundles/org.openhab.binding.warmup/pom.xml | 6 ++---- .../org.openhab.binding.weathercompany/pom.xml | 6 ++---- .../pom.xml | 6 ++---- bundles/org.openhab.binding.webthing/pom.xml | 6 ++---- bundles/org.openhab.binding.wemo/pom.xml | 6 ++---- bundles/org.openhab.binding.wifiled/pom.xml | 6 ++---- bundles/org.openhab.binding.windcentrale/pom.xml | 6 ++---- bundles/org.openhab.binding.wlanthermo/pom.xml | 6 ++---- bundles/org.openhab.binding.wled/pom.xml | 6 ++---- bundles/org.openhab.binding.wolfsmartset/pom.xml | 6 ++---- bundles/org.openhab.binding.xmltv/pom.xml | 6 ++---- bundles/org.openhab.binding.xmppclient/pom.xml | 6 ++---- .../org.openhab.binding.yamahareceiver/pom.xml | 6 ++---- bundles/org.openhab.binding.yeelight/pom.xml | 6 ++---- bundles/org.openhab.binding.yioremote/pom.xml | 6 ++---- bundles/org.openhab.binding.zoneminder/pom.xml | 6 ++---- bundles/org.openhab.binding.zway/pom.xml | 6 ++---- bundles/org.openhab.io.homekit/pom.xml | 6 ++---- bundles/org.openhab.io.hueemulation/pom.xml | 6 ++---- bundles/org.openhab.io.imperihome/pom.xml | 6 ++---- bundles/org.openhab.io.metrics/pom.xml | 6 ++---- bundles/org.openhab.io.neeo/pom.xml | 6 ++---- bundles/org.openhab.io.openhabcloud/pom.xml | 6 ++---- bundles/org.openhab.persistence.dynamodb/pom.xml | 6 ++---- bundles/org.openhab.persistence.influxdb/pom.xml | 6 ++---- bundles/org.openhab.persistence.jdbc/pom.xml | 6 ++---- bundles/org.openhab.persistence.jpa/pom.xml | 6 ++---- bundles/org.openhab.persistence.mapdb/pom.xml | 6 ++---- bundles/org.openhab.persistence.mongodb/pom.xml | 6 ++---- bundles/org.openhab.persistence.rrd4j/pom.xml | 6 ++---- bundles/org.openhab.transform.bin2json/pom.xml | 6 ++---- bundles/org.openhab.transform.exec/pom.xml | 6 ++---- bundles/org.openhab.transform.javascript/pom.xml | 6 ++---- bundles/org.openhab.transform.jinja/pom.xml | 6 ++---- bundles/org.openhab.transform.jsonpath/pom.xml | 6 ++---- bundles/org.openhab.transform.map/pom.xml | 6 ++---- bundles/org.openhab.transform.regex/pom.xml | 6 ++---- bundles/org.openhab.transform.scale/pom.xml | 6 ++---- bundles/org.openhab.transform.xpath/pom.xml | 6 ++---- bundles/org.openhab.transform.xslt/pom.xml | 6 ++---- bundles/org.openhab.voice.googletts/pom.xml | 6 ++---- bundles/org.openhab.voice.mactts/pom.xml | 6 ++---- bundles/org.openhab.voice.marytts/pom.xml | 6 ++---- bundles/org.openhab.voice.picotts/pom.xml | 6 ++---- bundles/org.openhab.voice.pollytts/pom.xml | 6 ++---- bundles/org.openhab.voice.voicerss/pom.xml | 6 ++---- bundles/pom.xml | 6 ++---- features/openhab-addons-external/pom.xml | 6 ++---- features/openhab-addons/pom.xml | 9 +++------ features/pom.xml | 6 ++---- itests/org.openhab.binding.astro.tests/pom.xml | 6 ++---- itests/org.openhab.binding.avmfritz.tests/pom.xml | 6 ++---- itests/org.openhab.binding.feed.tests/pom.xml | 6 ++---- itests/org.openhab.binding.hue.tests/pom.xml | 6 ++---- itests/org.openhab.binding.max.tests/pom.xml | 6 ++---- .../org.openhab.binding.mielecloud.tests/pom.xml | 6 ++---- itests/org.openhab.binding.modbus.tests/pom.xml | 6 ++---- itests/org.openhab.binding.nest.tests/pom.xml | 6 ++---- itests/org.openhab.binding.ntp.tests/pom.xml | 6 ++---- .../org.openhab.binding.systeminfo.tests/pom.xml | 6 ++---- itests/org.openhab.binding.tradfri.tests/pom.xml | 6 ++---- itests/org.openhab.binding.wemo.tests/pom.xml | 6 ++---- .../org.openhab.persistence.mapdb.tests/pom.xml | 6 ++---- itests/pom.xml | 6 ++---- pom.xml | 8 +++----- 393 files changed, 791 insertions(+), 1581 deletions(-) diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 5ce8d23a023d9..ad0e6564b5cef 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bom org.openhab.addons.reactor.bom - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bom.openhab-addons diff --git a/bom/openhab-core-index/pom.xml b/bom/openhab-core-index/pom.xml index 3456b6202c2b5..99bb3c2712fbd 100644 --- a/bom/openhab-core-index/pom.xml +++ b/bom/openhab-core-index/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bom org.openhab.addons.reactor.bom - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bom.openhab-core-index diff --git a/bom/pom.xml b/bom/pom.xml index eb177324e81a9..18942f907d7f1 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons org.openhab.addons.reactor - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bom @@ -39,14 +37,11 @@ - + - + - + header diff --git a/bom/runtime-index/pom.xml b/bom/runtime-index/pom.xml index 6f7d6162570de..75e2de0502f4d 100644 --- a/bom/runtime-index/pom.xml +++ b/bom/runtime-index/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bom org.openhab.addons.reactor.bom - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bom.runtime-index diff --git a/bom/test-index/pom.xml b/bom/test-index/pom.xml index 817a356f8e22c..d10c095e9afa2 100644 --- a/bom/test-index/pom.xml +++ b/bom/test-index/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bom org.openhab.addons.reactor.bom - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bom.test-index diff --git a/bundles/org.openhab.automation.groovyscripting/pom.xml b/bundles/org.openhab.automation.groovyscripting/pom.xml index 14472d023c519..1f67a063ea9b4 100644 --- a/bundles/org.openhab.automation.groovyscripting/pom.xml +++ b/bundles/org.openhab.automation.groovyscripting/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.groovyscripting diff --git a/bundles/org.openhab.automation.jrubyscripting/pom.xml b/bundles/org.openhab.automation.jrubyscripting/pom.xml index 5a4e65d12ffd8..07b5b8d9ce384 100644 --- a/bundles/org.openhab.automation.jrubyscripting/pom.xml +++ b/bundles/org.openhab.automation.jrubyscripting/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.jrubyscripting diff --git a/bundles/org.openhab.automation.jsscripting/pom.xml b/bundles/org.openhab.automation.jsscripting/pom.xml index af6b049e298d2..ea995c055e9ed 100644 --- a/bundles/org.openhab.automation.jsscripting/pom.xml +++ b/bundles/org.openhab.automation.jsscripting/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.jsscripting diff --git a/bundles/org.openhab.automation.jythonscripting/pom.xml b/bundles/org.openhab.automation.jythonscripting/pom.xml index 6533d1d72b098..e7c3fec47213a 100644 --- a/bundles/org.openhab.automation.jythonscripting/pom.xml +++ b/bundles/org.openhab.automation.jythonscripting/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.jythonscripting diff --git a/bundles/org.openhab.automation.pidcontroller/pom.xml b/bundles/org.openhab.automation.pidcontroller/pom.xml index 18a5ed49e76b9..4ce46018c56d9 100644 --- a/bundles/org.openhab.automation.pidcontroller/pom.xml +++ b/bundles/org.openhab.automation.pidcontroller/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.pidcontroller diff --git a/bundles/org.openhab.automation.pwm/pom.xml b/bundles/org.openhab.automation.pwm/pom.xml index 406fad0562ce1..7e8c67e24968e 100644 --- a/bundles/org.openhab.automation.pwm/pom.xml +++ b/bundles/org.openhab.automation.pwm/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.automation.pwm diff --git a/bundles/org.openhab.binding.adorne/pom.xml b/bundles/org.openhab.binding.adorne/pom.xml index b54f153cb7f71..afc44bf2488e3 100644 --- a/bundles/org.openhab.binding.adorne/pom.xml +++ b/bundles/org.openhab.binding.adorne/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.adorne diff --git a/bundles/org.openhab.binding.ahawastecollection/pom.xml b/bundles/org.openhab.binding.ahawastecollection/pom.xml index e4069b04f72bc..ca91fe36811a1 100644 --- a/bundles/org.openhab.binding.ahawastecollection/pom.xml +++ b/bundles/org.openhab.binding.ahawastecollection/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ahawastecollection diff --git a/bundles/org.openhab.binding.airq/pom.xml b/bundles/org.openhab.binding.airq/pom.xml index 6d6295793140a..202dcedea1c17 100644 --- a/bundles/org.openhab.binding.airq/pom.xml +++ b/bundles/org.openhab.binding.airq/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.airq diff --git a/bundles/org.openhab.binding.airquality/pom.xml b/bundles/org.openhab.binding.airquality/pom.xml index b25893b605856..dfacad0e6989d 100644 --- a/bundles/org.openhab.binding.airquality/pom.xml +++ b/bundles/org.openhab.binding.airquality/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.airquality diff --git a/bundles/org.openhab.binding.airvisualnode/pom.xml b/bundles/org.openhab.binding.airvisualnode/pom.xml index f0207650f1785..db6213863eda9 100644 --- a/bundles/org.openhab.binding.airvisualnode/pom.xml +++ b/bundles/org.openhab.binding.airvisualnode/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.airvisualnode diff --git a/bundles/org.openhab.binding.alarmdecoder/pom.xml b/bundles/org.openhab.binding.alarmdecoder/pom.xml index 28819561e65f5..cfef62bf80f03 100644 --- a/bundles/org.openhab.binding.alarmdecoder/pom.xml +++ b/bundles/org.openhab.binding.alarmdecoder/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.alarmdecoder diff --git a/bundles/org.openhab.binding.allplay/pom.xml b/bundles/org.openhab.binding.allplay/pom.xml index 733613f9deea8..0971954a5a7bd 100644 --- a/bundles/org.openhab.binding.allplay/pom.xml +++ b/bundles/org.openhab.binding.allplay/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.allplay diff --git a/bundles/org.openhab.binding.amazondashbutton/pom.xml b/bundles/org.openhab.binding.amazondashbutton/pom.xml index e6b9de41ef9f3..91080ae8d0d5a 100644 --- a/bundles/org.openhab.binding.amazondashbutton/pom.xml +++ b/bundles/org.openhab.binding.amazondashbutton/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.amazondashbutton diff --git a/bundles/org.openhab.binding.amazonechocontrol/pom.xml b/bundles/org.openhab.binding.amazonechocontrol/pom.xml index b773a68d14c5f..d36d148219925 100644 --- a/bundles/org.openhab.binding.amazonechocontrol/pom.xml +++ b/bundles/org.openhab.binding.amazonechocontrol/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.amazonechocontrol diff --git a/bundles/org.openhab.binding.ambientweather/pom.xml b/bundles/org.openhab.binding.ambientweather/pom.xml index cfa4a2867106d..bfcaf1a263d78 100644 --- a/bundles/org.openhab.binding.ambientweather/pom.xml +++ b/bundles/org.openhab.binding.ambientweather/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ambientweather diff --git a/bundles/org.openhab.binding.amplipi/pom.xml b/bundles/org.openhab.binding.amplipi/pom.xml index 55ec0c7caa2ee..bf462e02d3a8b 100644 --- a/bundles/org.openhab.binding.amplipi/pom.xml +++ b/bundles/org.openhab.binding.amplipi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.amplipi diff --git a/bundles/org.openhab.binding.androiddebugbridge/pom.xml b/bundles/org.openhab.binding.androiddebugbridge/pom.xml index 7650096685618..bb1f11865caeb 100644 --- a/bundles/org.openhab.binding.androiddebugbridge/pom.xml +++ b/bundles/org.openhab.binding.androiddebugbridge/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.androiddebugbridge diff --git a/bundles/org.openhab.binding.anel/pom.xml b/bundles/org.openhab.binding.anel/pom.xml index 325a69c4de77e..fbbf0e92bb7dd 100644 --- a/bundles/org.openhab.binding.anel/pom.xml +++ b/bundles/org.openhab.binding.anel/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.anel diff --git a/bundles/org.openhab.binding.astro/pom.xml b/bundles/org.openhab.binding.astro/pom.xml index 5e3199a19bd34..d5a6c055cf94c 100644 --- a/bundles/org.openhab.binding.astro/pom.xml +++ b/bundles/org.openhab.binding.astro/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.astro diff --git a/bundles/org.openhab.binding.atlona/pom.xml b/bundles/org.openhab.binding.atlona/pom.xml index 73e9f4de13584..600df7cfacfe5 100644 --- a/bundles/org.openhab.binding.atlona/pom.xml +++ b/bundles/org.openhab.binding.atlona/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.atlona diff --git a/bundles/org.openhab.binding.autelis/pom.xml b/bundles/org.openhab.binding.autelis/pom.xml index c6bc9b8beb9ae..38b7c1c7f09d6 100644 --- a/bundles/org.openhab.binding.autelis/pom.xml +++ b/bundles/org.openhab.binding.autelis/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.autelis diff --git a/bundles/org.openhab.binding.automower/pom.xml b/bundles/org.openhab.binding.automower/pom.xml index 35d5f29bbe580..8fd7e66c0cbc0 100644 --- a/bundles/org.openhab.binding.automower/pom.xml +++ b/bundles/org.openhab.binding.automower/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.automower diff --git a/bundles/org.openhab.binding.avmfritz/pom.xml b/bundles/org.openhab.binding.avmfritz/pom.xml index a587827e74e2c..219a9a0487e2c 100644 --- a/bundles/org.openhab.binding.avmfritz/pom.xml +++ b/bundles/org.openhab.binding.avmfritz/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.avmfritz diff --git a/bundles/org.openhab.binding.benqprojector/pom.xml b/bundles/org.openhab.binding.benqprojector/pom.xml index 3dceca45a5632..251f29f964085 100644 --- a/bundles/org.openhab.binding.benqprojector/pom.xml +++ b/bundles/org.openhab.binding.benqprojector/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.benqprojector diff --git a/bundles/org.openhab.binding.bigassfan/pom.xml b/bundles/org.openhab.binding.bigassfan/pom.xml index 829996efcafc8..c1a4952afd7a0 100644 --- a/bundles/org.openhab.binding.bigassfan/pom.xml +++ b/bundles/org.openhab.binding.bigassfan/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bigassfan diff --git a/bundles/org.openhab.binding.bluetooth.airthings/pom.xml b/bundles/org.openhab.binding.bluetooth.airthings/pom.xml index bd8aa1f5f8c38..ed72d0c3fe192 100644 --- a/bundles/org.openhab.binding.bluetooth.airthings/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.airthings/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.airthings diff --git a/bundles/org.openhab.binding.bluetooth.am43/pom.xml b/bundles/org.openhab.binding.bluetooth.am43/pom.xml index f69c769a6bb61..2ec5b338d7ea4 100644 --- a/bundles/org.openhab.binding.bluetooth.am43/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.am43/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.am43 diff --git a/bundles/org.openhab.binding.bluetooth.bluegiga/pom.xml b/bundles/org.openhab.binding.bluetooth.bluegiga/pom.xml index 3eaf1fd93f032..a7b234ccbebef 100644 --- a/bundles/org.openhab.binding.bluetooth.bluegiga/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.bluegiga/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.bluegiga diff --git a/bundles/org.openhab.binding.bluetooth.bluez/pom.xml b/bundles/org.openhab.binding.bluetooth.bluez/pom.xml index f8c963f0afcfc..0769fe248233a 100644 --- a/bundles/org.openhab.binding.bluetooth.bluez/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.bluez/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.bluez diff --git a/bundles/org.openhab.binding.bluetooth.blukii/pom.xml b/bundles/org.openhab.binding.bluetooth.blukii/pom.xml index 28612d9ef08ad..aeaca7c7ab83b 100644 --- a/bundles/org.openhab.binding.bluetooth.blukii/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.blukii/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.blukii diff --git a/bundles/org.openhab.binding.bluetooth.daikinmadoka/pom.xml b/bundles/org.openhab.binding.bluetooth.daikinmadoka/pom.xml index 927ccf2b2dd96..4057edd967509 100644 --- a/bundles/org.openhab.binding.bluetooth.daikinmadoka/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.daikinmadoka/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.daikinmadoka diff --git a/bundles/org.openhab.binding.bluetooth.enoceanble/pom.xml b/bundles/org.openhab.binding.bluetooth.enoceanble/pom.xml index d38512217b262..f1f5933631253 100644 --- a/bundles/org.openhab.binding.bluetooth.enoceanble/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.enoceanble/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.enoceanble diff --git a/bundles/org.openhab.binding.bluetooth.generic/pom.xml b/bundles/org.openhab.binding.bluetooth.generic/pom.xml index c86acdde350b7..0f155db7dc162 100644 --- a/bundles/org.openhab.binding.bluetooth.generic/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.generic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.generic diff --git a/bundles/org.openhab.binding.bluetooth.govee/pom.xml b/bundles/org.openhab.binding.bluetooth.govee/pom.xml index 786b43d0edbe1..c1380cf21ea32 100644 --- a/bundles/org.openhab.binding.bluetooth.govee/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.govee/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.govee diff --git a/bundles/org.openhab.binding.bluetooth.roaming/pom.xml b/bundles/org.openhab.binding.bluetooth.roaming/pom.xml index 4eb842ba45466..185af64350d77 100644 --- a/bundles/org.openhab.binding.bluetooth.roaming/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.roaming/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.roaming diff --git a/bundles/org.openhab.binding.bluetooth.ruuvitag/pom.xml b/bundles/org.openhab.binding.bluetooth.ruuvitag/pom.xml index e382f1c3e7ea5..5fa307d1aab87 100644 --- a/bundles/org.openhab.binding.bluetooth.ruuvitag/pom.xml +++ b/bundles/org.openhab.binding.bluetooth.ruuvitag/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth.ruuvitag diff --git a/bundles/org.openhab.binding.bluetooth/pom.xml b/bundles/org.openhab.binding.bluetooth/pom.xml index 5132fea63d78b..fd30c194e66da 100644 --- a/bundles/org.openhab.binding.bluetooth/pom.xml +++ b/bundles/org.openhab.binding.bluetooth/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bluetooth diff --git a/bundles/org.openhab.binding.bmwconnecteddrive/pom.xml b/bundles/org.openhab.binding.bmwconnecteddrive/pom.xml index dc2b5f2ee12c5..601356087aacf 100644 --- a/bundles/org.openhab.binding.bmwconnecteddrive/pom.xml +++ b/bundles/org.openhab.binding.bmwconnecteddrive/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bmwconnecteddrive diff --git a/bundles/org.openhab.binding.boschindego/pom.xml b/bundles/org.openhab.binding.boschindego/pom.xml index cc84519ef84b4..23ad73db54651 100644 --- a/bundles/org.openhab.binding.boschindego/pom.xml +++ b/bundles/org.openhab.binding.boschindego/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.boschindego diff --git a/bundles/org.openhab.binding.boschshc/pom.xml b/bundles/org.openhab.binding.boschshc/pom.xml index 933e850df0795..bb4833deebc63 100644 --- a/bundles/org.openhab.binding.boschshc/pom.xml +++ b/bundles/org.openhab.binding.boschshc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.boschshc diff --git a/bundles/org.openhab.binding.bosesoundtouch/pom.xml b/bundles/org.openhab.binding.bosesoundtouch/pom.xml index 1e0c80f271102..dd447d8f6b80a 100644 --- a/bundles/org.openhab.binding.bosesoundtouch/pom.xml +++ b/bundles/org.openhab.binding.bosesoundtouch/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bosesoundtouch diff --git a/bundles/org.openhab.binding.broadlinkthermostat/pom.xml b/bundles/org.openhab.binding.broadlinkthermostat/pom.xml index 090de068353f6..aa37aeaca6d03 100644 --- a/bundles/org.openhab.binding.broadlinkthermostat/pom.xml +++ b/bundles/org.openhab.binding.broadlinkthermostat/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.broadlinkthermostat diff --git a/bundles/org.openhab.binding.bsblan/pom.xml b/bundles/org.openhab.binding.bsblan/pom.xml index 71b9352f1b9d5..5d64e2906b42e 100644 --- a/bundles/org.openhab.binding.bsblan/pom.xml +++ b/bundles/org.openhab.binding.bsblan/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bsblan diff --git a/bundles/org.openhab.binding.bticinosmarther/pom.xml b/bundles/org.openhab.binding.bticinosmarther/pom.xml index 76b1238137263..a8b65db1ab4cc 100644 --- a/bundles/org.openhab.binding.bticinosmarther/pom.xml +++ b/bundles/org.openhab.binding.bticinosmarther/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.bticinosmarther diff --git a/bundles/org.openhab.binding.buienradar/pom.xml b/bundles/org.openhab.binding.buienradar/pom.xml index 2954710e675fa..8c95a155a2d1d 100644 --- a/bundles/org.openhab.binding.buienradar/pom.xml +++ b/bundles/org.openhab.binding.buienradar/pom.xml @@ -1,11 +1,9 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.buienradar openHAB Add-ons :: Bundles :: Buienradar Binding diff --git a/bundles/org.openhab.binding.caddx/pom.xml b/bundles/org.openhab.binding.caddx/pom.xml index d90a4c2d5f9aa..a6a4a8d8cf554 100644 --- a/bundles/org.openhab.binding.caddx/pom.xml +++ b/bundles/org.openhab.binding.caddx/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.caddx diff --git a/bundles/org.openhab.binding.cbus/pom.xml b/bundles/org.openhab.binding.cbus/pom.xml index 36d2764733c89..a1a99733a00c3 100644 --- a/bundles/org.openhab.binding.cbus/pom.xml +++ b/bundles/org.openhab.binding.cbus/pom.xml @@ -1,6 +1,4 @@ - - + 4.0.0 @@ -8,7 +6,7 @@ org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.cbus diff --git a/bundles/org.openhab.binding.chromecast/pom.xml b/bundles/org.openhab.binding.chromecast/pom.xml index f28ea0b361914..243a6443d9fba 100644 --- a/bundles/org.openhab.binding.chromecast/pom.xml +++ b/bundles/org.openhab.binding.chromecast/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.chromecast diff --git a/bundles/org.openhab.binding.cm11a/pom.xml b/bundles/org.openhab.binding.cm11a/pom.xml index fd49156f41aa2..36ad9bd1b9561 100644 --- a/bundles/org.openhab.binding.cm11a/pom.xml +++ b/bundles/org.openhab.binding.cm11a/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.cm11a diff --git a/bundles/org.openhab.binding.comfoair/pom.xml b/bundles/org.openhab.binding.comfoair/pom.xml index b6a05190cb234..d2479e65da6c4 100644 --- a/bundles/org.openhab.binding.comfoair/pom.xml +++ b/bundles/org.openhab.binding.comfoair/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.comfoair diff --git a/bundles/org.openhab.binding.coolmasternet/pom.xml b/bundles/org.openhab.binding.coolmasternet/pom.xml index 85b4b7161cf16..71fa59e7f12ec 100644 --- a/bundles/org.openhab.binding.coolmasternet/pom.xml +++ b/bundles/org.openhab.binding.coolmasternet/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.coolmasternet diff --git a/bundles/org.openhab.binding.coronastats/pom.xml b/bundles/org.openhab.binding.coronastats/pom.xml index 92618cc02f6f3..fdf6258776448 100644 --- a/bundles/org.openhab.binding.coronastats/pom.xml +++ b/bundles/org.openhab.binding.coronastats/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.coronastats diff --git a/bundles/org.openhab.binding.daikin/pom.xml b/bundles/org.openhab.binding.daikin/pom.xml index 1a9f8739e5b1b..2f5554757ce40 100644 --- a/bundles/org.openhab.binding.daikin/pom.xml +++ b/bundles/org.openhab.binding.daikin/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.daikin diff --git a/bundles/org.openhab.binding.dali/pom.xml b/bundles/org.openhab.binding.dali/pom.xml index bbf43a45b9f23..b1bb69856095b 100644 --- a/bundles/org.openhab.binding.dali/pom.xml +++ b/bundles/org.openhab.binding.dali/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dali diff --git a/bundles/org.openhab.binding.danfossairunit/pom.xml b/bundles/org.openhab.binding.danfossairunit/pom.xml index 44affd933a276..39443ebe4b463 100644 --- a/bundles/org.openhab.binding.danfossairunit/pom.xml +++ b/bundles/org.openhab.binding.danfossairunit/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.danfossairunit diff --git a/bundles/org.openhab.binding.darksky/pom.xml b/bundles/org.openhab.binding.darksky/pom.xml index 354378667ed58..720eb017d6bd5 100644 --- a/bundles/org.openhab.binding.darksky/pom.xml +++ b/bundles/org.openhab.binding.darksky/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.darksky diff --git a/bundles/org.openhab.binding.dbquery/pom.xml b/bundles/org.openhab.binding.dbquery/pom.xml index 0ac0787c13860..b16869df10d44 100644 --- a/bundles/org.openhab.binding.dbquery/pom.xml +++ b/bundles/org.openhab.binding.dbquery/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dbquery diff --git a/bundles/org.openhab.binding.deconz/pom.xml b/bundles/org.openhab.binding.deconz/pom.xml index a0774180d377d..431679324f0cd 100644 --- a/bundles/org.openhab.binding.deconz/pom.xml +++ b/bundles/org.openhab.binding.deconz/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.deconz diff --git a/bundles/org.openhab.binding.denonmarantz/pom.xml b/bundles/org.openhab.binding.denonmarantz/pom.xml index fdee178f6928c..7f6470d600af2 100644 --- a/bundles/org.openhab.binding.denonmarantz/pom.xml +++ b/bundles/org.openhab.binding.denonmarantz/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.denonmarantz diff --git a/bundles/org.openhab.binding.deutschebahn/pom.xml b/bundles/org.openhab.binding.deutschebahn/pom.xml index 48ddb0006be01..df625aad20402 100644 --- a/bundles/org.openhab.binding.deutschebahn/pom.xml +++ b/bundles/org.openhab.binding.deutschebahn/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.deutschebahn diff --git a/bundles/org.openhab.binding.digiplex/pom.xml b/bundles/org.openhab.binding.digiplex/pom.xml index 276d6069659d5..21b63b31591d5 100644 --- a/bundles/org.openhab.binding.digiplex/pom.xml +++ b/bundles/org.openhab.binding.digiplex/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.digiplex diff --git a/bundles/org.openhab.binding.digitalstrom/pom.xml b/bundles/org.openhab.binding.digitalstrom/pom.xml index b3b73fe4f778b..45ee2a150b7a3 100644 --- a/bundles/org.openhab.binding.digitalstrom/pom.xml +++ b/bundles/org.openhab.binding.digitalstrom/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.digitalstrom diff --git a/bundles/org.openhab.binding.dlinksmarthome/pom.xml b/bundles/org.openhab.binding.dlinksmarthome/pom.xml index d347dd07d04b8..4cd08bf93ee9e 100644 --- a/bundles/org.openhab.binding.dlinksmarthome/pom.xml +++ b/bundles/org.openhab.binding.dlinksmarthome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dlinksmarthome diff --git a/bundles/org.openhab.binding.dmx/pom.xml b/bundles/org.openhab.binding.dmx/pom.xml index ca5ecce684379..ec92a4057f5ab 100644 --- a/bundles/org.openhab.binding.dmx/pom.xml +++ b/bundles/org.openhab.binding.dmx/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dmx diff --git a/bundles/org.openhab.binding.dominoswiss/pom.xml b/bundles/org.openhab.binding.dominoswiss/pom.xml index b5c5b3cd2e0fd..701a49bf52289 100644 --- a/bundles/org.openhab.binding.dominoswiss/pom.xml +++ b/bundles/org.openhab.binding.dominoswiss/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dominoswiss diff --git a/bundles/org.openhab.binding.doorbird/pom.xml b/bundles/org.openhab.binding.doorbird/pom.xml index a1f3754109a3c..3f0698fac46f8 100644 --- a/bundles/org.openhab.binding.doorbird/pom.xml +++ b/bundles/org.openhab.binding.doorbird/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.doorbird diff --git a/bundles/org.openhab.binding.draytonwiser/pom.xml b/bundles/org.openhab.binding.draytonwiser/pom.xml index 031f1b4d10bcf..89fd8309839bb 100644 --- a/bundles/org.openhab.binding.draytonwiser/pom.xml +++ b/bundles/org.openhab.binding.draytonwiser/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.draytonwiser diff --git a/bundles/org.openhab.binding.dscalarm/pom.xml b/bundles/org.openhab.binding.dscalarm/pom.xml index 4376995198d66..38ed77957c88a 100644 --- a/bundles/org.openhab.binding.dscalarm/pom.xml +++ b/bundles/org.openhab.binding.dscalarm/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dscalarm diff --git a/bundles/org.openhab.binding.dsmr/pom.xml b/bundles/org.openhab.binding.dsmr/pom.xml index 2e69e6044308b..97d6fdb2a78d6 100644 --- a/bundles/org.openhab.binding.dsmr/pom.xml +++ b/bundles/org.openhab.binding.dsmr/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dsmr diff --git a/bundles/org.openhab.binding.dwdpollenflug/pom.xml b/bundles/org.openhab.binding.dwdpollenflug/pom.xml index 39335bb8f4277..44451498c0a70 100644 --- a/bundles/org.openhab.binding.dwdpollenflug/pom.xml +++ b/bundles/org.openhab.binding.dwdpollenflug/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dwdpollenflug diff --git a/bundles/org.openhab.binding.dwdunwetter/pom.xml b/bundles/org.openhab.binding.dwdunwetter/pom.xml index b396ff90bfeb2..118810e97b94d 100644 --- a/bundles/org.openhab.binding.dwdunwetter/pom.xml +++ b/bundles/org.openhab.binding.dwdunwetter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.dwdunwetter diff --git a/bundles/org.openhab.binding.ecobee/pom.xml b/bundles/org.openhab.binding.ecobee/pom.xml index 30a253a66637d..4c83f1988cec8 100644 --- a/bundles/org.openhab.binding.ecobee/pom.xml +++ b/bundles/org.openhab.binding.ecobee/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ecobee diff --git a/bundles/org.openhab.binding.ecotouch/pom.xml b/bundles/org.openhab.binding.ecotouch/pom.xml index 1c80d2d239483..8052f8dd2fdda 100644 --- a/bundles/org.openhab.binding.ecotouch/pom.xml +++ b/bundles/org.openhab.binding.ecotouch/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ecotouch diff --git a/bundles/org.openhab.binding.ekey/pom.xml b/bundles/org.openhab.binding.ekey/pom.xml index c7682fba56314..7073db97cf1cd 100644 --- a/bundles/org.openhab.binding.ekey/pom.xml +++ b/bundles/org.openhab.binding.ekey/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ekey diff --git a/bundles/org.openhab.binding.elerotransmitterstick/pom.xml b/bundles/org.openhab.binding.elerotransmitterstick/pom.xml index ad417fee63824..985e1cdc40d53 100644 --- a/bundles/org.openhab.binding.elerotransmitterstick/pom.xml +++ b/bundles/org.openhab.binding.elerotransmitterstick/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.elerotransmitterstick diff --git a/bundles/org.openhab.binding.energenie/pom.xml b/bundles/org.openhab.binding.energenie/pom.xml index 7dfbe84043e15..7ff618c2e7a90 100644 --- a/bundles/org.openhab.binding.energenie/pom.xml +++ b/bundles/org.openhab.binding.energenie/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.energenie diff --git a/bundles/org.openhab.binding.enigma2/pom.xml b/bundles/org.openhab.binding.enigma2/pom.xml index 56b66aa6ba528..63e9998151c51 100644 --- a/bundles/org.openhab.binding.enigma2/pom.xml +++ b/bundles/org.openhab.binding.enigma2/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.enigma2 diff --git a/bundles/org.openhab.binding.enocean/pom.xml b/bundles/org.openhab.binding.enocean/pom.xml index 42ea266173934..7cb571013b8ec 100644 --- a/bundles/org.openhab.binding.enocean/pom.xml +++ b/bundles/org.openhab.binding.enocean/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.enocean diff --git a/bundles/org.openhab.binding.enphase/pom.xml b/bundles/org.openhab.binding.enphase/pom.xml index 5d2d16e42a4f4..072351ab46a49 100644 --- a/bundles/org.openhab.binding.enphase/pom.xml +++ b/bundles/org.openhab.binding.enphase/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.enphase diff --git a/bundles/org.openhab.binding.enturno/pom.xml b/bundles/org.openhab.binding.enturno/pom.xml index bcdf52753c649..305e6e4beba3e 100644 --- a/bundles/org.openhab.binding.enturno/pom.xml +++ b/bundles/org.openhab.binding.enturno/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.enturno diff --git a/bundles/org.openhab.binding.epsonprojector/pom.xml b/bundles/org.openhab.binding.epsonprojector/pom.xml index 40a4f4c978e5e..c2573f7ce41e5 100644 --- a/bundles/org.openhab.binding.epsonprojector/pom.xml +++ b/bundles/org.openhab.binding.epsonprojector/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.epsonprojector diff --git a/bundles/org.openhab.binding.etherrain/pom.xml b/bundles/org.openhab.binding.etherrain/pom.xml index e76ed92c5fb58..264de9e0c97ad 100644 --- a/bundles/org.openhab.binding.etherrain/pom.xml +++ b/bundles/org.openhab.binding.etherrain/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.etherrain diff --git a/bundles/org.openhab.binding.evohome/pom.xml b/bundles/org.openhab.binding.evohome/pom.xml index 68eca5501e6d9..fbc5d7a46391c 100644 --- a/bundles/org.openhab.binding.evohome/pom.xml +++ b/bundles/org.openhab.binding.evohome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.evohome diff --git a/bundles/org.openhab.binding.exec/pom.xml b/bundles/org.openhab.binding.exec/pom.xml index 9582e90dfc23a..63242a2d5c215 100644 --- a/bundles/org.openhab.binding.exec/pom.xml +++ b/bundles/org.openhab.binding.exec/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.exec diff --git a/bundles/org.openhab.binding.feed/pom.xml b/bundles/org.openhab.binding.feed/pom.xml index 0ad4cd113847f..b85d670d15c2b 100644 --- a/bundles/org.openhab.binding.feed/pom.xml +++ b/bundles/org.openhab.binding.feed/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.feed diff --git a/bundles/org.openhab.binding.feican/pom.xml b/bundles/org.openhab.binding.feican/pom.xml index e4e99fe21565e..5a3886733e279 100644 --- a/bundles/org.openhab.binding.feican/pom.xml +++ b/bundles/org.openhab.binding.feican/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.feican diff --git a/bundles/org.openhab.binding.fmiweather/pom.xml b/bundles/org.openhab.binding.fmiweather/pom.xml index 6950d7460c409..d3b0567a9a8a6 100644 --- a/bundles/org.openhab.binding.fmiweather/pom.xml +++ b/bundles/org.openhab.binding.fmiweather/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.fmiweather diff --git a/bundles/org.openhab.binding.folderwatcher/pom.xml b/bundles/org.openhab.binding.folderwatcher/pom.xml index 442fe5131b9e4..1ffe2c29e9a9e 100644 --- a/bundles/org.openhab.binding.folderwatcher/pom.xml +++ b/bundles/org.openhab.binding.folderwatcher/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.folderwatcher diff --git a/bundles/org.openhab.binding.folding/pom.xml b/bundles/org.openhab.binding.folding/pom.xml index 43ca21ef09324..3aeb07810ca9a 100644 --- a/bundles/org.openhab.binding.folding/pom.xml +++ b/bundles/org.openhab.binding.folding/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.folding diff --git a/bundles/org.openhab.binding.foobot/pom.xml b/bundles/org.openhab.binding.foobot/pom.xml index aea6f4c4a5398..31588fec087fa 100644 --- a/bundles/org.openhab.binding.foobot/pom.xml +++ b/bundles/org.openhab.binding.foobot/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.foobot diff --git a/bundles/org.openhab.binding.freebox/pom.xml b/bundles/org.openhab.binding.freebox/pom.xml index e991e474293b2..76d2769655922 100644 --- a/bundles/org.openhab.binding.freebox/pom.xml +++ b/bundles/org.openhab.binding.freebox/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.freebox diff --git a/bundles/org.openhab.binding.fronius/pom.xml b/bundles/org.openhab.binding.fronius/pom.xml index 860df607c5ff5..e3ecaae345b7f 100644 --- a/bundles/org.openhab.binding.fronius/pom.xml +++ b/bundles/org.openhab.binding.fronius/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.fronius diff --git a/bundles/org.openhab.binding.fsinternetradio/pom.xml b/bundles/org.openhab.binding.fsinternetradio/pom.xml index d06f07bf3bc91..7fb790619d0a0 100644 --- a/bundles/org.openhab.binding.fsinternetradio/pom.xml +++ b/bundles/org.openhab.binding.fsinternetradio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.fsinternetradio diff --git a/bundles/org.openhab.binding.ftpupload/pom.xml b/bundles/org.openhab.binding.ftpupload/pom.xml index e63a70bac4acd..2233e301c04e1 100644 --- a/bundles/org.openhab.binding.ftpupload/pom.xml +++ b/bundles/org.openhab.binding.ftpupload/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ftpupload diff --git a/bundles/org.openhab.binding.gardena/pom.xml b/bundles/org.openhab.binding.gardena/pom.xml index 218dfa37f8ac8..524df57201b14 100644 --- a/bundles/org.openhab.binding.gardena/pom.xml +++ b/bundles/org.openhab.binding.gardena/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.gardena diff --git a/bundles/org.openhab.binding.gce/pom.xml b/bundles/org.openhab.binding.gce/pom.xml index c2aa79f94bf08..8bd54356db534 100644 --- a/bundles/org.openhab.binding.gce/pom.xml +++ b/bundles/org.openhab.binding.gce/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.gce diff --git a/bundles/org.openhab.binding.generacmobilelink/pom.xml b/bundles/org.openhab.binding.generacmobilelink/pom.xml index d4b8230dd0402..70893340a7476 100644 --- a/bundles/org.openhab.binding.generacmobilelink/pom.xml +++ b/bundles/org.openhab.binding.generacmobilelink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.generacmobilelink diff --git a/bundles/org.openhab.binding.globalcache/pom.xml b/bundles/org.openhab.binding.globalcache/pom.xml index 77a18300f001c..9ca641bea5ff9 100644 --- a/bundles/org.openhab.binding.globalcache/pom.xml +++ b/bundles/org.openhab.binding.globalcache/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.globalcache diff --git a/bundles/org.openhab.binding.goecharger/pom.xml b/bundles/org.openhab.binding.goecharger/pom.xml index 766be80bec905..620800e9a7c1b 100644 --- a/bundles/org.openhab.binding.goecharger/pom.xml +++ b/bundles/org.openhab.binding.goecharger/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.goecharger diff --git a/bundles/org.openhab.binding.gpio/pom.xml b/bundles/org.openhab.binding.gpio/pom.xml index 54fcaa1a7524e..feabf7cfa9616 100644 --- a/bundles/org.openhab.binding.gpio/pom.xml +++ b/bundles/org.openhab.binding.gpio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.gpio diff --git a/bundles/org.openhab.binding.gpstracker/pom.xml b/bundles/org.openhab.binding.gpstracker/pom.xml index 9c1ad019f68b5..2bb2b7fc1f4a9 100644 --- a/bundles/org.openhab.binding.gpstracker/pom.xml +++ b/bundles/org.openhab.binding.gpstracker/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.gpstracker diff --git a/bundles/org.openhab.binding.gree/pom.xml b/bundles/org.openhab.binding.gree/pom.xml index 58b7c4527d47c..241cef10b5d17 100644 --- a/bundles/org.openhab.binding.gree/pom.xml +++ b/bundles/org.openhab.binding.gree/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.gree diff --git a/bundles/org.openhab.binding.groheondus/pom.xml b/bundles/org.openhab.binding.groheondus/pom.xml index 0dbc9269c18cc..c179d4bbf5eb0 100644 --- a/bundles/org.openhab.binding.groheondus/pom.xml +++ b/bundles/org.openhab.binding.groheondus/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.groheondus diff --git a/bundles/org.openhab.binding.haassohnpelletstove/pom.xml b/bundles/org.openhab.binding.haassohnpelletstove/pom.xml index 78d7a404fc1bc..c9147e8bc1bdd 100644 --- a/bundles/org.openhab.binding.haassohnpelletstove/pom.xml +++ b/bundles/org.openhab.binding.haassohnpelletstove/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.haassohnpelletstove diff --git a/bundles/org.openhab.binding.harmonyhub/pom.xml b/bundles/org.openhab.binding.harmonyhub/pom.xml index 069c97ef0a05e..0bdbf01bec4aa 100644 --- a/bundles/org.openhab.binding.harmonyhub/pom.xml +++ b/bundles/org.openhab.binding.harmonyhub/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.harmonyhub diff --git a/bundles/org.openhab.binding.haywardomnilogic/pom.xml b/bundles/org.openhab.binding.haywardomnilogic/pom.xml index 97f06df6ce17a..5786919bac8cc 100644 --- a/bundles/org.openhab.binding.haywardomnilogic/pom.xml +++ b/bundles/org.openhab.binding.haywardomnilogic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.haywardomnilogic diff --git a/bundles/org.openhab.binding.hccrubbishcollection/pom.xml b/bundles/org.openhab.binding.hccrubbishcollection/pom.xml index a577a983ef018..e1882aa183a11 100644 --- a/bundles/org.openhab.binding.hccrubbishcollection/pom.xml +++ b/bundles/org.openhab.binding.hccrubbishcollection/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hccrubbishcollection diff --git a/bundles/org.openhab.binding.hdanywhere/pom.xml b/bundles/org.openhab.binding.hdanywhere/pom.xml index ce6514430b9e9..d21d2d01f50da 100644 --- a/bundles/org.openhab.binding.hdanywhere/pom.xml +++ b/bundles/org.openhab.binding.hdanywhere/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hdanywhere diff --git a/bundles/org.openhab.binding.hdpowerview/pom.xml b/bundles/org.openhab.binding.hdpowerview/pom.xml index f58bf1a66fa09..b7f350b70858b 100644 --- a/bundles/org.openhab.binding.hdpowerview/pom.xml +++ b/bundles/org.openhab.binding.hdpowerview/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hdpowerview diff --git a/bundles/org.openhab.binding.helios/pom.xml b/bundles/org.openhab.binding.helios/pom.xml index 896abee8bb8b3..d2a18ba6acb8b 100644 --- a/bundles/org.openhab.binding.helios/pom.xml +++ b/bundles/org.openhab.binding.helios/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.helios diff --git a/bundles/org.openhab.binding.heliosventilation/pom.xml b/bundles/org.openhab.binding.heliosventilation/pom.xml index d9c35781e0199..e77727c14e32a 100644 --- a/bundles/org.openhab.binding.heliosventilation/pom.xml +++ b/bundles/org.openhab.binding.heliosventilation/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.heliosventilation diff --git a/bundles/org.openhab.binding.heos/pom.xml b/bundles/org.openhab.binding.heos/pom.xml index 6fd96554c4f86..977230bc45095 100644 --- a/bundles/org.openhab.binding.heos/pom.xml +++ b/bundles/org.openhab.binding.heos/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.heos diff --git a/bundles/org.openhab.binding.homeconnect/pom.xml b/bundles/org.openhab.binding.homeconnect/pom.xml index 18708239ba5ba..fa6214930e142 100644 --- a/bundles/org.openhab.binding.homeconnect/pom.xml +++ b/bundles/org.openhab.binding.homeconnect/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.homeconnect diff --git a/bundles/org.openhab.binding.homematic/pom.xml b/bundles/org.openhab.binding.homematic/pom.xml index f83ef84acc0c1..93e2777604381 100644 --- a/bundles/org.openhab.binding.homematic/pom.xml +++ b/bundles/org.openhab.binding.homematic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.homematic diff --git a/bundles/org.openhab.binding.homewizard/pom.xml b/bundles/org.openhab.binding.homewizard/pom.xml index 8bbf79251861d..95987d4888e89 100644 --- a/bundles/org.openhab.binding.homewizard/pom.xml +++ b/bundles/org.openhab.binding.homewizard/pom.xml @@ -1,11 +1,9 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.homewizard openHAB Add-ons :: Bundles :: HomeWizard Binding diff --git a/bundles/org.openhab.binding.hpprinter/pom.xml b/bundles/org.openhab.binding.hpprinter/pom.xml index c4b93b2b7a9c6..f68c625a147f2 100644 --- a/bundles/org.openhab.binding.hpprinter/pom.xml +++ b/bundles/org.openhab.binding.hpprinter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hpprinter diff --git a/bundles/org.openhab.binding.http/pom.xml b/bundles/org.openhab.binding.http/pom.xml index 3072131a86789..3d19197f72e34 100644 --- a/bundles/org.openhab.binding.http/pom.xml +++ b/bundles/org.openhab.binding.http/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.http diff --git a/bundles/org.openhab.binding.hue/pom.xml b/bundles/org.openhab.binding.hue/pom.xml index de810f3a69980..b1ccdb41a5f1d 100644 --- a/bundles/org.openhab.binding.hue/pom.xml +++ b/bundles/org.openhab.binding.hue/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hue diff --git a/bundles/org.openhab.binding.hydrawise/pom.xml b/bundles/org.openhab.binding.hydrawise/pom.xml index 3ce7cad8af4f3..77d3f1e9d5a88 100644 --- a/bundles/org.openhab.binding.hydrawise/pom.xml +++ b/bundles/org.openhab.binding.hydrawise/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hydrawise diff --git a/bundles/org.openhab.binding.hyperion/pom.xml b/bundles/org.openhab.binding.hyperion/pom.xml index b68cf3a58a045..b8b61fbed6302 100644 --- a/bundles/org.openhab.binding.hyperion/pom.xml +++ b/bundles/org.openhab.binding.hyperion/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.hyperion diff --git a/bundles/org.openhab.binding.iammeter/pom.xml b/bundles/org.openhab.binding.iammeter/pom.xml index 2d073f11e11e3..1ecb1ff20ebbf 100644 --- a/bundles/org.openhab.binding.iammeter/pom.xml +++ b/bundles/org.openhab.binding.iammeter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.iammeter diff --git a/bundles/org.openhab.binding.iaqualink/pom.xml b/bundles/org.openhab.binding.iaqualink/pom.xml index 31cfdb6e90da6..f34c1022fa352 100644 --- a/bundles/org.openhab.binding.iaqualink/pom.xml +++ b/bundles/org.openhab.binding.iaqualink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.iaqualink diff --git a/bundles/org.openhab.binding.icalendar/pom.xml b/bundles/org.openhab.binding.icalendar/pom.xml index 768f07224abf3..fc493a709efe7 100644 --- a/bundles/org.openhab.binding.icalendar/pom.xml +++ b/bundles/org.openhab.binding.icalendar/pom.xml @@ -1,11 +1,9 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.icalendar openHAB Add-ons :: Bundles :: iCalendar Binding diff --git a/bundles/org.openhab.binding.icloud/pom.xml b/bundles/org.openhab.binding.icloud/pom.xml index e98c1aa6d085a..6410299d11a7d 100644 --- a/bundles/org.openhab.binding.icloud/pom.xml +++ b/bundles/org.openhab.binding.icloud/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.icloud diff --git a/bundles/org.openhab.binding.ihc/pom.xml b/bundles/org.openhab.binding.ihc/pom.xml index ed4cb9cf2497c..c4150769d5b42 100644 --- a/bundles/org.openhab.binding.ihc/pom.xml +++ b/bundles/org.openhab.binding.ihc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ihc diff --git a/bundles/org.openhab.binding.innogysmarthome/pom.xml b/bundles/org.openhab.binding.innogysmarthome/pom.xml index 917ceaea0e570..f189dae3a6e2a 100644 --- a/bundles/org.openhab.binding.innogysmarthome/pom.xml +++ b/bundles/org.openhab.binding.innogysmarthome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.innogysmarthome diff --git a/bundles/org.openhab.binding.insteon/pom.xml b/bundles/org.openhab.binding.insteon/pom.xml index a40cd433b7357..8327867044a85 100644 --- a/bundles/org.openhab.binding.insteon/pom.xml +++ b/bundles/org.openhab.binding.insteon/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.insteon diff --git a/bundles/org.openhab.binding.intesis/pom.xml b/bundles/org.openhab.binding.intesis/pom.xml index 725b3286d4bde..1aa671d986bc4 100644 --- a/bundles/org.openhab.binding.intesis/pom.xml +++ b/bundles/org.openhab.binding.intesis/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.intesis diff --git a/bundles/org.openhab.binding.ipcamera/pom.xml b/bundles/org.openhab.binding.ipcamera/pom.xml index 181918c99ee29..1e99879eb8414 100644 --- a/bundles/org.openhab.binding.ipcamera/pom.xml +++ b/bundles/org.openhab.binding.ipcamera/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ipcamera diff --git a/bundles/org.openhab.binding.ipobserver/pom.xml b/bundles/org.openhab.binding.ipobserver/pom.xml index 8ccc812a05502..debc51b92bd6d 100644 --- a/bundles/org.openhab.binding.ipobserver/pom.xml +++ b/bundles/org.openhab.binding.ipobserver/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ipobserver diff --git a/bundles/org.openhab.binding.ipp/pom.xml b/bundles/org.openhab.binding.ipp/pom.xml index acbc7dd2a2a97..5a704007e4795 100644 --- a/bundles/org.openhab.binding.ipp/pom.xml +++ b/bundles/org.openhab.binding.ipp/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ipp diff --git a/bundles/org.openhab.binding.irobot/pom.xml b/bundles/org.openhab.binding.irobot/pom.xml index 35e06a24d9fa7..e6b0aadec73e3 100644 --- a/bundles/org.openhab.binding.irobot/pom.xml +++ b/bundles/org.openhab.binding.irobot/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.irobot diff --git a/bundles/org.openhab.binding.irtrans/pom.xml b/bundles/org.openhab.binding.irtrans/pom.xml index 7055eacab89ae..b32421b5dddf6 100644 --- a/bundles/org.openhab.binding.irtrans/pom.xml +++ b/bundles/org.openhab.binding.irtrans/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.irtrans diff --git a/bundles/org.openhab.binding.ism8/pom.xml b/bundles/org.openhab.binding.ism8/pom.xml index bf2094570752a..514887322abae 100644 --- a/bundles/org.openhab.binding.ism8/pom.xml +++ b/bundles/org.openhab.binding.ism8/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ism8 diff --git a/bundles/org.openhab.binding.jablotron/pom.xml b/bundles/org.openhab.binding.jablotron/pom.xml index 06c5a8d8acd15..bacf9fdfde113 100644 --- a/bundles/org.openhab.binding.jablotron/pom.xml +++ b/bundles/org.openhab.binding.jablotron/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.jablotron diff --git a/bundles/org.openhab.binding.jeelink/pom.xml b/bundles/org.openhab.binding.jeelink/pom.xml index 68bc2e8b40f70..76b8bb9c1f5b7 100644 --- a/bundles/org.openhab.binding.jeelink/pom.xml +++ b/bundles/org.openhab.binding.jeelink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.jeelink diff --git a/bundles/org.openhab.binding.kaleidescape/pom.xml b/bundles/org.openhab.binding.kaleidescape/pom.xml index a4bcf0483d959..b6ac145eb0dfa 100644 --- a/bundles/org.openhab.binding.kaleidescape/pom.xml +++ b/bundles/org.openhab.binding.kaleidescape/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.kaleidescape diff --git a/bundles/org.openhab.binding.keba/pom.xml b/bundles/org.openhab.binding.keba/pom.xml index 0f0de5267e293..58858192d1bed 100644 --- a/bundles/org.openhab.binding.keba/pom.xml +++ b/bundles/org.openhab.binding.keba/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.keba diff --git a/bundles/org.openhab.binding.km200/pom.xml b/bundles/org.openhab.binding.km200/pom.xml index 0140e6b88099d..ad102e60d5af7 100644 --- a/bundles/org.openhab.binding.km200/pom.xml +++ b/bundles/org.openhab.binding.km200/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.km200 diff --git a/bundles/org.openhab.binding.knx/pom.xml b/bundles/org.openhab.binding.knx/pom.xml index f7faff1148a82..e190a0859584b 100644 --- a/bundles/org.openhab.binding.knx/pom.xml +++ b/bundles/org.openhab.binding.knx/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.knx diff --git a/bundles/org.openhab.binding.kodi/pom.xml b/bundles/org.openhab.binding.kodi/pom.xml index aa5aa6a0f4797..3e635d73554c0 100644 --- a/bundles/org.openhab.binding.kodi/pom.xml +++ b/bundles/org.openhab.binding.kodi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.kodi diff --git a/bundles/org.openhab.binding.konnected/pom.xml b/bundles/org.openhab.binding.konnected/pom.xml index 188bc586c28bb..19cf8a1f96cf9 100644 --- a/bundles/org.openhab.binding.konnected/pom.xml +++ b/bundles/org.openhab.binding.konnected/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.konnected diff --git a/bundles/org.openhab.binding.kostalinverter/pom.xml b/bundles/org.openhab.binding.kostalinverter/pom.xml index f123404d37da5..39a31fac3677f 100644 --- a/bundles/org.openhab.binding.kostalinverter/pom.xml +++ b/bundles/org.openhab.binding.kostalinverter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.kostalinverter diff --git a/bundles/org.openhab.binding.kvv/pom.xml b/bundles/org.openhab.binding.kvv/pom.xml index 21ca78a296d46..17e28081eab4c 100644 --- a/bundles/org.openhab.binding.kvv/pom.xml +++ b/bundles/org.openhab.binding.kvv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.kvv diff --git a/bundles/org.openhab.binding.lametrictime/pom.xml b/bundles/org.openhab.binding.lametrictime/pom.xml index 97f19f6cb795d..67cd67084c389 100644 --- a/bundles/org.openhab.binding.lametrictime/pom.xml +++ b/bundles/org.openhab.binding.lametrictime/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lametrictime diff --git a/bundles/org.openhab.binding.lcn/pom.xml b/bundles/org.openhab.binding.lcn/pom.xml index ed51e82af0f30..2216f2731c28a 100644 --- a/bundles/org.openhab.binding.lcn/pom.xml +++ b/bundles/org.openhab.binding.lcn/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lcn diff --git a/bundles/org.openhab.binding.leapmotion/pom.xml b/bundles/org.openhab.binding.leapmotion/pom.xml index 3ff357cca48fe..f8cac6244e97b 100644 --- a/bundles/org.openhab.binding.leapmotion/pom.xml +++ b/bundles/org.openhab.binding.leapmotion/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.leapmotion diff --git a/bundles/org.openhab.binding.lghombot/pom.xml b/bundles/org.openhab.binding.lghombot/pom.xml index 1900d1fc591dc..480c9a0913fff 100644 --- a/bundles/org.openhab.binding.lghombot/pom.xml +++ b/bundles/org.openhab.binding.lghombot/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lghombot diff --git a/bundles/org.openhab.binding.lgtvserial/pom.xml b/bundles/org.openhab.binding.lgtvserial/pom.xml index 848afd5b4b134..b0d027299b72b 100644 --- a/bundles/org.openhab.binding.lgtvserial/pom.xml +++ b/bundles/org.openhab.binding.lgtvserial/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lgtvserial diff --git a/bundles/org.openhab.binding.lgwebos/pom.xml b/bundles/org.openhab.binding.lgwebos/pom.xml index 5e8cb8c8f7f2d..b2109c3f08ee7 100644 --- a/bundles/org.openhab.binding.lgwebos/pom.xml +++ b/bundles/org.openhab.binding.lgwebos/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lgwebos diff --git a/bundles/org.openhab.binding.lifx/pom.xml b/bundles/org.openhab.binding.lifx/pom.xml index d21fef4ebd3e0..906e8284da6fd 100644 --- a/bundles/org.openhab.binding.lifx/pom.xml +++ b/bundles/org.openhab.binding.lifx/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lifx diff --git a/bundles/org.openhab.binding.linky/pom.xml b/bundles/org.openhab.binding.linky/pom.xml index 91f453971211a..e885770a23968 100644 --- a/bundles/org.openhab.binding.linky/pom.xml +++ b/bundles/org.openhab.binding.linky/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.linky diff --git a/bundles/org.openhab.binding.linuxinput/pom.xml b/bundles/org.openhab.binding.linuxinput/pom.xml index 18a3e41265a42..bc8b6b3f8c681 100644 --- a/bundles/org.openhab.binding.linuxinput/pom.xml +++ b/bundles/org.openhab.binding.linuxinput/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.linuxinput diff --git a/bundles/org.openhab.binding.lirc/pom.xml b/bundles/org.openhab.binding.lirc/pom.xml index 46fe2605870c2..2680c476b031e 100644 --- a/bundles/org.openhab.binding.lirc/pom.xml +++ b/bundles/org.openhab.binding.lirc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lirc diff --git a/bundles/org.openhab.binding.logreader/pom.xml b/bundles/org.openhab.binding.logreader/pom.xml index 7365deab6a6ab..ad0cf13dd3b8d 100644 --- a/bundles/org.openhab.binding.logreader/pom.xml +++ b/bundles/org.openhab.binding.logreader/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.logreader diff --git a/bundles/org.openhab.binding.loxone/pom.xml b/bundles/org.openhab.binding.loxone/pom.xml index 010bfe61195b1..880944300bdeb 100644 --- a/bundles/org.openhab.binding.loxone/pom.xml +++ b/bundles/org.openhab.binding.loxone/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.loxone diff --git a/bundles/org.openhab.binding.luftdateninfo/pom.xml b/bundles/org.openhab.binding.luftdateninfo/pom.xml index 0482e1515a39d..1de1c42b24c4e 100644 --- a/bundles/org.openhab.binding.luftdateninfo/pom.xml +++ b/bundles/org.openhab.binding.luftdateninfo/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.luftdateninfo diff --git a/bundles/org.openhab.binding.lutron/pom.xml b/bundles/org.openhab.binding.lutron/pom.xml index 3b60ce6537b6c..8de7b40363732 100644 --- a/bundles/org.openhab.binding.lutron/pom.xml +++ b/bundles/org.openhab.binding.lutron/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.lutron diff --git a/bundles/org.openhab.binding.luxtronikheatpump/pom.xml b/bundles/org.openhab.binding.luxtronikheatpump/pom.xml index fb65d2def4b11..0307113bd8276 100644 --- a/bundles/org.openhab.binding.luxtronikheatpump/pom.xml +++ b/bundles/org.openhab.binding.luxtronikheatpump/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.luxtronikheatpump diff --git a/bundles/org.openhab.binding.magentatv/pom.xml b/bundles/org.openhab.binding.magentatv/pom.xml index 0705f0df41bfb..8a5bb6a0fefd6 100644 --- a/bundles/org.openhab.binding.magentatv/pom.xml +++ b/bundles/org.openhab.binding.magentatv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.magentatv diff --git a/bundles/org.openhab.binding.mail/pom.xml b/bundles/org.openhab.binding.mail/pom.xml index 1b39a3b5b3c2a..4364e0a5c640e 100644 --- a/bundles/org.openhab.binding.mail/pom.xml +++ b/bundles/org.openhab.binding.mail/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mail diff --git a/bundles/org.openhab.binding.max/pom.xml b/bundles/org.openhab.binding.max/pom.xml index 371f312452a92..efc6496182a85 100644 --- a/bundles/org.openhab.binding.max/pom.xml +++ b/bundles/org.openhab.binding.max/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.max diff --git a/bundles/org.openhab.binding.mcp23017/pom.xml b/bundles/org.openhab.binding.mcp23017/pom.xml index 2a8cc07cc9cc2..93dfcf12b941c 100644 --- a/bundles/org.openhab.binding.mcp23017/pom.xml +++ b/bundles/org.openhab.binding.mcp23017/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mcp23017 diff --git a/bundles/org.openhab.binding.mecmeter/pom.xml b/bundles/org.openhab.binding.mecmeter/pom.xml index afafbbcb03271..2d37d13281b00 100644 --- a/bundles/org.openhab.binding.mecmeter/pom.xml +++ b/bundles/org.openhab.binding.mecmeter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mecmeter diff --git a/bundles/org.openhab.binding.melcloud/pom.xml b/bundles/org.openhab.binding.melcloud/pom.xml index c3f2e5d88cf2d..6df421bc6a8c0 100644 --- a/bundles/org.openhab.binding.melcloud/pom.xml +++ b/bundles/org.openhab.binding.melcloud/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.melcloud diff --git a/bundles/org.openhab.binding.meteoalerte/pom.xml b/bundles/org.openhab.binding.meteoalerte/pom.xml index d15a9dd9a3fcd..4f657ad87412c 100644 --- a/bundles/org.openhab.binding.meteoalerte/pom.xml +++ b/bundles/org.openhab.binding.meteoalerte/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.meteoalerte diff --git a/bundles/org.openhab.binding.meteoblue/pom.xml b/bundles/org.openhab.binding.meteoblue/pom.xml index 4b2c0531996de..0dce09cd1266e 100644 --- a/bundles/org.openhab.binding.meteoblue/pom.xml +++ b/bundles/org.openhab.binding.meteoblue/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.meteoblue diff --git a/bundles/org.openhab.binding.meteostick/pom.xml b/bundles/org.openhab.binding.meteostick/pom.xml index 01f7288691a4e..0e6e27ea140a9 100644 --- a/bundles/org.openhab.binding.meteostick/pom.xml +++ b/bundles/org.openhab.binding.meteostick/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.meteostick diff --git a/bundles/org.openhab.binding.miele/pom.xml b/bundles/org.openhab.binding.miele/pom.xml index c5226dc2f7e6e..0c85ecd1e4468 100644 --- a/bundles/org.openhab.binding.miele/pom.xml +++ b/bundles/org.openhab.binding.miele/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.miele diff --git a/bundles/org.openhab.binding.mielecloud/pom.xml b/bundles/org.openhab.binding.mielecloud/pom.xml index 493d3c1fc6057..2d686093f4e7d 100644 --- a/bundles/org.openhab.binding.mielecloud/pom.xml +++ b/bundles/org.openhab.binding.mielecloud/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mielecloud diff --git a/bundles/org.openhab.binding.mihome/pom.xml b/bundles/org.openhab.binding.mihome/pom.xml index e5824a16371c0..9d7bbb8209bee 100644 --- a/bundles/org.openhab.binding.mihome/pom.xml +++ b/bundles/org.openhab.binding.mihome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mihome diff --git a/bundles/org.openhab.binding.miio/pom.xml b/bundles/org.openhab.binding.miio/pom.xml index 1cd8342be88b2..9c8639bd0f416 100644 --- a/bundles/org.openhab.binding.miio/pom.xml +++ b/bundles/org.openhab.binding.miio/pom.xml @@ -1,11 +1,9 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.miio openHAB Add-ons :: Bundles :: Xiaomi Wifi devices (Mi IO) Binding diff --git a/bundles/org.openhab.binding.mikrotik/pom.xml b/bundles/org.openhab.binding.mikrotik/pom.xml index 08a7da4226b96..5c8a6086c87b8 100644 --- a/bundles/org.openhab.binding.mikrotik/pom.xml +++ b/bundles/org.openhab.binding.mikrotik/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mikrotik diff --git a/bundles/org.openhab.binding.milight/pom.xml b/bundles/org.openhab.binding.milight/pom.xml index 22a3718f94314..f34e94c7039f4 100644 --- a/bundles/org.openhab.binding.milight/pom.xml +++ b/bundles/org.openhab.binding.milight/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.milight diff --git a/bundles/org.openhab.binding.millheat/pom.xml b/bundles/org.openhab.binding.millheat/pom.xml index df612505e8fff..7c9e3bdcf2737 100644 --- a/bundles/org.openhab.binding.millheat/pom.xml +++ b/bundles/org.openhab.binding.millheat/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.millheat diff --git a/bundles/org.openhab.binding.minecraft/pom.xml b/bundles/org.openhab.binding.minecraft/pom.xml index a1d948cc724d2..7f0c54af7fcc5 100644 --- a/bundles/org.openhab.binding.minecraft/pom.xml +++ b/bundles/org.openhab.binding.minecraft/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.minecraft diff --git a/bundles/org.openhab.binding.modbus.e3dc/pom.xml b/bundles/org.openhab.binding.modbus.e3dc/pom.xml index 731e02b51840e..da0fd716ee323 100644 --- a/bundles/org.openhab.binding.modbus.e3dc/pom.xml +++ b/bundles/org.openhab.binding.modbus.e3dc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.e3dc diff --git a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml index 90f0a5c211961..33a3a2cf1c9fb 100644 --- a/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml +++ b/bundles/org.openhab.binding.modbus.helioseasycontrols/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.helioseasycontrols diff --git a/bundles/org.openhab.binding.modbus.sbc/pom.xml b/bundles/org.openhab.binding.modbus.sbc/pom.xml index 1999d6ebc2c50..904cebdfa8bc5 100644 --- a/bundles/org.openhab.binding.modbus.sbc/pom.xml +++ b/bundles/org.openhab.binding.modbus.sbc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.sbc diff --git a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml index 9eaaee7b14fbb..1ea98866fe9c6 100644 --- a/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml +++ b/bundles/org.openhab.binding.modbus.stiebeleltron/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.stiebeleltron diff --git a/bundles/org.openhab.binding.modbus.studer/pom.xml b/bundles/org.openhab.binding.modbus.studer/pom.xml index ea6627bc74a3a..1c4ee243ed5c4 100644 --- a/bundles/org.openhab.binding.modbus.studer/pom.xml +++ b/bundles/org.openhab.binding.modbus.studer/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.studer diff --git a/bundles/org.openhab.binding.modbus.sunspec/pom.xml b/bundles/org.openhab.binding.modbus.sunspec/pom.xml index 70680856a8672..b67693a280b8c 100644 --- a/bundles/org.openhab.binding.modbus.sunspec/pom.xml +++ b/bundles/org.openhab.binding.modbus.sunspec/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus.sunspec diff --git a/bundles/org.openhab.binding.modbus/pom.xml b/bundles/org.openhab.binding.modbus/pom.xml index ea26f507dd7bb..fac16b10b8b6d 100644 --- a/bundles/org.openhab.binding.modbus/pom.xml +++ b/bundles/org.openhab.binding.modbus/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.modbus diff --git a/bundles/org.openhab.binding.monopriceaudio/pom.xml b/bundles/org.openhab.binding.monopriceaudio/pom.xml index 442c41d3e7d4a..037120a2f27f9 100644 --- a/bundles/org.openhab.binding.monopriceaudio/pom.xml +++ b/bundles/org.openhab.binding.monopriceaudio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.monopriceaudio diff --git a/bundles/org.openhab.binding.mpd/pom.xml b/bundles/org.openhab.binding.mpd/pom.xml index 55a0412445b67..65005de7d90a5 100644 --- a/bundles/org.openhab.binding.mpd/pom.xml +++ b/bundles/org.openhab.binding.mpd/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mpd diff --git a/bundles/org.openhab.binding.mqtt.espmilighthub/pom.xml b/bundles/org.openhab.binding.mqtt.espmilighthub/pom.xml index e68dfccefb3fb..bde74073fd49b 100644 --- a/bundles/org.openhab.binding.mqtt.espmilighthub/pom.xml +++ b/bundles/org.openhab.binding.mqtt.espmilighthub/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mqtt.espmilighthub diff --git a/bundles/org.openhab.binding.mqtt.generic/pom.xml b/bundles/org.openhab.binding.mqtt.generic/pom.xml index d7bdaa762fbc3..2e8840da6eb58 100644 --- a/bundles/org.openhab.binding.mqtt.generic/pom.xml +++ b/bundles/org.openhab.binding.mqtt.generic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mqtt.generic diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml b/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml index d4528d7ec8738..6e1d43f26ca67 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml +++ b/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mqtt.homeassistant diff --git a/bundles/org.openhab.binding.mqtt.homie/pom.xml b/bundles/org.openhab.binding.mqtt.homie/pom.xml index 1ae94eb3d1c30..c8245102d0b0a 100644 --- a/bundles/org.openhab.binding.mqtt.homie/pom.xml +++ b/bundles/org.openhab.binding.mqtt.homie/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mqtt.homie diff --git a/bundles/org.openhab.binding.mqtt/pom.xml b/bundles/org.openhab.binding.mqtt/pom.xml index 3842d5c322a61..87c0c491e397e 100644 --- a/bundles/org.openhab.binding.mqtt/pom.xml +++ b/bundles/org.openhab.binding.mqtt/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mqtt diff --git a/bundles/org.openhab.binding.myq/pom.xml b/bundles/org.openhab.binding.myq/pom.xml index 2ecc9a29d340d..0c71ad907413a 100644 --- a/bundles/org.openhab.binding.myq/pom.xml +++ b/bundles/org.openhab.binding.myq/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.myq diff --git a/bundles/org.openhab.binding.mystrom/pom.xml b/bundles/org.openhab.binding.mystrom/pom.xml index 232d2f07d80f6..63436e7b1c367 100644 --- a/bundles/org.openhab.binding.mystrom/pom.xml +++ b/bundles/org.openhab.binding.mystrom/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.mystrom diff --git a/bundles/org.openhab.binding.nanoleaf/pom.xml b/bundles/org.openhab.binding.nanoleaf/pom.xml index a6b47c321a669..a6adf2440023b 100644 --- a/bundles/org.openhab.binding.nanoleaf/pom.xml +++ b/bundles/org.openhab.binding.nanoleaf/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nanoleaf diff --git a/bundles/org.openhab.binding.neato/pom.xml b/bundles/org.openhab.binding.neato/pom.xml index 8c3f09c5defbd..35f5e04e02ee3 100644 --- a/bundles/org.openhab.binding.neato/pom.xml +++ b/bundles/org.openhab.binding.neato/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.neato diff --git a/bundles/org.openhab.binding.neeo/pom.xml b/bundles/org.openhab.binding.neeo/pom.xml index 40a4dc99c34d6..13b93f622b73f 100644 --- a/bundles/org.openhab.binding.neeo/pom.xml +++ b/bundles/org.openhab.binding.neeo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.neeo diff --git a/bundles/org.openhab.binding.neohub/pom.xml b/bundles/org.openhab.binding.neohub/pom.xml index f1d66941a7624..44db128ba8640 100644 --- a/bundles/org.openhab.binding.neohub/pom.xml +++ b/bundles/org.openhab.binding.neohub/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.neohub diff --git a/bundles/org.openhab.binding.nest/pom.xml b/bundles/org.openhab.binding.nest/pom.xml index 6198e843ac64f..4ec827867bcc5 100644 --- a/bundles/org.openhab.binding.nest/pom.xml +++ b/bundles/org.openhab.binding.nest/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nest diff --git a/bundles/org.openhab.binding.netatmo/pom.xml b/bundles/org.openhab.binding.netatmo/pom.xml index bef045a35f495..0162571aab168 100644 --- a/bundles/org.openhab.binding.netatmo/pom.xml +++ b/bundles/org.openhab.binding.netatmo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.netatmo diff --git a/bundles/org.openhab.binding.network/pom.xml b/bundles/org.openhab.binding.network/pom.xml index da4c0887a666a..586cb14aba02c 100644 --- a/bundles/org.openhab.binding.network/pom.xml +++ b/bundles/org.openhab.binding.network/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.network diff --git a/bundles/org.openhab.binding.networkupstools/pom.xml b/bundles/org.openhab.binding.networkupstools/pom.xml index 2579d13747fed..ad318a465d9fd 100644 --- a/bundles/org.openhab.binding.networkupstools/pom.xml +++ b/bundles/org.openhab.binding.networkupstools/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.networkupstools diff --git a/bundles/org.openhab.binding.nibeheatpump/pom.xml b/bundles/org.openhab.binding.nibeheatpump/pom.xml index 34becd4462a2d..bfa2e1339b957 100644 --- a/bundles/org.openhab.binding.nibeheatpump/pom.xml +++ b/bundles/org.openhab.binding.nibeheatpump/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nibeheatpump diff --git a/bundles/org.openhab.binding.nibeuplink/pom.xml b/bundles/org.openhab.binding.nibeuplink/pom.xml index 292156f0a4dc3..9efbd6e6a9419 100644 --- a/bundles/org.openhab.binding.nibeuplink/pom.xml +++ b/bundles/org.openhab.binding.nibeuplink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nibeuplink diff --git a/bundles/org.openhab.binding.nikobus/pom.xml b/bundles/org.openhab.binding.nikobus/pom.xml index 2d9c7fdd9d2d0..e094a420a9980 100644 --- a/bundles/org.openhab.binding.nikobus/pom.xml +++ b/bundles/org.openhab.binding.nikobus/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nikobus diff --git a/bundles/org.openhab.binding.nikohomecontrol/pom.xml b/bundles/org.openhab.binding.nikohomecontrol/pom.xml index 5e8d98fe13fdd..2fc00d0571719 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/pom.xml +++ b/bundles/org.openhab.binding.nikohomecontrol/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nikohomecontrol diff --git a/bundles/org.openhab.binding.novafinedust/pom.xml b/bundles/org.openhab.binding.novafinedust/pom.xml index d4e01c0d7a4e4..d6a0bac068167 100644 --- a/bundles/org.openhab.binding.novafinedust/pom.xml +++ b/bundles/org.openhab.binding.novafinedust/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.novafinedust diff --git a/bundles/org.openhab.binding.ntp/pom.xml b/bundles/org.openhab.binding.ntp/pom.xml index 601477450340d..ab0aea15fd4e0 100644 --- a/bundles/org.openhab.binding.ntp/pom.xml +++ b/bundles/org.openhab.binding.ntp/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ntp diff --git a/bundles/org.openhab.binding.nuki/pom.xml b/bundles/org.openhab.binding.nuki/pom.xml index 7e2a1098c65ae..0d8889999a767 100644 --- a/bundles/org.openhab.binding.nuki/pom.xml +++ b/bundles/org.openhab.binding.nuki/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nuki diff --git a/bundles/org.openhab.binding.nuvo/pom.xml b/bundles/org.openhab.binding.nuvo/pom.xml index 560683bc2a52f..bbfd538dec765 100644 --- a/bundles/org.openhab.binding.nuvo/pom.xml +++ b/bundles/org.openhab.binding.nuvo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nuvo diff --git a/bundles/org.openhab.binding.nzwateralerts/pom.xml b/bundles/org.openhab.binding.nzwateralerts/pom.xml index 56c1f52402c96..d63355349e12a 100644 --- a/bundles/org.openhab.binding.nzwateralerts/pom.xml +++ b/bundles/org.openhab.binding.nzwateralerts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.nzwateralerts diff --git a/bundles/org.openhab.binding.oceanic/pom.xml b/bundles/org.openhab.binding.oceanic/pom.xml index 692843420bc44..caa4a63de4731 100644 --- a/bundles/org.openhab.binding.oceanic/pom.xml +++ b/bundles/org.openhab.binding.oceanic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.oceanic diff --git a/bundles/org.openhab.binding.ojelectronics/pom.xml b/bundles/org.openhab.binding.ojelectronics/pom.xml index d300782606d26..dd785cdd0b5b4 100644 --- a/bundles/org.openhab.binding.ojelectronics/pom.xml +++ b/bundles/org.openhab.binding.ojelectronics/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ojelectronics diff --git a/bundles/org.openhab.binding.omnikinverter/pom.xml b/bundles/org.openhab.binding.omnikinverter/pom.xml index 2630c7c5dd482..9fee1230915e6 100644 --- a/bundles/org.openhab.binding.omnikinverter/pom.xml +++ b/bundles/org.openhab.binding.omnikinverter/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.omnikinverter diff --git a/bundles/org.openhab.binding.omnilink/pom.xml b/bundles/org.openhab.binding.omnilink/pom.xml index c008ef1870b44..07f8bc76c5ff1 100644 --- a/bundles/org.openhab.binding.omnilink/pom.xml +++ b/bundles/org.openhab.binding.omnilink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.omnilink diff --git a/bundles/org.openhab.binding.onebusaway/pom.xml b/bundles/org.openhab.binding.onebusaway/pom.xml index 8dc227de1f3fb..2a101cbe25b85 100644 --- a/bundles/org.openhab.binding.onebusaway/pom.xml +++ b/bundles/org.openhab.binding.onebusaway/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.onebusaway diff --git a/bundles/org.openhab.binding.onewire/pom.xml b/bundles/org.openhab.binding.onewire/pom.xml index 822468290d1c2..5cff8d88168be 100644 --- a/bundles/org.openhab.binding.onewire/pom.xml +++ b/bundles/org.openhab.binding.onewire/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.onewire diff --git a/bundles/org.openhab.binding.onewiregpio/pom.xml b/bundles/org.openhab.binding.onewiregpio/pom.xml index 564e62d83b6cf..f9e5dcd6a4f9d 100644 --- a/bundles/org.openhab.binding.onewiregpio/pom.xml +++ b/bundles/org.openhab.binding.onewiregpio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.onewiregpio diff --git a/bundles/org.openhab.binding.onkyo/pom.xml b/bundles/org.openhab.binding.onkyo/pom.xml index d89b1a274adda..cab8acf51285e 100644 --- a/bundles/org.openhab.binding.onkyo/pom.xml +++ b/bundles/org.openhab.binding.onkyo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.onkyo diff --git a/bundles/org.openhab.binding.opengarage/pom.xml b/bundles/org.openhab.binding.opengarage/pom.xml index a2c416bcf2a8b..9a9c043fc0327 100644 --- a/bundles/org.openhab.binding.opengarage/pom.xml +++ b/bundles/org.openhab.binding.opengarage/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.opengarage diff --git a/bundles/org.openhab.binding.opensprinkler/pom.xml b/bundles/org.openhab.binding.opensprinkler/pom.xml index 486f74bdd357d..e7195f12e7050 100644 --- a/bundles/org.openhab.binding.opensprinkler/pom.xml +++ b/bundles/org.openhab.binding.opensprinkler/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.opensprinkler diff --git a/bundles/org.openhab.binding.openthermgateway/pom.xml b/bundles/org.openhab.binding.openthermgateway/pom.xml index 91f046c86b65c..840a5c44f110a 100644 --- a/bundles/org.openhab.binding.openthermgateway/pom.xml +++ b/bundles/org.openhab.binding.openthermgateway/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.openthermgateway diff --git a/bundles/org.openhab.binding.openuv/pom.xml b/bundles/org.openhab.binding.openuv/pom.xml index 970b06f576e76..53997609530cb 100644 --- a/bundles/org.openhab.binding.openuv/pom.xml +++ b/bundles/org.openhab.binding.openuv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.openuv diff --git a/bundles/org.openhab.binding.openweathermap/pom.xml b/bundles/org.openhab.binding.openweathermap/pom.xml index 88e3436af185c..bbcfa6c26a2a7 100644 --- a/bundles/org.openhab.binding.openweathermap/pom.xml +++ b/bundles/org.openhab.binding.openweathermap/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.openweathermap diff --git a/bundles/org.openhab.binding.openwebnet/pom.xml b/bundles/org.openhab.binding.openwebnet/pom.xml index a6e25ffac9f50..ba3eef2e40b27 100644 --- a/bundles/org.openhab.binding.openwebnet/pom.xml +++ b/bundles/org.openhab.binding.openwebnet/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.openwebnet diff --git a/bundles/org.openhab.binding.oppo/pom.xml b/bundles/org.openhab.binding.oppo/pom.xml index fd33f5df60e0e..32d57c28478db 100644 --- a/bundles/org.openhab.binding.oppo/pom.xml +++ b/bundles/org.openhab.binding.oppo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.oppo diff --git a/bundles/org.openhab.binding.orbitbhyve/pom.xml b/bundles/org.openhab.binding.orbitbhyve/pom.xml index 332ae978100e3..1264a126afe87 100644 --- a/bundles/org.openhab.binding.orbitbhyve/pom.xml +++ b/bundles/org.openhab.binding.orbitbhyve/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.orbitbhyve diff --git a/bundles/org.openhab.binding.orvibo/pom.xml b/bundles/org.openhab.binding.orvibo/pom.xml index 80fb68d915fa9..2bf22ac63eeb4 100644 --- a/bundles/org.openhab.binding.orvibo/pom.xml +++ b/bundles/org.openhab.binding.orvibo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.orvibo diff --git a/bundles/org.openhab.binding.paradoxalarm/pom.xml b/bundles/org.openhab.binding.paradoxalarm/pom.xml index b3b21cae9ef67..0987ccb0b03d0 100644 --- a/bundles/org.openhab.binding.paradoxalarm/pom.xml +++ b/bundles/org.openhab.binding.paradoxalarm/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.reactor.bundles org.openhab.addons.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.paradoxalarm diff --git a/bundles/org.openhab.binding.pentair/pom.xml b/bundles/org.openhab.binding.pentair/pom.xml index eb28b57934800..e30efa8cba7eb 100644 --- a/bundles/org.openhab.binding.pentair/pom.xml +++ b/bundles/org.openhab.binding.pentair/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pentair diff --git a/bundles/org.openhab.binding.phc/pom.xml b/bundles/org.openhab.binding.phc/pom.xml index d94e9610d19bd..2da732eb48dcf 100644 --- a/bundles/org.openhab.binding.phc/pom.xml +++ b/bundles/org.openhab.binding.phc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.phc diff --git a/bundles/org.openhab.binding.pilight/pom.xml b/bundles/org.openhab.binding.pilight/pom.xml index f35d599a1c62d..f53b23c5d5cf4 100644 --- a/bundles/org.openhab.binding.pilight/pom.xml +++ b/bundles/org.openhab.binding.pilight/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pilight diff --git a/bundles/org.openhab.binding.pioneeravr/pom.xml b/bundles/org.openhab.binding.pioneeravr/pom.xml index 2035ba89f3fb9..4e02be79c5dea 100644 --- a/bundles/org.openhab.binding.pioneeravr/pom.xml +++ b/bundles/org.openhab.binding.pioneeravr/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pioneeravr diff --git a/bundles/org.openhab.binding.pixometer/pom.xml b/bundles/org.openhab.binding.pixometer/pom.xml index 1b7c5d8b7b65c..659370e8beb4a 100644 --- a/bundles/org.openhab.binding.pixometer/pom.xml +++ b/bundles/org.openhab.binding.pixometer/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pixometer diff --git a/bundles/org.openhab.binding.pjlinkdevice/pom.xml b/bundles/org.openhab.binding.pjlinkdevice/pom.xml index e79ad890a524f..873728617aff3 100644 --- a/bundles/org.openhab.binding.pjlinkdevice/pom.xml +++ b/bundles/org.openhab.binding.pjlinkdevice/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pjlinkdevice diff --git a/bundles/org.openhab.binding.playstation/pom.xml b/bundles/org.openhab.binding.playstation/pom.xml index 37294d22ecc19..9f538b6a5fd50 100644 --- a/bundles/org.openhab.binding.playstation/pom.xml +++ b/bundles/org.openhab.binding.playstation/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.playstation diff --git a/bundles/org.openhab.binding.plclogo/pom.xml b/bundles/org.openhab.binding.plclogo/pom.xml index 36f129a876cc4..88725f1dbfc87 100644 --- a/bundles/org.openhab.binding.plclogo/pom.xml +++ b/bundles/org.openhab.binding.plclogo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.plclogo diff --git a/bundles/org.openhab.binding.plugwise/pom.xml b/bundles/org.openhab.binding.plugwise/pom.xml index 0fada30c81ccd..afdd3a6077ea8 100644 --- a/bundles/org.openhab.binding.plugwise/pom.xml +++ b/bundles/org.openhab.binding.plugwise/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.plugwise diff --git a/bundles/org.openhab.binding.plugwiseha/pom.xml b/bundles/org.openhab.binding.plugwiseha/pom.xml index e31deffd5fdb1..5f5cb60d48387 100644 --- a/bundles/org.openhab.binding.plugwiseha/pom.xml +++ b/bundles/org.openhab.binding.plugwiseha/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.plugwiseha diff --git a/bundles/org.openhab.binding.powermax/pom.xml b/bundles/org.openhab.binding.powermax/pom.xml index c0800a411df0a..d58bcfa5ed7e5 100644 --- a/bundles/org.openhab.binding.powermax/pom.xml +++ b/bundles/org.openhab.binding.powermax/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.powermax diff --git a/bundles/org.openhab.binding.proteusecometer/pom.xml b/bundles/org.openhab.binding.proteusecometer/pom.xml index 73dfaf9b9caeb..4542085ba1bfc 100644 --- a/bundles/org.openhab.binding.proteusecometer/pom.xml +++ b/bundles/org.openhab.binding.proteusecometer/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.proteusecometer diff --git a/bundles/org.openhab.binding.pulseaudio/pom.xml b/bundles/org.openhab.binding.pulseaudio/pom.xml index d0ccde77cd990..c095c369aa377 100644 --- a/bundles/org.openhab.binding.pulseaudio/pom.xml +++ b/bundles/org.openhab.binding.pulseaudio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pulseaudio diff --git a/bundles/org.openhab.binding.pushbullet/pom.xml b/bundles/org.openhab.binding.pushbullet/pom.xml index 6dfd8f1e39475..45c26f7e1fb92 100644 --- a/bundles/org.openhab.binding.pushbullet/pom.xml +++ b/bundles/org.openhab.binding.pushbullet/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pushbullet diff --git a/bundles/org.openhab.binding.pushover/pom.xml b/bundles/org.openhab.binding.pushover/pom.xml index d4875af17449d..8616ab6252647 100644 --- a/bundles/org.openhab.binding.pushover/pom.xml +++ b/bundles/org.openhab.binding.pushover/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pushover diff --git a/bundles/org.openhab.binding.pushsafer/pom.xml b/bundles/org.openhab.binding.pushsafer/pom.xml index 971114e1d05f3..e5a3d510a0994 100644 --- a/bundles/org.openhab.binding.pushsafer/pom.xml +++ b/bundles/org.openhab.binding.pushsafer/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.pushsafer diff --git a/bundles/org.openhab.binding.qbus/pom.xml b/bundles/org.openhab.binding.qbus/pom.xml index 2fbdb419fed03..8e7b1392c592a 100644 --- a/bundles/org.openhab.binding.qbus/pom.xml +++ b/bundles/org.openhab.binding.qbus/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.qbus diff --git a/bundles/org.openhab.binding.radiothermostat/pom.xml b/bundles/org.openhab.binding.radiothermostat/pom.xml index c7f85b8d83cb4..451104f2e9e6c 100644 --- a/bundles/org.openhab.binding.radiothermostat/pom.xml +++ b/bundles/org.openhab.binding.radiothermostat/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.radiothermostat diff --git a/bundles/org.openhab.binding.regoheatpump/pom.xml b/bundles/org.openhab.binding.regoheatpump/pom.xml index df4e4f05a0716..6175abd63e72d 100644 --- a/bundles/org.openhab.binding.regoheatpump/pom.xml +++ b/bundles/org.openhab.binding.regoheatpump/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.regoheatpump diff --git a/bundles/org.openhab.binding.remoteopenhab/pom.xml b/bundles/org.openhab.binding.remoteopenhab/pom.xml index 4c9b362008fe2..729b133f91ac8 100644 --- a/bundles/org.openhab.binding.remoteopenhab/pom.xml +++ b/bundles/org.openhab.binding.remoteopenhab/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.remoteopenhab diff --git a/bundles/org.openhab.binding.renault/pom.xml b/bundles/org.openhab.binding.renault/pom.xml index bbd7abe02f806..c66870f92177e 100644 --- a/bundles/org.openhab.binding.renault/pom.xml +++ b/bundles/org.openhab.binding.renault/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.renault diff --git a/bundles/org.openhab.binding.resol/pom.xml b/bundles/org.openhab.binding.resol/pom.xml index 7a9d421d14807..ea381f061c5dd 100644 --- a/bundles/org.openhab.binding.resol/pom.xml +++ b/bundles/org.openhab.binding.resol/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.resol diff --git a/bundles/org.openhab.binding.revogi/pom.xml b/bundles/org.openhab.binding.revogi/pom.xml index 36854eee2e008..87bdbb84bdd64 100644 --- a/bundles/org.openhab.binding.revogi/pom.xml +++ b/bundles/org.openhab.binding.revogi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.revogi diff --git a/bundles/org.openhab.binding.rfxcom/pom.xml b/bundles/org.openhab.binding.rfxcom/pom.xml index 9aff790d4d6e5..6b432367426dd 100644 --- a/bundles/org.openhab.binding.rfxcom/pom.xml +++ b/bundles/org.openhab.binding.rfxcom/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.rfxcom diff --git a/bundles/org.openhab.binding.rme/pom.xml b/bundles/org.openhab.binding.rme/pom.xml index d3d9c6d612fd7..ca91ca9b380cb 100644 --- a/bundles/org.openhab.binding.rme/pom.xml +++ b/bundles/org.openhab.binding.rme/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.rme diff --git a/bundles/org.openhab.binding.robonect/pom.xml b/bundles/org.openhab.binding.robonect/pom.xml index ba588f4e616f9..fe74cad9ad819 100644 --- a/bundles/org.openhab.binding.robonect/pom.xml +++ b/bundles/org.openhab.binding.robonect/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.robonect diff --git a/bundles/org.openhab.binding.roku/pom.xml b/bundles/org.openhab.binding.roku/pom.xml index e99f520414667..643cd69c4de0b 100644 --- a/bundles/org.openhab.binding.roku/pom.xml +++ b/bundles/org.openhab.binding.roku/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.roku diff --git a/bundles/org.openhab.binding.rotel/pom.xml b/bundles/org.openhab.binding.rotel/pom.xml index 5732953242758..6179345758a34 100644 --- a/bundles/org.openhab.binding.rotel/pom.xml +++ b/bundles/org.openhab.binding.rotel/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.rotel diff --git a/bundles/org.openhab.binding.russound/pom.xml b/bundles/org.openhab.binding.russound/pom.xml index d55d54a0d3fc5..5bd5d3d289fb8 100644 --- a/bundles/org.openhab.binding.russound/pom.xml +++ b/bundles/org.openhab.binding.russound/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.russound diff --git a/bundles/org.openhab.binding.sagercaster/pom.xml b/bundles/org.openhab.binding.sagercaster/pom.xml index a8f28deaff110..1bf5db71ef195 100644 --- a/bundles/org.openhab.binding.sagercaster/pom.xml +++ b/bundles/org.openhab.binding.sagercaster/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sagercaster diff --git a/bundles/org.openhab.binding.samsungtv/pom.xml b/bundles/org.openhab.binding.samsungtv/pom.xml index e006f17b6a1cf..c41f88a354119 100644 --- a/bundles/org.openhab.binding.samsungtv/pom.xml +++ b/bundles/org.openhab.binding.samsungtv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.samsungtv diff --git a/bundles/org.openhab.binding.satel/pom.xml b/bundles/org.openhab.binding.satel/pom.xml index 798890a0c8b3c..90b0f06e382cd 100644 --- a/bundles/org.openhab.binding.satel/pom.xml +++ b/bundles/org.openhab.binding.satel/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.satel diff --git a/bundles/org.openhab.binding.semsportal/pom.xml b/bundles/org.openhab.binding.semsportal/pom.xml index 03bb167456573..ef90e12010b70 100644 --- a/bundles/org.openhab.binding.semsportal/pom.xml +++ b/bundles/org.openhab.binding.semsportal/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.semsportal diff --git a/bundles/org.openhab.binding.senechome/pom.xml b/bundles/org.openhab.binding.senechome/pom.xml index 451e8f9b995f1..cfb6dc9a98149 100644 --- a/bundles/org.openhab.binding.senechome/pom.xml +++ b/bundles/org.openhab.binding.senechome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.senechome diff --git a/bundles/org.openhab.binding.seneye/pom.xml b/bundles/org.openhab.binding.seneye/pom.xml index da7d54dfcccaa..e8110882d8936 100644 --- a/bundles/org.openhab.binding.seneye/pom.xml +++ b/bundles/org.openhab.binding.seneye/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.seneye diff --git a/bundles/org.openhab.binding.sensebox/pom.xml b/bundles/org.openhab.binding.sensebox/pom.xml index 7c5036bbad9b4..07993e7f6abb0 100644 --- a/bundles/org.openhab.binding.sensebox/pom.xml +++ b/bundles/org.openhab.binding.sensebox/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sensebox diff --git a/bundles/org.openhab.binding.sensibo/pom.xml b/bundles/org.openhab.binding.sensibo/pom.xml index 6a18eb7e00616..f93621488e950 100644 --- a/bundles/org.openhab.binding.sensibo/pom.xml +++ b/bundles/org.openhab.binding.sensibo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sensibo diff --git a/bundles/org.openhab.binding.serial/pom.xml b/bundles/org.openhab.binding.serial/pom.xml index dc03276790eb5..0baf1d2753a53 100644 --- a/bundles/org.openhab.binding.serial/pom.xml +++ b/bundles/org.openhab.binding.serial/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.serial diff --git a/bundles/org.openhab.binding.serialbutton/pom.xml b/bundles/org.openhab.binding.serialbutton/pom.xml index ebce69c71dfb5..e9c68e4ff1a58 100644 --- a/bundles/org.openhab.binding.serialbutton/pom.xml +++ b/bundles/org.openhab.binding.serialbutton/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.serialbutton diff --git a/bundles/org.openhab.binding.shelly/pom.xml b/bundles/org.openhab.binding.shelly/pom.xml index 5547d2efeab16..84279b73cb912 100644 --- a/bundles/org.openhab.binding.shelly/pom.xml +++ b/bundles/org.openhab.binding.shelly/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT diff --git a/bundles/org.openhab.binding.siemensrds/pom.xml b/bundles/org.openhab.binding.siemensrds/pom.xml index 0c36c1632f79f..f65aa09add5f8 100644 --- a/bundles/org.openhab.binding.siemensrds/pom.xml +++ b/bundles/org.openhab.binding.siemensrds/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.siemensrds diff --git a/bundles/org.openhab.binding.silvercrestwifisocket/pom.xml b/bundles/org.openhab.binding.silvercrestwifisocket/pom.xml index 91b2fcbf860aa..2a4dc20f7581b 100644 --- a/bundles/org.openhab.binding.silvercrestwifisocket/pom.xml +++ b/bundles/org.openhab.binding.silvercrestwifisocket/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.silvercrestwifisocket diff --git a/bundles/org.openhab.binding.sinope/pom.xml b/bundles/org.openhab.binding.sinope/pom.xml index faca1c889b107..d0bb76d3589a7 100644 --- a/bundles/org.openhab.binding.sinope/pom.xml +++ b/bundles/org.openhab.binding.sinope/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sinope diff --git a/bundles/org.openhab.binding.sleepiq/pom.xml b/bundles/org.openhab.binding.sleepiq/pom.xml index ecf607a943557..0aab2b8e5bbf1 100644 --- a/bundles/org.openhab.binding.sleepiq/pom.xml +++ b/bundles/org.openhab.binding.sleepiq/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sleepiq diff --git a/bundles/org.openhab.binding.smaenergymeter/pom.xml b/bundles/org.openhab.binding.smaenergymeter/pom.xml index 30a40097ad63d..6e57fca00292e 100644 --- a/bundles/org.openhab.binding.smaenergymeter/pom.xml +++ b/bundles/org.openhab.binding.smaenergymeter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.smaenergymeter diff --git a/bundles/org.openhab.binding.smartmeter/pom.xml b/bundles/org.openhab.binding.smartmeter/pom.xml index b339c8de59722..4dd7bbee51250 100644 --- a/bundles/org.openhab.binding.smartmeter/pom.xml +++ b/bundles/org.openhab.binding.smartmeter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.smartmeter diff --git a/bundles/org.openhab.binding.smartthings/pom.xml b/bundles/org.openhab.binding.smartthings/pom.xml index 7f716b92ac524..b632dc0ca51fd 100644 --- a/bundles/org.openhab.binding.smartthings/pom.xml +++ b/bundles/org.openhab.binding.smartthings/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.smartthings diff --git a/bundles/org.openhab.binding.smhi/pom.xml b/bundles/org.openhab.binding.smhi/pom.xml index 36d077e12ca11..ef1ba9503ca8b 100644 --- a/bundles/org.openhab.binding.smhi/pom.xml +++ b/bundles/org.openhab.binding.smhi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.smhi diff --git a/bundles/org.openhab.binding.sncf/pom.xml b/bundles/org.openhab.binding.sncf/pom.xml index aefe5411519fe..225b751cf35aa 100644 --- a/bundles/org.openhab.binding.sncf/pom.xml +++ b/bundles/org.openhab.binding.sncf/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sncf diff --git a/bundles/org.openhab.binding.snmp/pom.xml b/bundles/org.openhab.binding.snmp/pom.xml index d859b4b24f1d2..29acda5366771 100644 --- a/bundles/org.openhab.binding.snmp/pom.xml +++ b/bundles/org.openhab.binding.snmp/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.snmp diff --git a/bundles/org.openhab.binding.solaredge/pom.xml b/bundles/org.openhab.binding.solaredge/pom.xml index 02f3464293c5b..2d4ee418cc046 100644 --- a/bundles/org.openhab.binding.solaredge/pom.xml +++ b/bundles/org.openhab.binding.solaredge/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.solaredge diff --git a/bundles/org.openhab.binding.solarlog/pom.xml b/bundles/org.openhab.binding.solarlog/pom.xml index 5e12c16d78e61..5ddd73711bfb0 100644 --- a/bundles/org.openhab.binding.solarlog/pom.xml +++ b/bundles/org.openhab.binding.solarlog/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.solarlog diff --git a/bundles/org.openhab.binding.solarwatt/pom.xml b/bundles/org.openhab.binding.solarwatt/pom.xml index f21dcf74c5087..97f08a2ac4175 100644 --- a/bundles/org.openhab.binding.solarwatt/pom.xml +++ b/bundles/org.openhab.binding.solarwatt/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.solarwatt diff --git a/bundles/org.openhab.binding.somfymylink/pom.xml b/bundles/org.openhab.binding.somfymylink/pom.xml index 20bdd1ec9e72e..b0f5db09a679c 100644 --- a/bundles/org.openhab.binding.somfymylink/pom.xml +++ b/bundles/org.openhab.binding.somfymylink/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.somfymylink diff --git a/bundles/org.openhab.binding.somfytahoma/pom.xml b/bundles/org.openhab.binding.somfytahoma/pom.xml index a950b5d77b310..89f9602dd376e 100644 --- a/bundles/org.openhab.binding.somfytahoma/pom.xml +++ b/bundles/org.openhab.binding.somfytahoma/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.somfytahoma diff --git a/bundles/org.openhab.binding.sonos/pom.xml b/bundles/org.openhab.binding.sonos/pom.xml index 237f8ce63b8a9..e808308a5c194 100644 --- a/bundles/org.openhab.binding.sonos/pom.xml +++ b/bundles/org.openhab.binding.sonos/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sonos diff --git a/bundles/org.openhab.binding.sonyaudio/pom.xml b/bundles/org.openhab.binding.sonyaudio/pom.xml index 457df5038c58a..af94406e77209 100644 --- a/bundles/org.openhab.binding.sonyaudio/pom.xml +++ b/bundles/org.openhab.binding.sonyaudio/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sonyaudio diff --git a/bundles/org.openhab.binding.sonyprojector/pom.xml b/bundles/org.openhab.binding.sonyprojector/pom.xml index 46942fe6b8449..b814d542d8a2e 100644 --- a/bundles/org.openhab.binding.sonyprojector/pom.xml +++ b/bundles/org.openhab.binding.sonyprojector/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.sonyprojector diff --git a/bundles/org.openhab.binding.souliss/pom.xml b/bundles/org.openhab.binding.souliss/pom.xml index 621e9aac091bc..989ec8caa33d6 100644 --- a/bundles/org.openhab.binding.souliss/pom.xml +++ b/bundles/org.openhab.binding.souliss/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.souliss diff --git a/bundles/org.openhab.binding.spotify/pom.xml b/bundles/org.openhab.binding.spotify/pom.xml index c7aa4b33a86b6..adffec8961bb4 100644 --- a/bundles/org.openhab.binding.spotify/pom.xml +++ b/bundles/org.openhab.binding.spotify/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.spotify diff --git a/bundles/org.openhab.binding.squeezebox/pom.xml b/bundles/org.openhab.binding.squeezebox/pom.xml index 3b53db3a2ab57..56e3f382e9d18 100644 --- a/bundles/org.openhab.binding.squeezebox/pom.xml +++ b/bundles/org.openhab.binding.squeezebox/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.squeezebox diff --git a/bundles/org.openhab.binding.surepetcare/pom.xml b/bundles/org.openhab.binding.surepetcare/pom.xml index 57f5cae44fb59..0856f01f2d9f4 100644 --- a/bundles/org.openhab.binding.surepetcare/pom.xml +++ b/bundles/org.openhab.binding.surepetcare/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.surepetcare diff --git a/bundles/org.openhab.binding.synopanalyzer/pom.xml b/bundles/org.openhab.binding.synopanalyzer/pom.xml index fa001b3d32383..7c45074a43c99 100644 --- a/bundles/org.openhab.binding.synopanalyzer/pom.xml +++ b/bundles/org.openhab.binding.synopanalyzer/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.synopanalyzer diff --git a/bundles/org.openhab.binding.systeminfo/pom.xml b/bundles/org.openhab.binding.systeminfo/pom.xml index a9c0fffde0577..277a260e7c8cd 100644 --- a/bundles/org.openhab.binding.systeminfo/pom.xml +++ b/bundles/org.openhab.binding.systeminfo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.systeminfo diff --git a/bundles/org.openhab.binding.tacmi/pom.xml b/bundles/org.openhab.binding.tacmi/pom.xml index f1369476aba07..d490e51feaed9 100644 --- a/bundles/org.openhab.binding.tacmi/pom.xml +++ b/bundles/org.openhab.binding.tacmi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tacmi diff --git a/bundles/org.openhab.binding.tado/pom.xml b/bundles/org.openhab.binding.tado/pom.xml index eced645382a35..44e40523b154f 100644 --- a/bundles/org.openhab.binding.tado/pom.xml +++ b/bundles/org.openhab.binding.tado/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tado diff --git a/bundles/org.openhab.binding.tankerkoenig/pom.xml b/bundles/org.openhab.binding.tankerkoenig/pom.xml index d40edb90527f0..40780d0757b0f 100644 --- a/bundles/org.openhab.binding.tankerkoenig/pom.xml +++ b/bundles/org.openhab.binding.tankerkoenig/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tankerkoenig diff --git a/bundles/org.openhab.binding.tapocontrol/pom.xml b/bundles/org.openhab.binding.tapocontrol/pom.xml index 2e71e41e4d675..301d72e77f92f 100644 --- a/bundles/org.openhab.binding.tapocontrol/pom.xml +++ b/bundles/org.openhab.binding.tapocontrol/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tapocontrol diff --git a/bundles/org.openhab.binding.telegram/pom.xml b/bundles/org.openhab.binding.telegram/pom.xml index 41ebbc84ec277..448c23ea59786 100644 --- a/bundles/org.openhab.binding.telegram/pom.xml +++ b/bundles/org.openhab.binding.telegram/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.telegram diff --git a/bundles/org.openhab.binding.teleinfo/pom.xml b/bundles/org.openhab.binding.teleinfo/pom.xml index 1e04fc1219c48..c5cfb13c400f2 100644 --- a/bundles/org.openhab.binding.teleinfo/pom.xml +++ b/bundles/org.openhab.binding.teleinfo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.teleinfo diff --git a/bundles/org.openhab.binding.tellstick/pom.xml b/bundles/org.openhab.binding.tellstick/pom.xml index 6c12f20c3190c..83a129bd592cb 100644 --- a/bundles/org.openhab.binding.tellstick/pom.xml +++ b/bundles/org.openhab.binding.tellstick/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tellstick diff --git a/bundles/org.openhab.binding.tesla/pom.xml b/bundles/org.openhab.binding.tesla/pom.xml index e4e27ffe3d579..039023a774f18 100644 --- a/bundles/org.openhab.binding.tesla/pom.xml +++ b/bundles/org.openhab.binding.tesla/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tesla diff --git a/bundles/org.openhab.binding.tibber/pom.xml b/bundles/org.openhab.binding.tibber/pom.xml index 8b4d2acde81d8..d370abc144227 100644 --- a/bundles/org.openhab.binding.tibber/pom.xml +++ b/bundles/org.openhab.binding.tibber/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tibber diff --git a/bundles/org.openhab.binding.tivo/pom.xml b/bundles/org.openhab.binding.tivo/pom.xml index cd15d436580ed..57ebc6dfb9e30 100644 --- a/bundles/org.openhab.binding.tivo/pom.xml +++ b/bundles/org.openhab.binding.tivo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tivo diff --git a/bundles/org.openhab.binding.touchwand/pom.xml b/bundles/org.openhab.binding.touchwand/pom.xml index cc28a10087533..3aa6fe25bf5a6 100644 --- a/bundles/org.openhab.binding.touchwand/pom.xml +++ b/bundles/org.openhab.binding.touchwand/pom.xml @@ -1,12 +1,10 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.touchwand diff --git a/bundles/org.openhab.binding.tplinksmarthome/pom.xml b/bundles/org.openhab.binding.tplinksmarthome/pom.xml index 132a5ff4fcd97..33deb3e7d979e 100644 --- a/bundles/org.openhab.binding.tplinksmarthome/pom.xml +++ b/bundles/org.openhab.binding.tplinksmarthome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tplinksmarthome diff --git a/bundles/org.openhab.binding.tr064/pom.xml b/bundles/org.openhab.binding.tr064/pom.xml index 558aaea14b00f..c71ec17694b58 100644 --- a/bundles/org.openhab.binding.tr064/pom.xml +++ b/bundles/org.openhab.binding.tr064/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tr064 diff --git a/bundles/org.openhab.binding.tradfri/pom.xml b/bundles/org.openhab.binding.tradfri/pom.xml index 82c203d291922..8a1f4c9420667 100644 --- a/bundles/org.openhab.binding.tradfri/pom.xml +++ b/bundles/org.openhab.binding.tradfri/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.tradfri diff --git a/bundles/org.openhab.binding.twitter/pom.xml b/bundles/org.openhab.binding.twitter/pom.xml index 03450d9a75046..e6364115b852a 100644 --- a/bundles/org.openhab.binding.twitter/pom.xml +++ b/bundles/org.openhab.binding.twitter/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.twitter diff --git a/bundles/org.openhab.binding.unifi/pom.xml b/bundles/org.openhab.binding.unifi/pom.xml index e054e5bec60dc..489f234bcdb6c 100644 --- a/bundles/org.openhab.binding.unifi/pom.xml +++ b/bundles/org.openhab.binding.unifi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.unifi diff --git a/bundles/org.openhab.binding.unifiedremote/pom.xml b/bundles/org.openhab.binding.unifiedremote/pom.xml index d9ea3fc8c4b5d..fa4a6c2f5e318 100644 --- a/bundles/org.openhab.binding.unifiedremote/pom.xml +++ b/bundles/org.openhab.binding.unifiedremote/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.unifiedremote diff --git a/bundles/org.openhab.binding.upb/pom.xml b/bundles/org.openhab.binding.upb/pom.xml index bfb1cf115d7bd..3817d79ae755e 100644 --- a/bundles/org.openhab.binding.upb/pom.xml +++ b/bundles/org.openhab.binding.upb/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.upb diff --git a/bundles/org.openhab.binding.upnpcontrol/pom.xml b/bundles/org.openhab.binding.upnpcontrol/pom.xml index d1320fc3f1000..4c95c02fe746a 100644 --- a/bundles/org.openhab.binding.upnpcontrol/pom.xml +++ b/bundles/org.openhab.binding.upnpcontrol/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.upnpcontrol diff --git a/bundles/org.openhab.binding.urtsi/pom.xml b/bundles/org.openhab.binding.urtsi/pom.xml index 4b7ba73d2ff41..93eb9bfa382ee 100644 --- a/bundles/org.openhab.binding.urtsi/pom.xml +++ b/bundles/org.openhab.binding.urtsi/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.urtsi diff --git a/bundles/org.openhab.binding.valloxmv/pom.xml b/bundles/org.openhab.binding.valloxmv/pom.xml index 5354aa696bef5..cfa00313fbe38 100644 --- a/bundles/org.openhab.binding.valloxmv/pom.xml +++ b/bundles/org.openhab.binding.valloxmv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.valloxmv diff --git a/bundles/org.openhab.binding.vdr/pom.xml b/bundles/org.openhab.binding.vdr/pom.xml index 193a6fe207cbc..93cadb30c81ba 100644 --- a/bundles/org.openhab.binding.vdr/pom.xml +++ b/bundles/org.openhab.binding.vdr/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.vdr diff --git a/bundles/org.openhab.binding.vektiva/pom.xml b/bundles/org.openhab.binding.vektiva/pom.xml index e939790285d26..bd72e02e523dd 100644 --- a/bundles/org.openhab.binding.vektiva/pom.xml +++ b/bundles/org.openhab.binding.vektiva/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.reactor.bundles org.openhab.addons.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.vektiva diff --git a/bundles/org.openhab.binding.velbus/pom.xml b/bundles/org.openhab.binding.velbus/pom.xml index 3419880cb308a..98f68971a7f6c 100644 --- a/bundles/org.openhab.binding.velbus/pom.xml +++ b/bundles/org.openhab.binding.velbus/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.velbus diff --git a/bundles/org.openhab.binding.velux/pom.xml b/bundles/org.openhab.binding.velux/pom.xml index 0157827666a60..6f88d0121f6c2 100644 --- a/bundles/org.openhab.binding.velux/pom.xml +++ b/bundles/org.openhab.binding.velux/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.velux diff --git a/bundles/org.openhab.binding.venstarthermostat/pom.xml b/bundles/org.openhab.binding.venstarthermostat/pom.xml index 8cac390001610..0a1a8e2282e13 100644 --- a/bundles/org.openhab.binding.venstarthermostat/pom.xml +++ b/bundles/org.openhab.binding.venstarthermostat/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.venstarthermostat diff --git a/bundles/org.openhab.binding.ventaair/pom.xml b/bundles/org.openhab.binding.ventaair/pom.xml index bbefb8b7b1d13..dbb4230203796 100644 --- a/bundles/org.openhab.binding.ventaair/pom.xml +++ b/bundles/org.openhab.binding.ventaair/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.ventaair diff --git a/bundles/org.openhab.binding.verisure/pom.xml b/bundles/org.openhab.binding.verisure/pom.xml index 8b11e0093a535..0c8c36bb5d9f6 100644 --- a/bundles/org.openhab.binding.verisure/pom.xml +++ b/bundles/org.openhab.binding.verisure/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.verisure diff --git a/bundles/org.openhab.binding.vigicrues/pom.xml b/bundles/org.openhab.binding.vigicrues/pom.xml index a5ce9b8e0f9d9..bc30b8cf5bb16 100644 --- a/bundles/org.openhab.binding.vigicrues/pom.xml +++ b/bundles/org.openhab.binding.vigicrues/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.vigicrues diff --git a/bundles/org.openhab.binding.vitotronic/pom.xml b/bundles/org.openhab.binding.vitotronic/pom.xml index 2513b84842c11..e0c691bf859c8 100644 --- a/bundles/org.openhab.binding.vitotronic/pom.xml +++ b/bundles/org.openhab.binding.vitotronic/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.vitotronic diff --git a/bundles/org.openhab.binding.volvooncall/pom.xml b/bundles/org.openhab.binding.volvooncall/pom.xml index fc37b234c19fe..4a7b5ea23fe15 100644 --- a/bundles/org.openhab.binding.volvooncall/pom.xml +++ b/bundles/org.openhab.binding.volvooncall/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.volvooncall diff --git a/bundles/org.openhab.binding.warmup/pom.xml b/bundles/org.openhab.binding.warmup/pom.xml index ad71de8ba81e1..960dd52070e58 100644 --- a/bundles/org.openhab.binding.warmup/pom.xml +++ b/bundles/org.openhab.binding.warmup/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.warmup diff --git a/bundles/org.openhab.binding.weathercompany/pom.xml b/bundles/org.openhab.binding.weathercompany/pom.xml index 104a2e8c78201..5310856cdc6d2 100644 --- a/bundles/org.openhab.binding.weathercompany/pom.xml +++ b/bundles/org.openhab.binding.weathercompany/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.weathercompany diff --git a/bundles/org.openhab.binding.weatherunderground/pom.xml b/bundles/org.openhab.binding.weatherunderground/pom.xml index a150fc770386f..59b3aa37cf25f 100644 --- a/bundles/org.openhab.binding.weatherunderground/pom.xml +++ b/bundles/org.openhab.binding.weatherunderground/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.weatherunderground diff --git a/bundles/org.openhab.binding.webthing/pom.xml b/bundles/org.openhab.binding.webthing/pom.xml index 1448c43c5896f..6f2bdd90c73d6 100644 --- a/bundles/org.openhab.binding.webthing/pom.xml +++ b/bundles/org.openhab.binding.webthing/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.webthing diff --git a/bundles/org.openhab.binding.wemo/pom.xml b/bundles/org.openhab.binding.wemo/pom.xml index 7fad9a20cd21d..69a13707144ec 100644 --- a/bundles/org.openhab.binding.wemo/pom.xml +++ b/bundles/org.openhab.binding.wemo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.wemo diff --git a/bundles/org.openhab.binding.wifiled/pom.xml b/bundles/org.openhab.binding.wifiled/pom.xml index 713074f07941c..474b8537e8f3a 100644 --- a/bundles/org.openhab.binding.wifiled/pom.xml +++ b/bundles/org.openhab.binding.wifiled/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.wifiled diff --git a/bundles/org.openhab.binding.windcentrale/pom.xml b/bundles/org.openhab.binding.windcentrale/pom.xml index 2f83fc5929b71..09379dfc32322 100644 --- a/bundles/org.openhab.binding.windcentrale/pom.xml +++ b/bundles/org.openhab.binding.windcentrale/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.windcentrale diff --git a/bundles/org.openhab.binding.wlanthermo/pom.xml b/bundles/org.openhab.binding.wlanthermo/pom.xml index 64e735a5672e8..69e20e4d9628a 100644 --- a/bundles/org.openhab.binding.wlanthermo/pom.xml +++ b/bundles/org.openhab.binding.wlanthermo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.wlanthermo diff --git a/bundles/org.openhab.binding.wled/pom.xml b/bundles/org.openhab.binding.wled/pom.xml index 45e9840f59430..cf1f231840a01 100644 --- a/bundles/org.openhab.binding.wled/pom.xml +++ b/bundles/org.openhab.binding.wled/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.wled diff --git a/bundles/org.openhab.binding.wolfsmartset/pom.xml b/bundles/org.openhab.binding.wolfsmartset/pom.xml index bfaa738634bda..f0e623d695bf1 100644 --- a/bundles/org.openhab.binding.wolfsmartset/pom.xml +++ b/bundles/org.openhab.binding.wolfsmartset/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.wolfsmartset diff --git a/bundles/org.openhab.binding.xmltv/pom.xml b/bundles/org.openhab.binding.xmltv/pom.xml index 0f5c19ca783d9..549707ecf4256 100644 --- a/bundles/org.openhab.binding.xmltv/pom.xml +++ b/bundles/org.openhab.binding.xmltv/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.xmltv diff --git a/bundles/org.openhab.binding.xmppclient/pom.xml b/bundles/org.openhab.binding.xmppclient/pom.xml index bfb83ed484a90..02fc894081624 100644 --- a/bundles/org.openhab.binding.xmppclient/pom.xml +++ b/bundles/org.openhab.binding.xmppclient/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.xmppclient diff --git a/bundles/org.openhab.binding.yamahareceiver/pom.xml b/bundles/org.openhab.binding.yamahareceiver/pom.xml index 0f2ca173bc55e..d3e58cc1931c4 100644 --- a/bundles/org.openhab.binding.yamahareceiver/pom.xml +++ b/bundles/org.openhab.binding.yamahareceiver/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.yamahareceiver diff --git a/bundles/org.openhab.binding.yeelight/pom.xml b/bundles/org.openhab.binding.yeelight/pom.xml index c24854ae230ff..cbc8e9406445b 100644 --- a/bundles/org.openhab.binding.yeelight/pom.xml +++ b/bundles/org.openhab.binding.yeelight/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.yeelight diff --git a/bundles/org.openhab.binding.yioremote/pom.xml b/bundles/org.openhab.binding.yioremote/pom.xml index ea6129e9c09df..8c89d7b7f8972 100644 --- a/bundles/org.openhab.binding.yioremote/pom.xml +++ b/bundles/org.openhab.binding.yioremote/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.yioremote diff --git a/bundles/org.openhab.binding.zoneminder/pom.xml b/bundles/org.openhab.binding.zoneminder/pom.xml index 1b97abb3d87cf..04c7304b5aa62 100644 --- a/bundles/org.openhab.binding.zoneminder/pom.xml +++ b/bundles/org.openhab.binding.zoneminder/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.zoneminder diff --git a/bundles/org.openhab.binding.zway/pom.xml b/bundles/org.openhab.binding.zway/pom.xml index 2d078231c67c3..2f5a253d91fbc 100644 --- a/bundles/org.openhab.binding.zway/pom.xml +++ b/bundles/org.openhab.binding.zway/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.binding.zway diff --git a/bundles/org.openhab.io.homekit/pom.xml b/bundles/org.openhab.io.homekit/pom.xml index c153955a82f7b..60bd0456ff121 100644 --- a/bundles/org.openhab.io.homekit/pom.xml +++ b/bundles/org.openhab.io.homekit/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.homekit diff --git a/bundles/org.openhab.io.hueemulation/pom.xml b/bundles/org.openhab.io.hueemulation/pom.xml index 7d4b14beb9f6a..06c0ee344ae89 100644 --- a/bundles/org.openhab.io.hueemulation/pom.xml +++ b/bundles/org.openhab.io.hueemulation/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.hueemulation diff --git a/bundles/org.openhab.io.imperihome/pom.xml b/bundles/org.openhab.io.imperihome/pom.xml index 0164336091be7..351c06dd3861c 100644 --- a/bundles/org.openhab.io.imperihome/pom.xml +++ b/bundles/org.openhab.io.imperihome/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.imperihome diff --git a/bundles/org.openhab.io.metrics/pom.xml b/bundles/org.openhab.io.metrics/pom.xml index 91540d606f72b..8f18d4433ab36 100644 --- a/bundles/org.openhab.io.metrics/pom.xml +++ b/bundles/org.openhab.io.metrics/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.metrics diff --git a/bundles/org.openhab.io.neeo/pom.xml b/bundles/org.openhab.io.neeo/pom.xml index 319e671c3ada1..6dcbeaf75b7e4 100644 --- a/bundles/org.openhab.io.neeo/pom.xml +++ b/bundles/org.openhab.io.neeo/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.neeo diff --git a/bundles/org.openhab.io.openhabcloud/pom.xml b/bundles/org.openhab.io.openhabcloud/pom.xml index 3e742ab68008c..2ba6208297141 100644 --- a/bundles/org.openhab.io.openhabcloud/pom.xml +++ b/bundles/org.openhab.io.openhabcloud/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.io.openhabcloud diff --git a/bundles/org.openhab.persistence.dynamodb/pom.xml b/bundles/org.openhab.persistence.dynamodb/pom.xml index 0820e551e1ba7..40812d144792b 100644 --- a/bundles/org.openhab.persistence.dynamodb/pom.xml +++ b/bundles/org.openhab.persistence.dynamodb/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.dynamodb diff --git a/bundles/org.openhab.persistence.influxdb/pom.xml b/bundles/org.openhab.persistence.influxdb/pom.xml index 3d8e8fe9a48cb..d6b92ae8bbd5c 100644 --- a/bundles/org.openhab.persistence.influxdb/pom.xml +++ b/bundles/org.openhab.persistence.influxdb/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.influxdb diff --git a/bundles/org.openhab.persistence.jdbc/pom.xml b/bundles/org.openhab.persistence.jdbc/pom.xml index 47383a5614b8d..3ff296ca78daf 100644 --- a/bundles/org.openhab.persistence.jdbc/pom.xml +++ b/bundles/org.openhab.persistence.jdbc/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.jdbc diff --git a/bundles/org.openhab.persistence.jpa/pom.xml b/bundles/org.openhab.persistence.jpa/pom.xml index 7b5457bdde68a..1f63b42e03894 100644 --- a/bundles/org.openhab.persistence.jpa/pom.xml +++ b/bundles/org.openhab.persistence.jpa/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.jpa diff --git a/bundles/org.openhab.persistence.mapdb/pom.xml b/bundles/org.openhab.persistence.mapdb/pom.xml index 403aa0998d12d..335cee8c8a3ee 100644 --- a/bundles/org.openhab.persistence.mapdb/pom.xml +++ b/bundles/org.openhab.persistence.mapdb/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.mapdb diff --git a/bundles/org.openhab.persistence.mongodb/pom.xml b/bundles/org.openhab.persistence.mongodb/pom.xml index 2432f26e571ab..535e8fdb93e3a 100644 --- a/bundles/org.openhab.persistence.mongodb/pom.xml +++ b/bundles/org.openhab.persistence.mongodb/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.mongodb diff --git a/bundles/org.openhab.persistence.rrd4j/pom.xml b/bundles/org.openhab.persistence.rrd4j/pom.xml index 74d0b50f6cb55..2c1470c337781 100644 --- a/bundles/org.openhab.persistence.rrd4j/pom.xml +++ b/bundles/org.openhab.persistence.rrd4j/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.persistence.rrd4j diff --git a/bundles/org.openhab.transform.bin2json/pom.xml b/bundles/org.openhab.transform.bin2json/pom.xml index 85ae91689a535..ed24320e6c1d8 100644 --- a/bundles/org.openhab.transform.bin2json/pom.xml +++ b/bundles/org.openhab.transform.bin2json/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.bin2json diff --git a/bundles/org.openhab.transform.exec/pom.xml b/bundles/org.openhab.transform.exec/pom.xml index beaf295a1721d..2faaf498bef50 100644 --- a/bundles/org.openhab.transform.exec/pom.xml +++ b/bundles/org.openhab.transform.exec/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.exec diff --git a/bundles/org.openhab.transform.javascript/pom.xml b/bundles/org.openhab.transform.javascript/pom.xml index 6a8f538bd742e..b83efb5c88570 100644 --- a/bundles/org.openhab.transform.javascript/pom.xml +++ b/bundles/org.openhab.transform.javascript/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.javascript diff --git a/bundles/org.openhab.transform.jinja/pom.xml b/bundles/org.openhab.transform.jinja/pom.xml index 0b916b2aecc98..3c2eac60a59da 100644 --- a/bundles/org.openhab.transform.jinja/pom.xml +++ b/bundles/org.openhab.transform.jinja/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.jinja diff --git a/bundles/org.openhab.transform.jsonpath/pom.xml b/bundles/org.openhab.transform.jsonpath/pom.xml index 2494f3c540ec3..6710ac3cd8c3d 100644 --- a/bundles/org.openhab.transform.jsonpath/pom.xml +++ b/bundles/org.openhab.transform.jsonpath/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.jsonpath diff --git a/bundles/org.openhab.transform.map/pom.xml b/bundles/org.openhab.transform.map/pom.xml index ba67160b4a258..fcf94d02015ad 100644 --- a/bundles/org.openhab.transform.map/pom.xml +++ b/bundles/org.openhab.transform.map/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.map diff --git a/bundles/org.openhab.transform.regex/pom.xml b/bundles/org.openhab.transform.regex/pom.xml index 9dde4569b21dc..a56d47517c0b9 100644 --- a/bundles/org.openhab.transform.regex/pom.xml +++ b/bundles/org.openhab.transform.regex/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.regex diff --git a/bundles/org.openhab.transform.scale/pom.xml b/bundles/org.openhab.transform.scale/pom.xml index 852956f93ec4a..791de023ceba7 100644 --- a/bundles/org.openhab.transform.scale/pom.xml +++ b/bundles/org.openhab.transform.scale/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.scale diff --git a/bundles/org.openhab.transform.xpath/pom.xml b/bundles/org.openhab.transform.xpath/pom.xml index e4a253f8a7c6f..c5296868a9149 100644 --- a/bundles/org.openhab.transform.xpath/pom.xml +++ b/bundles/org.openhab.transform.xpath/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.xpath diff --git a/bundles/org.openhab.transform.xslt/pom.xml b/bundles/org.openhab.transform.xslt/pom.xml index de8390ba10c68..4fa04487d3517 100644 --- a/bundles/org.openhab.transform.xslt/pom.xml +++ b/bundles/org.openhab.transform.xslt/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.transform.xslt diff --git a/bundles/org.openhab.voice.googletts/pom.xml b/bundles/org.openhab.voice.googletts/pom.xml index e65c9125b4e65..dd53286d9f7a1 100644 --- a/bundles/org.openhab.voice.googletts/pom.xml +++ b/bundles/org.openhab.voice.googletts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.googletts diff --git a/bundles/org.openhab.voice.mactts/pom.xml b/bundles/org.openhab.voice.mactts/pom.xml index 0cbdae6a95ff2..a90bc09ac732a 100644 --- a/bundles/org.openhab.voice.mactts/pom.xml +++ b/bundles/org.openhab.voice.mactts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.mactts diff --git a/bundles/org.openhab.voice.marytts/pom.xml b/bundles/org.openhab.voice.marytts/pom.xml index 3c9bf58ad1f5f..88956db52638b 100644 --- a/bundles/org.openhab.voice.marytts/pom.xml +++ b/bundles/org.openhab.voice.marytts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.marytts diff --git a/bundles/org.openhab.voice.picotts/pom.xml b/bundles/org.openhab.voice.picotts/pom.xml index 7e1c5fee45b19..19fe820842c9a 100644 --- a/bundles/org.openhab.voice.picotts/pom.xml +++ b/bundles/org.openhab.voice.picotts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.picotts diff --git a/bundles/org.openhab.voice.pollytts/pom.xml b/bundles/org.openhab.voice.pollytts/pom.xml index a51aef19b2bf6..7fbcc43bb99cd 100644 --- a/bundles/org.openhab.voice.pollytts/pom.xml +++ b/bundles/org.openhab.voice.pollytts/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.pollytts diff --git a/bundles/org.openhab.voice.voicerss/pom.xml b/bundles/org.openhab.voice.voicerss/pom.xml index b6806a4304098..03c2060fb103b 100644 --- a/bundles/org.openhab.voice.voicerss/pom.xml +++ b/bundles/org.openhab.voice.voicerss/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.voice.voicerss diff --git a/bundles/pom.xml b/bundles/pom.xml index 63b09b249007f..4ccac55f163a6 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons org.openhab.addons.reactor - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.bundles diff --git a/features/openhab-addons-external/pom.xml b/features/openhab-addons-external/pom.xml index 5391a77458487..c33443dc4257d 100644 --- a/features/openhab-addons-external/pom.xml +++ b/features/openhab-addons-external/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.features.karaf org.openhab.addons.reactor.features.karaf - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.features.karaf.openhab-addons-external diff --git a/features/openhab-addons/pom.xml b/features/openhab-addons/pom.xml index c118cc1f8a519..437967d72cda2 100644 --- a/features/openhab-addons/pom.xml +++ b/features/openhab-addons/pom.xml @@ -1,13 +1,11 @@ - - + 4.0.0 org.openhab.addons.features.karaf org.openhab.addons.reactor.features.karaf - 3.2.0-SNAPSHOT + 3.3.0-SNAPSHOT org.openhab.addons.features.karaf.openhab-addons @@ -52,8 +50,7 @@ - +

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ÚIq} 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 T%$Tr50{pwAXQErD?HK((KR*_- literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.jsscripting/docs/rule-script.png b/bundles/org.openhab.automation.jsscripting/docs/rule-script.png new file mode 100644 index 0000000000000000000000000000000000000000..585d16e15ef3585b9ff4157bb9d7ebbf56736f26 GIT binary patch literal 117326 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 OV`h5oBKBwJhyMo{oXOz; literal 0 HcmV?d00001 diff --git a/bundles/org.openhab.automation.jsscripting/docs/settings.png b/bundles/org.openhab.automation.jsscripting/docs/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..a342844e4e42a2a222cd15790cdd89725aed9b15 GIT binary patch literal 125391 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