From 862f861652707b445f0a9b0015cf6f4134cdbea7 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 09:18:18 +0200 Subject: [PATCH 01/45] initial commit of skeleton Signed-off-by: Bernhard Kreuz --- bundles/org.openhab.binding.romyrobot/NOTICE | 13 + .../org.openhab.binding.romyrobot/README.md | 94 +++ bundles/org.openhab.binding.romyrobot/pom.xml | 17 + .../src/main/feature/feature.xml | 9 + .../internal/romyRobotBindingConstants.java | 34 + .../internal/romyRobotConfiguration.java | 31 + .../romyrobot/internal/romyRobotHandler.java | 104 +++ .../internal/romyRobotHandlerFactory.java | 55 ++ .../src/main/resources/OH-INF/addon/addon.xml | 10 + .../OH-INF/i18n/romyrobot.properties | 3 + .../resources/OH-INF/thing/thing-types.xml | 48 ++ bundles/pom.xml | 652 +++++++++++++++++- 12 files changed, 1068 insertions(+), 2 deletions(-) create mode 100644 bundles/org.openhab.binding.romyrobot/NOTICE create mode 100644 bundles/org.openhab.binding.romyrobot/README.md create mode 100644 bundles/org.openhab.binding.romyrobot/pom.xml create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/addon/addon.xml create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/i18n/romyrobot.properties create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml diff --git a/bundles/org.openhab.binding.romyrobot/NOTICE b/bundles/org.openhab.binding.romyrobot/NOTICE new file mode 100644 index 000000000000..38d625e34923 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/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.romyrobot/README.md b/bundles/org.openhab.binding.romyrobot/README.md new file mode 100644 index 000000000000..5a732d17155a --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/README.md @@ -0,0 +1,94 @@ +# romyRobot Binding + +_Give some details about what this binding is meant for - a protocol, system, specific device._ + +_If possible, provide some resources like pictures (only PNG is supported currently), 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._ + +_Put each sentence in a separate line to improve readability of diffs._ + +## Supported Things + +_Please describe the different supported things / devices including their ThingTypeUID 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._ + +- `bridge`: Short description of the Bridge, if any +- `sample`: Short description of the Thing with the ThingTypeUID `sample` + +## 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 romyRobot Binding +# +# Default secret key for the pairing of the romyRobot 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._ + +_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._ + +### `sample` Thing Configuration + +| Name | Type | Description | Default | Required | Advanced | +|-----------------|---------|---------------------------------------|---------|----------|----------| +| hostname | text | Hostname or IP address of the device | N/A | yes | no | +| password | text | Password to access the device | N/A | yes | no | +| refreshInterval | integer | Interval the device is polled in sec. | 600 | no | yes | + +## 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 | Read/Write | Description | +|---------|--------|------------|-----------------------------| +| control | Switch | RW | This is the control channel | + +## Full Example + +_Provide a full usage example based on textual configuration files._ +_*.things, *.items examples are mandatory as textual configuration is well used by many users._ +_*.sitemap examples are optional._ + +### Thing Configuration + +```java +Example thing configuration goes here. +``` +### Item Configuration + +```java +Example item configuration goes here. +``` + +### Sitemap Configuration + +```perl +Optional Sitemap configuration goes here. +Remove this section, if not needed. +``` + +## 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.romyrobot/pom.xml b/bundles/org.openhab.binding.romyrobot/pom.xml new file mode 100644 index 000000000000..146297c24938 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/pom.xml @@ -0,0 +1,17 @@ + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 4.0.0-SNAPSHOT + + + org.openhab.binding.romyrobot + + openHAB Add-ons :: Bundles :: romyRobot Binding + + diff --git a/bundles/org.openhab.binding.romyrobot/src/main/feature/feature.xml b/bundles/org.openhab.binding.romyrobot/src/main/feature/feature.xml new file mode 100644 index 000000000000..f4eb85b9ce2f --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/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.romyrobot/${project.version} + + diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java new file mode 100644 index 000000000000..11441de67f11 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link romyRobotBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotBindingConstants { + + private static final String BINDING_ID = "romyrobot"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_SAMPLE = new ThingTypeUID(BINDING_ID, "sample"); + + // List of all Channel ids + public static final String CHANNEL_1 = "channel1"; +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java new file mode 100644 index 000000000000..4f9d5fe10aa9 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link romyRobotConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotConfiguration { + + /** + * Sample configuration parameters. Replace with your own. + */ + public String hostname = ""; + public String password = ""; + public int refreshInterval = 600; +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java new file mode 100644 index 000000000000..5a3bea157a3a --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +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 romyRobotHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(romyRobotHandler.class); + + private @Nullable romyRobotConfiguration config; + + public romyRobotHandler(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() { + config = getConfigAs(romyRobotConfiguration.class); + + // TODO: Initialize the handler. + // The framework requires you to return from this method quickly, i.e. any network access must be done in + // the background initialization below. + // 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. + + // 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); + + // Example for background initialization: + scheduler.execute(() -> { + boolean thingReachable = true; // + // when done do: + if (thingReachable) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE); + } + }); + + // These logging types should be primarily used by bindings + // logger.trace("Example trace message"); + // logger.debug("Example debug message"); + // logger.warn("Example warn message"); + // + // Logging to INFO should be avoided normally. + // See https://www.openhab.org/docs/developer/guidelines.html#f-logging + + // Note: When initialization can NOT be done set the status with more details for further + // analysis. See also class ThingStatusDetail for all available status details. + // Add a description to give user information to understand why thing does not work as expected. E.g. + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + // "Can not access device as username and/or password are invalid"); + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java new file mode 100644 index 000000000000..2e510bf57ee9 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; + +import java.util.Set; + +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 romyRobotHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.romyrobot", service = ThingHandlerFactory.class) +public class romyRobotHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SAMPLE); + + @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_SAMPLE.equals(thingTypeUID)) { + return new romyRobotHandler(thing); + } + + return null; + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/addon/addon.xml new file mode 100644 index 000000000000..01701d0dfcee --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/addon/addon.xml @@ -0,0 +1,10 @@ + + + + binding + romyRobot Binding + This is the binding for romyRobot. + + diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/i18n/romyrobot.properties b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/i18n/romyrobot.properties new file mode 100644 index 000000000000..0c2f44015a92 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/i18n/romyrobot.properties @@ -0,0 +1,3 @@ +# FIXME: please add all English translations to this file so the texts can be translated using Crowdin +# FIXME: to generate the content of this file run: mvn i18n:generate-default-translations +# FIXME: see also: https://www.openhab.org/docs/developer/utils/i18n.html diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 000000000000..e8dec224100b --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,48 @@ + + + + + + + + + Sample thing for romyRobot Binding + + + + + + + + network-address + + Hostname or IP address of the device + + + password + + Password to access the device + + + + Interval the device is polled in sec. + 600 + true + + + + + + + Number:Temperature + + Sample channel for romyRobot Binding + + diff --git a/bundles/pom.xml b/bundles/pom.xml index bc0ef858994b..1e7759b4a20a 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -1,677 +1,1325 @@ - + 4.0.0 + org.openhab.addons + org.openhab.addons.reactor + 4.1.0-SNAPSHOT + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + pom openHAB Add-ons :: Bundles + + org.openhab.automation.groovyscripting + org.openhab.automation.jrubyscripting + org.openhab.automation.jsscripting + org.openhab.automation.jsscriptingnashorn + org.openhab.automation.jythonscripting + org.openhab.automation.pidcontroller + org.openhab.automation.pwm + + org.openhab.io.homekit + org.openhab.io.hueemulation + org.openhab.io.metrics + org.openhab.io.neeo + org.openhab.io.openhabcloud + + org.openhab.transform.bin2json + org.openhab.transform.exec + org.openhab.transform.jinja + org.openhab.transform.jsonpath + org.openhab.transform.map + org.openhab.transform.regex + org.openhab.transform.rollershutterposition + org.openhab.transform.scale + org.openhab.transform.vat + org.openhab.transform.xpath + org.openhab.transform.xslt + + org.openhab.binding.adorne + org.openhab.binding.ahawastecollection + org.openhab.binding.airq + org.openhab.binding.airquality + org.openhab.binding.airvisualnode + org.openhab.binding.alarmdecoder + org.openhab.binding.allplay + org.openhab.binding.amazondashbutton + org.openhab.binding.amazonechocontrol + org.openhab.binding.ambientweather + org.openhab.binding.amplipi + org.openhab.binding.androiddebugbridge + org.openhab.binding.androidtv + org.openhab.binding.anel + org.openhab.binding.anthem + org.openhab.binding.astro + org.openhab.binding.asuswrt + org.openhab.binding.atlona + org.openhab.binding.autelis + org.openhab.binding.automower + org.openhab.binding.avmfritz + org.openhab.binding.awattar + org.openhab.binding.benqprojector + org.openhab.binding.bigassfan + org.openhab.binding.bluetooth + org.openhab.binding.bluetooth.airthings + org.openhab.binding.bluetooth.am43 + org.openhab.binding.bluetooth.bluegiga + org.openhab.binding.bluetooth.bluez + org.openhab.binding.bluetooth.blukii + org.openhab.binding.bluetooth.daikinmadoka + org.openhab.binding.bluetooth.enoceanble + org.openhab.binding.bluetooth.generic + org.openhab.binding.bluetooth.govee + org.openhab.binding.bluetooth.radoneye + org.openhab.binding.bluetooth.roaming + org.openhab.binding.bluetooth.ruuvitag + org.openhab.binding.bondhome + org.openhab.binding.boschindego + org.openhab.binding.boschshc + org.openhab.binding.bosesoundtouch + org.openhab.binding.broadlinkthermostat + org.openhab.binding.bsblan + org.openhab.binding.bticinosmarther + org.openhab.binding.buienradar + org.openhab.binding.caddx + org.openhab.binding.cbus + org.openhab.binding.chatgpt + org.openhab.binding.chromecast + org.openhab.binding.cm11a + org.openhab.binding.comfoair + org.openhab.binding.coolmasternet + org.openhab.binding.coronastats + org.openhab.binding.daikin + org.openhab.binding.dali + org.openhab.binding.danfossairunit + 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 + org.openhab.binding.dmx + org.openhab.binding.dominoswiss + org.openhab.binding.doorbird + org.openhab.binding.draytonwiser + org.openhab.binding.dscalarm + org.openhab.binding.dsmr + org.openhab.binding.dwdpollenflug + org.openhab.binding.dwdunwetter + org.openhab.binding.easee + org.openhab.binding.echonetlite + org.openhab.binding.ecobee + org.openhab.binding.ecotouch + org.openhab.binding.ecovacs + org.openhab.binding.ecowatt + org.openhab.binding.ekey + org.openhab.binding.electroluxair + org.openhab.binding.elerotransmitterstick + org.openhab.binding.elroconnects + org.openhab.binding.energenie + org.openhab.binding.energidataservice + org.openhab.binding.enigma2 + org.openhab.binding.enocean + org.openhab.binding.enphase + org.openhab.binding.enturno + org.openhab.binding.epsonprojector + org.openhab.binding.etherrain + org.openhab.binding.evcc + org.openhab.binding.evohome + org.openhab.binding.exec + org.openhab.binding.feed + org.openhab.binding.feican + org.openhab.binding.fineoffsetweatherstation + org.openhab.binding.flicbutton + org.openhab.binding.fmiweather + org.openhab.binding.folderwatcher + org.openhab.binding.folding + org.openhab.binding.foobot + org.openhab.binding.freebox + org.openhab.binding.freeboxos + org.openhab.binding.fronius + org.openhab.binding.fsinternetradio + org.openhab.binding.ftpupload + org.openhab.binding.gardena + org.openhab.binding.gce + org.openhab.binding.generacmobilelink + org.openhab.binding.goecharger + org.openhab.binding.gpio + org.openhab.binding.globalcache + org.openhab.binding.gpstracker + org.openhab.binding.gree + org.openhab.binding.groupepsa + org.openhab.binding.groheondus + org.openhab.binding.guntamatic + org.openhab.binding.haassohnpelletstove + org.openhab.binding.harmonyhub + org.openhab.binding.haywardomnilogic + org.openhab.binding.hccrubbishcollection + org.openhab.binding.hdanywhere + org.openhab.binding.hdpowerview + org.openhab.binding.helios + org.openhab.binding.heliosventilation + org.openhab.binding.heos + org.openhab.binding.herzborg + org.openhab.binding.homeconnect + org.openhab.binding.homematic + org.openhab.binding.homewizard + org.openhab.binding.hpprinter + org.openhab.binding.http + org.openhab.binding.hue + org.openhab.binding.hydrawise + org.openhab.binding.hyperion + org.openhab.binding.iammeter + org.openhab.binding.iaqualink + org.openhab.binding.icalendar + org.openhab.binding.icloud + org.openhab.binding.ihc + org.openhab.binding.insteon + org.openhab.binding.ipcamera + org.openhab.binding.ipobserver + org.openhab.binding.intesis + org.openhab.binding.ipp + org.openhab.binding.irobot + org.openhab.binding.irtrans + org.openhab.binding.ism8 + org.openhab.binding.jablotron + org.openhab.binding.jeelink + org.openhab.binding.jellyfin + org.openhab.binding.juicenet + org.openhab.binding.kaleidescape + org.openhab.binding.keba + org.openhab.binding.km200 + org.openhab.binding.knx + org.openhab.binding.kodi + org.openhab.binding.konnected + org.openhab.binding.kostalinverter + org.openhab.binding.kvv + org.openhab.binding.lametrictime + org.openhab.binding.lcn + org.openhab.binding.leapmotion + org.openhab.binding.lghombot + org.openhab.binding.lgtvserial + org.openhab.binding.lgwebos + org.openhab.binding.lifx + org.openhab.binding.linky + org.openhab.binding.linuxinput + org.openhab.binding.liquidcheck + org.openhab.binding.lirc + org.openhab.binding.livisismarthome + org.openhab.binding.logreader + org.openhab.binding.loxone + org.openhab.binding.lutron + org.openhab.binding.luxom + org.openhab.binding.luxtronikheatpump + org.openhab.binding.magentatv + org.openhab.binding.mail + org.openhab.binding.max + org.openhab.binding.mcd + org.openhab.binding.mcp23017 + org.openhab.binding.meater + org.openhab.binding.mecmeter + org.openhab.binding.melcloud + org.openhab.binding.mercedesme + org.openhab.binding.meteoalerte + org.openhab.binding.meteoblue + org.openhab.binding.meteostick + org.openhab.binding.miele + org.openhab.binding.mielecloud + org.openhab.binding.mihome + org.openhab.binding.miio + org.openhab.binding.mikrotik + org.openhab.binding.millheat + org.openhab.binding.milight + org.openhab.binding.minecraft + org.openhab.binding.modbus + org.openhab.binding.modbus.e3dc + org.openhab.binding.modbus.sbc + org.openhab.binding.modbus.studer + org.openhab.binding.modbus.sunspec + org.openhab.binding.modbus.stiebeleltron + org.openhab.binding.modbus.helioseasycontrols + org.openhab.binding.monopriceaudio + org.openhab.binding.mpd + org.openhab.binding.mqtt + org.openhab.binding.mqtt.espmilighthub + org.openhab.binding.mqtt.generic + org.openhab.binding.mqtt.homeassistant + org.openhab.binding.mqtt.homie + org.openhab.binding.mqtt.ruuvigateway + org.openhab.binding.mybmw + org.openhab.binding.mycroft + org.openhab.binding.mynice org.openhab.binding.mystrom + org.openhab.binding.nanoleaf + org.openhab.binding.neato + org.openhab.binding.neeo + org.openhab.binding.neohub + org.openhab.binding.nest + org.openhab.binding.netatmo + org.openhab.binding.network + org.openhab.binding.networkupstools + org.openhab.binding.nibeheatpump + org.openhab.binding.nibeuplink + org.openhab.binding.nikobus + org.openhab.binding.nikohomecontrol + org.openhab.binding.nobohub + org.openhab.binding.novafinedust + org.openhab.binding.ntp + org.openhab.binding.nuki + org.openhab.binding.nuvo + org.openhab.binding.nzwateralerts + org.openhab.binding.oceanic + org.openhab.binding.ojelectronics + org.openhab.binding.omnikinverter + org.openhab.binding.omnilink + org.openhab.binding.onebusaway + org.openhab.binding.onewiregpio + org.openhab.binding.onewire + org.openhab.binding.onkyo + org.openhab.binding.opengarage + org.openhab.binding.opensprinkler + org.openhab.binding.openthermgateway + org.openhab.binding.openuv + org.openhab.binding.openweathermap + org.openhab.binding.openwebnet + org.openhab.binding.oppo + org.openhab.binding.orbitbhyve + org.openhab.binding.orvibo + org.openhab.binding.paradoxalarm + org.openhab.binding.pentair + org.openhab.binding.phc + org.openhab.binding.pilight + org.openhab.binding.pioneeravr + org.openhab.binding.pixometer + org.openhab.binding.pjlinkdevice + org.openhab.binding.playstation + org.openhab.binding.plclogo + org.openhab.binding.plex + org.openhab.binding.plugwise + org.openhab.binding.plugwiseha + org.openhab.binding.powermax + org.openhab.binding.proteusecometer + org.openhab.binding.prowl + org.openhab.binding.publictransportswitzerland + org.openhab.binding.pulseaudio + org.openhab.binding.pushbullet + org.openhab.binding.pushover + org.openhab.binding.pushsafer + org.openhab.binding.qbus + org.openhab.binding.qolsysiq + org.openhab.binding.radiothermostat + 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 + org.openhab.binding.robonect + org.openhab.binding.roku + + org.openhab.binding.romyrobot + org.openhab.binding.rotel + org.openhab.binding.russound + org.openhab.binding.sagercaster + org.openhab.binding.samsungtv + org.openhab.binding.satel + org.openhab.binding.semsportal + org.openhab.binding.senechome + org.openhab.binding.seneye + org.openhab.binding.sensebox + org.openhab.binding.sensibo + org.openhab.binding.sensorcommunity + org.openhab.binding.serial + org.openhab.binding.serialbutton + org.openhab.binding.shelly + org.openhab.binding.silvercrestwifisocket + org.openhab.binding.siemensrds + org.openhab.binding.sinope + org.openhab.binding.sleepiq + org.openhab.binding.smaenergymeter + org.openhab.binding.smartmeter + org.openhab.binding.smartthings + org.openhab.binding.smhi + org.openhab.binding.smsmodem + org.openhab.binding.sncf + org.openhab.binding.snmp + org.openhab.binding.solaredge + org.openhab.binding.solarlog + org.openhab.binding.solarmax + org.openhab.binding.solarwatt + org.openhab.binding.solax + org.openhab.binding.somfymylink + org.openhab.binding.somfytahoma + org.openhab.binding.somneo + org.openhab.binding.sonnen + org.openhab.binding.sonos + org.openhab.binding.sonyaudio + org.openhab.binding.sonyprojector + org.openhab.binding.souliss + org.openhab.binding.speedtest + org.openhab.binding.spotify + org.openhab.binding.squeezebox + org.openhab.binding.surepetcare + org.openhab.binding.synopanalyzer + org.openhab.binding.systeminfo + org.openhab.binding.tacmi + org.openhab.binding.tado + org.openhab.binding.tankerkoenig + org.openhab.binding.tapocontrol org.openhab.binding.tasmotaplug org.openhab.binding.telegram + org.openhab.binding.teleinfo + org.openhab.binding.tellstick + org.openhab.binding.tesla + org.openhab.binding.tibber + org.openhab.binding.tivo + org.openhab.binding.touchwand + org.openhab.binding.tplinkrouter + org.openhab.binding.tplinksmarthome + org.openhab.binding.tr064 + org.openhab.binding.tradfri org.openhab.binding.unifi + org.openhab.binding.unifiedremote + org.openhab.binding.upnpcontrol + org.openhab.binding.upb + org.openhab.binding.urtsi + org.openhab.binding.valloxmv + org.openhab.binding.vdr + org.openhab.binding.vektiva + org.openhab.binding.velbus + org.openhab.binding.velux + org.openhab.binding.venstarthermostat + org.openhab.binding.ventaair + org.openhab.binding.verisure + org.openhab.binding.vesync + org.openhab.binding.vigicrues + org.openhab.binding.vitotronic + org.openhab.binding.vizio + org.openhab.binding.volvooncall + org.openhab.binding.volumio + org.openhab.binding.warmup + org.openhab.binding.weathercompany + org.openhab.binding.weatherunderground + org.openhab.binding.webexteams + org.openhab.binding.webthing + org.openhab.binding.wemo + org.openhab.binding.wifiled + org.openhab.binding.windcentrale + org.openhab.binding.wlanthermo + org.openhab.binding.wled + org.openhab.binding.wolfsmartset + org.openhab.binding.wundergroundupdatereceiver org.openhab.binding.x org.openhab.binding.xmltv + org.openhab.binding.xmppclient + org.openhab.binding.yamahamusiccast + org.openhab.binding.yamahareceiver + org.openhab.binding.yioremote + org.openhab.binding.yeelight + org.openhab.binding.zoneminder + org.openhab.binding.zway + + org.openhab.persistence.dynamodb + org.openhab.persistence.influxdb + org.openhab.persistence.inmemory + org.openhab.persistence.jdbc + org.openhab.persistence.jpa + org.openhab.persistence.mapdb + org.openhab.persistence.mongodb + org.openhab.persistence.rrd4j + + org.openhab.voice.googlestt + org.openhab.voice.googletts + org.openhab.voice.mactts + org.openhab.voice.marytts + org.openhab.voice.mimictts + org.openhab.voice.actiontemplatehli + org.openhab.voice.picotts + org.openhab.voice.pollytts + org.openhab.voice.porcupineks + org.openhab.voice.rustpotterks + org.openhab.voice.voicerss + org.openhab.voice.voskstt + org.openhab.voice.watsonstt + + + target/dependency + + + + org.lastnpe.eea + eea-all + ${eea.version} + + + + org.openhab.core.bom + org.openhab.core.bom.compile + pom + provided + + + org.openhab.core.bom + org.openhab.core.bom.openhab-core + pom + provided + + + commons-net + commons-net + + + + + org.openhab.core.bom + org.openhab.core.bom.test + pom + test + + + + org.apache.karaf.features + framework + ${karaf.version} + kar + true + + + * + * + + + + + + org.apache.karaf.features + standard + ${karaf.version} + features + xml + provided + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + true + + + + org.apache.karaf.tooling + karaf-maven-plugin + ${karaf.version} + true + + 80 + true + true + false + true + true + + + + compile + + features-generate-descriptor + + generate-resources + + ${feature.directory} + + + + karaf-feature-verification + + verify + + verify + + + + mvn:org.apache.karaf.features/framework/${karaf.version}/xml/features + mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features + mvn:org.apache.karaf.features/specs/${karaf.version}/xml/features + + file:${project.build.directory}/feature/feature.xml + + org.apache.karaf.features:framework + ${oh.java.version} + + framework + + + openhab-* + + false + true + first + + + + + + + + biz.aQute.bnd + bnd-maven-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.karaf.tooling + karaf-maven-plugin + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.0 + + + embed-dependencies + + unpack-dependencies + + + runtime + jar + **/module-info.class + javax.activation,org.apache.karaf.features,org.lastnpe.eea + ${dep.noembedding} + ${project.build.directory}/classes + true + true + true + jar + + + + unpack-eea + + unpack + + + + + org.lastnpe.eea + eea-all + ${eea.version} + true + + + + + + + + + + + no-embed-dependencies + + + noEmbedDependencies.profile + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + embed-dependencies + none + + + + + + + From 622f7d14db47adfa180ad83a0fc6f7571b73a93a Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 10:00:52 +0200 Subject: [PATCH 02/45] defined initial thing types Signed-off-by: Bernhard Kreuz --- .../resources/OH-INF/thing/thing-types.xml | 142 +++++++++++++++--- 1 file changed, 121 insertions(+), 21 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index e8dec224100b..cd1676bd4048 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -4,31 +4,36 @@ 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"> - - - - - - Sample thing for romyRobot Binding + + + A RomyRobot vacuum robot + CleaningRobot - + + + + + + + + + + + network-address - Hostname or IP address of the device + The host name or IP address of the RomyRobot Web API interface. Please take note that you have to first open the URL in your browser and unlock the HTTP interface with the code you find under the dustbin. - - password - - Password to access the device + + + Port of the RomyRobot Web API interface. + 8080 + true @@ -36,13 +41,108 @@ 600 true + + + Specifies the connection timeout in seconds. + 5 + - - - Number:Temperature - - Sample channel for romyRobot Binding + + String + + Firmware version installed on vacuum + + + + String + + Command to execute + + + + + + + + + + + + String + + Intensitiy of water usage + + + + + + + + + + + String + + Choose an available cleaning strategy + + + + + + + + + + + String + + Choose an available suction mode + + + + + + + + + + + + String + + Robots current status + + + + Number + + Battery charge percentage + + + + String + + Indicates the vacuums charging status + + + + Number + + Wi-Fi signal strength + + + + String + + Robots current power status + + + + String + + Information about availabler maps. Useful for composing commands + From 24bb8f2d569d1a378f92fa51b549e97d64bab03f Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 10:01:24 +0200 Subject: [PATCH 03/45] remaining skeleton files Signed-off-by: Bernhard Kreuz --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 4a68d285a178..eb8149bd1b1a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -294,6 +294,7 @@ /bundles/org.openhab.binding.rme/ @kgoderis /bundles/org.openhab.binding.robonect/ @reyem /bundles/org.openhab.binding.roku/ @mlobstein +/bundles/org.openhab.binding.romyrobot/ @wzbfyb /bundles/org.openhab.binding.rotel/ @lolodomo /bundles/org.openhab.binding.russound/ @openhab/add-ons-maintainers /bundles/org.openhab.binding.sagercaster/ @clinique diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index dadea0ba22ef..0206f5dd2b3c 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -1456,6 +1456,11 @@ org.openhab.binding.roku ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.romyrobot + ${project.version} + org.openhab.addons.bundles org.openhab.binding.rotel From 6cde35a7e713abbed8887b068977cfca73b9b678 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 14:12:58 +0200 Subject: [PATCH 04/45] initial implementation to read most channels Signed-off-by: Bernhard Kreuz --- bundles/org.openhab.binding.romyrobot/pom.xml | 2 +- .../romyrobot/internal/api/RomyApi.java | 115 +++++++++ .../RomyApiAGON_1_2_4_release_3_14_3068.java | 240 ++++++++++++++++++ .../internal/api/RomyApiFactory.java | 42 +++ .../internal/romyRobotBindingConstants.java | 17 +- .../internal/romyRobotConfiguration.java | 7 +- .../romyrobot/internal/romyRobotHandler.java | 114 +++++---- .../internal/romyRobotHandlerFactory.java | 21 +- .../resources/OH-INF/thing/thing-types.xml | 32 +-- 9 files changed, 519 insertions(+), 71 deletions(-) create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java diff --git a/bundles/org.openhab.binding.romyrobot/pom.xml b/bundles/org.openhab.binding.romyrobot/pom.xml index 146297c24938..ff5583a4f27d 100644 --- a/bundles/org.openhab.binding.romyrobot/pom.xml +++ b/bundles/org.openhab.binding.romyrobot/pom.xml @@ -12,6 +12,6 @@ org.openhab.binding.romyrobot - openHAB Add-ons :: Bundles :: romyRobot Binding + openHAB Add-ons :: Bundles :: RomyRobot Binding diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java new file mode 100644 index 000000000000..71cedac41e42 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package org.openhab.binding.romyrobot.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link RomyApi} interface defines the functions which are + * controllable on the Romy API interface. + * + * @author Bernhard Kreuz - Initial contribution + */ + +@NonNullByDefault +public interface RomyApi { + /** + * Sends all the GET requests and stores/cache the responses for use by the API to prevent the need for multiple + * requests. + * + * @throws Exception + * + * @throws CommunicationApiException + * @throws UnauthorizedApiException + */ + void refresh() throws Exception; + + /** + * + * @return Firmware Version of robot + */ + String getFirmwareVersion(); + + /** + * + * @return Status / Mode robot is currently in + */ + String getModeString(); + + /** + * + * @return currently set pump volume + */ + String getActivePumpVolume(); + + /** + * + * @param volume the pump volume used on next start + */ + void setActivePumpVolume(String volume); + + /** + * + * @return cleaning strategy + */ + String getStrategy(); + + /** + * + * @param strategy cleaning strategy + */ + void setStrategy(String strategy); + + /** + * + * @return suction mode, see thing xml for details + */ + String getSuctionMode(); + + /** + * + * @param suctionMode suction mode to be used for next start + */ + void setSuctionMode(String suctionMode); + + /** + * + * @return current battery level + */ + int getBatteryLevel(); + + /** + * + * @return weither the vacuum is charging + */ + String getChargingStatus(); + + /** + * + * @return WiFi rssi + */ + int getRssi(); + + /** + * + * @return current power status of the vacuum + */ + String getPowerStatus(); + + /** + * + * @return a String listing the available maps + */ + String getAvailableMaps(); +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java new file mode 100644 index 000000000000..76eb1c6a0273 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -0,0 +1,240 @@ +package org.openhab.binding.romyrobot.internal.api; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNull; +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.romyrobot.internal.RomyRobotConfiguration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { + + private @NonNull String hostname; + private @NonNull RomyRobotConfiguration config; + protected HttpRequestSender http; + private String firmwareVersion = "UNKNOWN"; + private String mode; + private String activePumpVolume; + private String charging; + private int batteryLevel; + private String powerStatus; + private String maps; + private int rssi; + private String strategy; + private String suctionMode; + private static final String CMD_GET_ROBOT_ID = "get/robot_id"; + private static final String CMD_GET_STATUS = "get/status"; + private static final String CMD_GET_MAPS = "get/maps"; + private static final String CMD_GET_WIFI_STATUS = "get/wifi_status"; + private static final String CMD_GET_POWER_STATUS = "get/power_status"; + private static final @NonNull String UNKNOWN = "UNKNOWN"; + + public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, + final @NonNull RomyRobotConfiguration config) { + this.config = config; + if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { + this.hostname = config.hostname; + } else { + this.hostname = "http://" + config.hostname; + } + + this.http = new HttpRequestSender(httpClient); + } + + /** + * Returns the hostname and port formatted URL as a String. + * + * @return String representation of the OpenSprinkler API URL. + */ + protected String getBaseUrl() { + return hostname + ":" + config.port + "/"; + } + + @Override + public void refresh() throws Exception { + String returnContent; + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + firmwareVersion = new ObjectMapper().readTree(returnContent).get("firmware").asText(); + if (firmwareVersion == null) { + throw new Exception("There was a problem in the HTTP communication: firmware was empty."); + } + maps = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); + powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + mode = jsonNode.get("mode").asText(); + activePumpVolume = jsonNode.get("active_pump_volume").asText(); + charging = jsonNode.get("charging").asText(); + batteryLevel = jsonNode.get("battery_level").asInt(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_WIFI_STATUS, null); + jsonNode = new ObjectMapper().readTree(returnContent); + rssi = jsonNode.get("rssi").asInt(); + } + + @Override + public String getFirmwareVersion() { + return firmwareVersion; + } + + @Override + public String getModeString() { + return mode; + } + + @Override + public String getActivePumpVolume() { + return activePumpVolume; + } + + @Override + public void setActivePumpVolume(@NonNull String volume) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setActivePumpVolume'"); + } + + @Override + public String getStrategy() { + return strategy; + } + + @Override + public void setStrategy(@NonNull String strategy) { + this.strategy = strategy; + } + + @Override + public String getSuctionMode() { + return suctionMode; + } + + @Override + public void setSuctionMode(@NonNull String suctionMode) { + this.suctionMode = suctionMode; + } + + @Override + public int getBatteryLevel() { + return batteryLevel; + } + + @Override + public String getChargingStatus() { + return charging; + } + + @Override + public int getRssi() { + return rssi; + } + + @Override + public String getPowerStatus() { + return powerStatus; + } + + @Override + public String getAvailableMaps() { + return maps; + } + + /** + * This class contains helper methods for communicating HTTP GET and HTTP POST + * requests. + * + * @author Chris Graham - Initial contribution + * @author Florian Schmidt - Reduce visibility of Http communication to Api + */ + protected class HttpRequestSender { + private static final int HTTP_OK_CODE = 200; + private static final String USER_AGENT = "Mozilla/5.0"; + + private final HttpClient httpClient; + + public HttpRequestSender(HttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Given a URL and a set parameters, send a HTTP GET request to the URL location + * created by the URL and parameters. + * + * @param url The URL to send a GET request to. + * @param urlParameters List of parameters to use in the URL for the GET + * request. Null if no parameters. + * @return String contents of the response for the GET request. + * @throws Exception + */ + public String sendHttpGet(String url, @Nullable String urlParameters) throws Exception { + String location = null; + if (urlParameters != null) { + location = url + "?" + urlParameters; + } else { + location = url; + } + ContentResponse response; + try { + response = withGeneralProperties(httpClient.newRequest(location)) + .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); + } catch (Exception e) { + throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + } + if (response.getStatus() != HTTP_OK_CODE) { + throw new Exception( + "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); + } + String content = response.getContentAsString(); + if ("{\"result\":2}".equals(content)) { + throw new Exception("Unauthorized, check your robot was unlocked"); + } + return content; + } + + private Request withGeneralProperties(Request request) { + // TODO: request header configuration + /* + * request.header(HttpHeader.USER_AGENT, USER_AGENT); + * if (!config.basicUsername.isEmpty() && !config.basicPassword.isEmpty()) { + * String encoded = Base64.getEncoder().encodeToString( + * (config.basicUsername + ":" + config.basicPassword).getBytes(StandardCharsets.UTF_8)); + * request.header(HttpHeader.AUTHORIZATION, "Basic " + encoded); + * } + */ + return request; + } + + /** + * Given a URL and a set parameters, send a HTTP POST request to the URL + * location created by the URL and parameters. + * + * @param url The URL to send a POST request to. + * @param urlParameters List of parameters to use in the URL for the POST + * request. Null if no parameters. + * @return String contents of the response for the POST request. + * @throws Exception + */ + public String sendHttpPost(String url, String urlParameters) throws Exception { + ContentResponse response; + try { + response = withGeneralProperties(httpClient.newRequest(url)).timeout(config.timeout, TimeUnit.SECONDS) + .method(HttpMethod.POST).content(new StringContentProvider(urlParameters)).send(); + } catch (Exception e) { + throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + } + if (response.getStatus() != HTTP_OK_CODE) { + throw new Exception( + "Error sending HTTP POST request to " + url + ". Got response code: " + response.getStatus()); + } + return response.getContentAsString(); + } + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java new file mode 100644 index 000000000000..6c5c4006e8d0 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jetty.client.HttpClient; +import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +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; + +/** + * The {@link RomyApiFactory} class is used for creating instances of + * the Romy API classes to interact with the RomyRobot HTTP API. + * + * @author Bernhard Kreuz - Initial contribution + */ +@Component(service = RomyApiFactory.class) +@NonNullByDefault +public class RomyApiFactory { + private HttpClient httpClient; + + @Activate + public RomyApiFactory(@Reference HttpClientFactory httpClientFactory) { + this.httpClient = httpClientFactory.getCommonHttpClient(); + } + + public RomyApi getHttpApi(RomyRobotConfiguration config) { + return new RomyApiAGON_1_2_4_release_3_14_3068(this.httpClient, config); + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index 11441de67f11..332f0d1ca315 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -22,13 +22,24 @@ * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotBindingConstants { +public class RomyRobotBindingConstants { private static final String BINDING_ID = "romyrobot"; // List of all Thing Type UIDs - public static final ThingTypeUID THING_TYPE_SAMPLE = new ThingTypeUID(BINDING_ID, "sample"); + public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "romyrobot"); // List of all Channel ids - public static final String CHANNEL_1 = "channel1"; + + public static final String CHANNEL_FW_VERSION = "fwversion"; + public static final String CHANNEL_COMMAND = "command"; + public static final String CHANNEL_MODE = "mode"; + public static final String CHANNEL_ACTIVE_PUMP_VOLUME = "activepumpvolume"; + public static final String CHANNEL_STRATEGY = "strategy"; + public static final String CHANNEL_SUCTION_MODE = "suctionmode"; + public static final String CHANNEL_BATTERY = "battery"; + public static final String CHANNEL_CHARGING = "charging"; + public static final String CHANNEL_RSSI = "rssi"; + public static final String CHANNEL_POWER_STATUS = "powerstatus"; + public static final String CHANNEL_AVAILABLE_MAPS = "availablemaps"; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java index 4f9d5fe10aa9..a79579a92b08 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java @@ -15,17 +15,18 @@ import org.eclipse.jdt.annotation.NonNullByDefault; /** - * The {@link romyRobotConfiguration} class contains fields mapping thing configuration parameters. + * The {@link RomyRobotConfiguration} class contains fields mapping thing configuration parameters. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotConfiguration { +public class RomyRobotConfiguration { /** * Sample configuration parameters. Replace with your own. */ public String hostname = ""; - public String password = ""; public int refreshInterval = 600; + public int port = 8080; + public int timeout = 5; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 5a3bea157a3a..1d6cc20ef536 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -12,13 +12,25 @@ */ package org.openhab.binding.romyrobot.internal; -import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; +import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; +import static org.openhab.core.library.unit.Units.PERCENT; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.validation.constraints.NotNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.api.RomyApi; +import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; +import org.openhab.core.library.types.DecimalType; +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; @@ -26,25 +38,30 @@ import org.slf4j.LoggerFactory; /** - * The {@link romyRobotHandler} is responsible for handling commands, which are + * The {@link RomyRobotHandler} is responsible for handling commands, which are * sent to one of the channels. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotHandler extends BaseThingHandler { +public class RomyRobotHandler extends BaseThingHandler { - private final Logger logger = LoggerFactory.getLogger(romyRobotHandler.class); + private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); - private @Nullable romyRobotConfiguration config; + private @NotNull RomyRobotConfiguration config; + private @Nullable ScheduledFuture pollingJob; + private @Nullable RomyApi romyDevice; + private @Nullable RomyApiFactory apiFactory; - public romyRobotHandler(Thing thing) { + public RomyRobotHandler(Thing thing, RomyApiFactory apiFactory) { super(thing); + this.apiFactory = apiFactory; + config = getConfigAs(RomyRobotConfiguration.class); } @Override public void handleCommand(ChannelUID channelUID, Command command) { - if (CHANNEL_1.equals(channelUID.getId())) { + if (CHANNEL_FW_VERSION.equals(channelUID.getId())) { if (command instanceof RefreshType) { // TODO: handle data refresh } @@ -60,45 +77,56 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void initialize() { - config = getConfigAs(romyRobotConfiguration.class); - - // TODO: Initialize the handler. - // The framework requires you to return from this method quickly, i.e. any network access must be done in - // the background initialization below. - // 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. - - // 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. + config = getConfigAs(RomyRobotConfiguration.class); updateStatus(ThingStatus.UNKNOWN); + pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); + } - // Example for background initialization: - scheduler.execute(() -> { - boolean thingReachable = true; // - // when done do: - if (thingReachable) { + public void refreshVacuum() { + RomyApi localApi = romyDevice; + if (localApi == null) { + setupAPI(); + localApi = romyDevice; + } + if (localApi != null) { + try { + localApi.refresh(); updateStatus(ThingStatus.ONLINE); - } else { - updateStatus(ThingStatus.OFFLINE); + this.updateChannels(); + + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); } - }); - - // These logging types should be primarily used by bindings - // logger.trace("Example trace message"); - // logger.debug("Example debug message"); - // logger.warn("Example warn message"); - // - // Logging to INFO should be avoided normally. - // See https://www.openhab.org/docs/developer/guidelines.html#f-logging - - // Note: When initialization can NOT be done set the status with more details for further - // analysis. See also class ThingStatusDetail for all available status details. - // Add a description to give user information to understand why thing does not work as expected. E.g. - // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - // "Can not access device as username and/or password are invalid"); + } + } + + private void updateChannels() { + if (romyDevice != null) { + updateState(CHANNEL_FW_VERSION, StringType.valueOf(romyDevice.getFirmwareVersion())); + updateState(CHANNEL_MODE, StringType.valueOf(romyDevice.getModeString())); + updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(romyDevice.getActivePumpVolume())); + updateState(CHANNEL_BATTERY, QuantityType.valueOf(romyDevice.getBatteryLevel(), PERCENT)); + updateState(CHANNEL_CHARGING, StringType.valueOf(romyDevice.getChargingStatus())); + updateState(CHANNEL_POWER_STATUS, StringType.valueOf(romyDevice.getPowerStatus())); + updateState(CHANNEL_RSSI, new DecimalType(romyDevice.getRssi())); + updateState(CHANNEL_STRATEGY, StringType.valueOf(romyDevice.getStrategy())); + updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(romyDevice.getSuctionMode())); + updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(romyDevice.getAvailableMaps())); + } + } + + private void setupAPI() { + logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", + config.hostname, config.port, config.refreshInterval, config.timeout); + try { + romyDevice = apiFactory.getHttpApi(config); + RomyApi localApi = romyDevice; + + } catch (Exception exp) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not create an API connection to RomyRobot. Error received: " + exp); + return; + } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index 2e510bf57ee9..30d7a84b3d11 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -12,30 +12,39 @@ */ package org.openhab.binding.romyrobot.internal; -import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; +import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.ROMYROBOT_DEVICE; import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; 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 romyRobotHandlerFactory} is responsible for creating things and thing + * The {@link RomyRobotHandlerFactory} is responsible for creating things and thing * handlers. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault @Component(configurationPid = "binding.romyrobot", service = ThingHandlerFactory.class) -public class romyRobotHandlerFactory extends BaseThingHandlerFactory { +public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { - private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SAMPLE); + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); + private RomyApiFactory apiFactory; + + @Activate + public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory) { + this.apiFactory = apiFactory; + } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -46,8 +55,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (THING_TYPE_SAMPLE.equals(thingTypeUID)) { - return new romyRobotHandler(thing); + if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { + return new RomyRobotHandler(thing, apiFactory); } return null; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index cd1676bd4048..9e85ca6200ee 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -10,24 +10,25 @@ CleaningRobot - + - + - + - - + + network-address - The host name or IP address of the RomyRobot Web API interface. Please take note that you have to first open the URL in your browser and unlock the HTTP interface with the code you find under the dustbin. + The host name or IP address of the RomyRobot Web API interface. Please take note that you have to first + open the URL in your browser and unlock the HTTP interface with the code you find under the dustbin. @@ -49,7 +50,7 @@ - + String Firmware version installed on vacuum @@ -60,7 +61,8 @@ Command to execute - + @@ -69,12 +71,12 @@ - + String Intensitiy of water usage - + @@ -87,7 +89,7 @@ Choose an available cleaning strategy - + @@ -95,12 +97,12 @@ - + String Choose an available suction mode - + @@ -133,13 +135,13 @@ Wi-Fi signal strength - + String Robots current power status - + String Information about availabler maps. Useful for composing commands From 6ac0bd268016b20134ec02e2d7e6423266c497ef Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 14:25:42 +0200 Subject: [PATCH 05/45] fixed notnull warnings Signed-off-by: Bernhard Kreuz --- .../romyrobot/internal/romyRobotHandler.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 1d6cc20ef536..100f238d72a0 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -45,15 +45,14 @@ */ @NonNullByDefault public class RomyRobotHandler extends BaseThingHandler { - private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); private @NotNull RomyRobotConfiguration config; private @Nullable ScheduledFuture pollingJob; private @Nullable RomyApi romyDevice; - private @Nullable RomyApiFactory apiFactory; + private @NotNull RomyApiFactory apiFactory; - public RomyRobotHandler(Thing thing, RomyApiFactory apiFactory) { + public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory) { super(thing); this.apiFactory = apiFactory; config = getConfigAs(RomyRobotConfiguration.class); @@ -82,17 +81,18 @@ public void initialize() { pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); } - public void refreshVacuum() { + public void refreshVacuum() { + RomyApiFactory apiFactory = getApiFactory(); RomyApi localApi = romyDevice; if (localApi == null) { - setupAPI(); + setupAPI(apiFactory); localApi = romyDevice; } if (localApi != null) { try { localApi.refresh(); updateStatus(ThingStatus.ONLINE); - this.updateChannels(); + this.updateChannels(localApi); } catch (Exception e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, @@ -101,27 +101,30 @@ public void refreshVacuum() { } } - private void updateChannels() { + private RomyApiFactory getApiFactory() { + return apiFactory; + } + + private void updateChannels(RomyApi device) { if (romyDevice != null) { - updateState(CHANNEL_FW_VERSION, StringType.valueOf(romyDevice.getFirmwareVersion())); - updateState(CHANNEL_MODE, StringType.valueOf(romyDevice.getModeString())); - updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(romyDevice.getActivePumpVolume())); - updateState(CHANNEL_BATTERY, QuantityType.valueOf(romyDevice.getBatteryLevel(), PERCENT)); - updateState(CHANNEL_CHARGING, StringType.valueOf(romyDevice.getChargingStatus())); - updateState(CHANNEL_POWER_STATUS, StringType.valueOf(romyDevice.getPowerStatus())); - updateState(CHANNEL_RSSI, new DecimalType(romyDevice.getRssi())); - updateState(CHANNEL_STRATEGY, StringType.valueOf(romyDevice.getStrategy())); - updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(romyDevice.getSuctionMode())); - updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(romyDevice.getAvailableMaps())); + updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); + updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); + updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); + updateState(CHANNEL_BATTERY, QuantityType.valueOf(device.getBatteryLevel(), PERCENT)); + updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); + updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); + updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); + updateState(CHANNEL_STRATEGY, StringType.valueOf(device.getStrategy())); + updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(device.getSuctionMode())); + updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(device.getAvailableMaps())); } } - private void setupAPI() { + private void setupAPI(RomyApiFactory apiFactory) { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); try { romyDevice = apiFactory.getHttpApi(config); - RomyApi localApi = romyDevice; } catch (Exception exp) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, From e493b91b06db17fd60d0ccc9ef57e2bfd2f9e219 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 14:32:57 +0200 Subject: [PATCH 06/45] implemented clean all, start, continue, go_home and stop. implemented loading of maps Signed-off-by: Bernhard Kreuz --- ...yRobotStateDescriptionOptionsProvider.java | 43 ++++++ .../romyrobot/internal/api/RomyApi.java | 18 ++- .../RomyApiAGON_1_2_4_release_3_14_3068.java | 84 ++++++++++-- .../internal/romyRobotBindingConstants.java | 3 +- .../romyrobot/internal/romyRobotHandler.java | 125 +++++++++++------- .../internal/romyRobotHandlerFactory.java | 7 +- .../resources/OH-INF/thing/thing-types.xml | 20 ++- 7 files changed, 229 insertions(+), 71 deletions(-) create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotStateDescriptionOptionsProvider.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotStateDescriptionOptionsProvider.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotStateDescriptionOptionsProvider.java new file mode 100644 index 000000000000..8959a14015ce --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotStateDescriptionOptionsProvider.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.events.EventPublisher; +import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.link.ItemChannelLinkRegistry; +import org.openhab.core.thing.type.DynamicStateDescriptionProvider; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Dynamic provider of state options while leaving other state description fields as original. + * + * @author Gregory Moyer - Initial contribution + * @author Mark Hilbush - Adapted to squeezebox binding + */ +@Component(service = { DynamicStateDescriptionProvider.class, RomyRobotStateDescriptionOptionsProvider.class }) +@NonNullByDefault +public class RomyRobotStateDescriptionOptionsProvider extends BaseDynamicStateDescriptionProvider { + + @Activate + public RomyRobotStateDescriptionOptionsProvider(final @Reference EventPublisher eventPublisher, // + final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, // + final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.eventPublisher = eventPublisher; + this.itemChannelLinkRegistry = itemChannelLinkRegistry; + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 71cedac41e42..480dd22bf98b 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -13,7 +13,7 @@ package org.openhab.binding.romyrobot.internal.api; -import org.eclipse.jdt.annotation.NonNullByDefault; +import java.util.HashMap; /** * The {@link RomyApi} interface defines the functions which are @@ -22,7 +22,6 @@ * @author Bernhard Kreuz - Initial contribution */ -@NonNullByDefault public interface RomyApi { /** * Sends all the GET requests and stores/cache the responses for use by the API to prevent the need for multiple @@ -111,5 +110,18 @@ public interface RomyApi { * * @return a String listing the available maps */ - String getAvailableMaps(); + HashMap getAvailableMaps(); + + /** + * + * @return a String listing the available maps + */ + String getAvailableMapsJson(); + + /** + * + * @param command command to execute + * @throws Exception + */ + void executeCommand(String command) throws Exception; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java index 76eb1c6a0273..174eaefb221f 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -1,5 +1,8 @@ package org.openhab.binding.romyrobot.internal.api; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNull; @@ -10,7 +13,11 @@ import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -25,10 +32,12 @@ public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { private String charging; private int batteryLevel; private String powerStatus; - private String maps; + private String mapsJson; private int rssi; private String strategy; private String suctionMode; + private String selectedMap; + private HashMap availableMaps = new HashMap(); private static final String CMD_GET_ROBOT_ID = "get/robot_id"; private static final String CMD_GET_STATUS = "get/status"; private static final String CMD_GET_MAPS = "get/maps"; @@ -36,6 +45,8 @@ public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { private static final String CMD_GET_POWER_STATUS = "get/power_status"; private static final @NonNull String UNKNOWN = "UNKNOWN"; + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { this.config = config; @@ -65,7 +76,8 @@ public void refresh() throws Exception { if (firmwareVersion == null) { throw new Exception("There was a problem in the HTTP communication: firmware was empty."); } - maps = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + parseMaps(mapsJson); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); @@ -81,6 +93,25 @@ public void refresh() throws Exception { rssi = jsonNode.get("rssi").asInt(); } + private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { + JsonNode node = new ObjectMapper().readTree(jsonString); + JsonNode maps = node.get("maps"); + if (maps.isArray()) { + availableMaps.clear(); + for (final JsonNode field : maps) { + String key = field.get("map_meta_data").textValue(); + String value = field.get("map_id").asInt() + ""; + String permanentFlag = field.get("permanent_flag").textValue(); + if ("true".equalsIgnoreCase(permanentFlag)) { + availableMaps.put(key, value); + } + } + } + if (availableMaps.size() == 1 || selectedMap == null) { + selectedMap = availableMaps.values().iterator().next(); + } + } + @Override public String getFirmwareVersion() { return firmwareVersion; @@ -97,9 +128,8 @@ public String getActivePumpVolume() { } @Override - public void setActivePumpVolume(@NonNull String volume) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'setActivePumpVolume'"); + public void setActivePumpVolume(String volume) { + this.activePumpVolume = volume; } @Override @@ -108,7 +138,7 @@ public String getStrategy() { } @Override - public void setStrategy(@NonNull String strategy) { + public void setStrategy(String strategy) { this.strategy = strategy; } @@ -118,7 +148,7 @@ public String getSuctionMode() { } @Override - public void setSuctionMode(@NonNull String suctionMode) { + public void setSuctionMode(String suctionMode) { this.suctionMode = suctionMode; } @@ -143,8 +173,8 @@ public String getPowerStatus() { } @Override - public String getAvailableMaps() { - return maps; + public String getAvailableMapsJson() { + return mapsJson; } /** @@ -237,4 +267,40 @@ public String sendHttpPost(String url, String urlParameters) throws Exception { return response.getContentAsString(); } } + + @Override + public void executeCommand(String command) throws Exception { + if ("REFRESH".equalsIgnoreCase(command)) { + return; + } + // String query = "/$" + command; + String query = null; + List params = new ArrayList(); + if ("clean_start_or_continue".equalsIgnoreCase(command) || "clean_all".equalsIgnoreCase(command) + || "clean_spot".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { + if (suctionMode != null && !"REFRESH".equals(suctionMode)) { + params.add("cleaning_parameter_set=" + suctionMode); + } + if (strategy != null && !"REFRESH".equals(strategy)) { + params.add("cleaning_strategy_mode=" + strategy); + + } + if (activePumpVolume != null) { + params.add("pump_volume=" + activePumpVolume); + } + if (params.size() > 0) { + query = String.join("&", params); + } + } else if ("redo_explore".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { + params.add("map_id" + selectedMap); + } + String url = getBaseUrl() + "set/" + command; + logger.info("executing RomyRobot command: {} at url {}", query, url); + http.sendHttpGet(url, query); + } + + @Override + public HashMap getAvailableMaps() { + return availableMaps; + } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index 332f0d1ca315..f44f78988320 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -41,5 +41,6 @@ public class RomyRobotBindingConstants { public static final String CHANNEL_CHARGING = "charging"; public static final String CHANNEL_RSSI = "rssi"; public static final String CHANNEL_POWER_STATUS = "powerstatus"; - public static final String CHANNEL_AVAILABLE_MAPS = "availablemaps"; + public static final String CHANNEL_SELECTED_MAP = "seletedmap"; + public static final String CHANNEL_AVAILABLE_MAPS_JSON = "availablemapsjson"; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 100f238d72a0..ac431b89ba30 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -15,13 +15,14 @@ import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; import static org.openhab.core.library.unit.Units.PERCENT; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import javax.validation.constraints.NotNull; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.library.types.DecimalType; @@ -34,6 +35,7 @@ import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; +import org.openhab.core.types.StateOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,34 +45,47 @@ * * @author Bernhard Kreuz - Initial contribution */ -@NonNullByDefault + public class RomyRobotHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); - private @NotNull RomyRobotConfiguration config; - private @Nullable ScheduledFuture pollingJob; - private @Nullable RomyApi romyDevice; - private @NotNull RomyApiFactory apiFactory; + private RomyRobotConfiguration config; + private ScheduledFuture pollingJob; + private RomyApi romyDevice; + private RomyApiFactory apiFactory; + private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; - public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory) { + public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory, + RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { super(thing); this.apiFactory = apiFactory; + this.stateDescriptionProvider = stateDescriptionProvider; config = getConfigAs(RomyRobotConfiguration.class); + romyDevice = setupAPI(apiFactory); } @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (CHANNEL_FW_VERSION.equals(channelUID.getId())) { - if (command instanceof RefreshType) { - // TODO: handle data refresh + public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command command) { + if (command instanceof RefreshType) { + try { + getRomyApi().refresh(); + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "RomyRobot refresh threw exception."); + } + } + if (CHANNEL_STRATEGY.equals(channelUID.getId())) { + updateState(CHANNEL_STRATEGY, new StringType(command.toString())); + getRomyApi().setStrategy(command.toString()); + } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { + updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); + getRomyApi().setSuctionMode(command.toString()); + } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { + updateState(CHANNEL_COMMAND, new StringType(command.toString())); + try { + getRomyApi().executeCommand(command.toString()); + } catch (Exception e) { + logger.error("error executing command against RomyRobot", e); } - - // 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"); } } @@ -81,32 +96,21 @@ public void initialize() { pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); } - public void refreshVacuum() { - RomyApiFactory apiFactory = getApiFactory(); - RomyApi localApi = romyDevice; - if (localApi == null) { - setupAPI(apiFactory); - localApi = romyDevice; - } - if (localApi != null) { - try { - localApi.refresh(); - updateStatus(ThingStatus.ONLINE); - this.updateChannels(localApi); + public void refreshVacuum() { - } catch (Exception e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); - } + try { + getRomyApi().refresh(); + updateStatus(ThingStatus.ONLINE); + this.updateChannels(getRomyApi()); + + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); } } - private RomyApiFactory getApiFactory() { - return apiFactory; - } - - private void updateChannels(RomyApi device) { - if (romyDevice != null) { + private void updateChannels(RomyApi device) { + if (device != null) { updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); @@ -114,22 +118,43 @@ private void updateChannels(RomyApi device) { updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); - updateState(CHANNEL_STRATEGY, StringType.valueOf(device.getStrategy())); - updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(device.getSuctionMode())); - updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(device.getAvailableMaps())); + updateState(CHANNEL_AVAILABLE_MAPS_JSON, StringType.valueOf(device.getAvailableMapsJson())); + updateMapsList(device.getAvailableMaps()); + } + } + + public void updateMapsList(HashMap maps) { + logger.trace("RomyRobot updating maps list with {} options", maps.size()); + List options = new ArrayList<>(); + for (String key : maps.keySet()) { + options.add(new StateOption(key, maps.get(key))); } + stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SELECTED_MAP), options); } - private void setupAPI(RomyApiFactory apiFactory) { + private RomyApi setupAPI(RomyApiFactory apiFactory) { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); - try { + return apiFactory.getHttpApi(config); + } + + private RomyApi getRomyApi() { + if (romyDevice == null) { romyDevice = apiFactory.getHttpApi(config); + } + return romyDevice; + } - } catch (Exception exp) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not create an API connection to RomyRobot. Error received: " + exp); - return; + @Override + public void dispose() { + RomyApi localApi = romyDevice; + if (localApi != null) { + romyDevice = null; + } + ScheduledFuture localFuture = pollingJob; + if (localFuture != null) { + localFuture.cancel(true); + pollingJob = null; } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index 30d7a84b3d11..f13675139a5b 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -40,10 +40,13 @@ public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); private RomyApiFactory apiFactory; + private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; @Activate - public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory) { + public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory, + @Reference RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { this.apiFactory = apiFactory; + this.stateDescriptionProvider = stateDescriptionProvider; } @Override @@ -56,7 +59,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { - return new RomyRobotHandler(thing, apiFactory); + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); } return null; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index 9e85ca6200ee..d26e4328af66 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -20,7 +20,8 @@ - + + @@ -39,13 +40,14 @@ Interval the device is polled in sec. - 600 + 180 true Specifies the connection timeout in seconds. 5 + true @@ -61,13 +63,14 @@ Command to execute - + + + @@ -76,7 +79,7 @@ Intensitiy of water usage - + @@ -141,7 +144,12 @@ Robots current power status - + + String + + selected map if multiple maps are stored, used on commands + + String Information about availabler maps. Useful for composing commands From a6c72c651f1074c2503df212908cfa5c22092969 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 14:44:57 +0200 Subject: [PATCH 07/45] fixed wrong assignement of selected map options Signed-off-by: Bernhard Kreuz --- .../internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java | 4 ++-- .../binding/romyrobot/internal/romyRobotBindingConstants.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java index 174eaefb221f..3bf73b697cae 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -99,8 +99,8 @@ private void parseMaps(String jsonString) throws JsonMappingException, JsonProce if (maps.isArray()) { availableMaps.clear(); for (final JsonNode field : maps) { - String key = field.get("map_meta_data").textValue(); - String value = field.get("map_id").asInt() + ""; + String value = field.get("map_meta_data").textValue(); + String key = field.get("map_id").asInt() + ""; String permanentFlag = field.get("permanent_flag").textValue(); if ("true".equalsIgnoreCase(permanentFlag)) { availableMaps.put(key, value); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index f44f78988320..d7b992cbc3d8 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -41,6 +41,6 @@ public class RomyRobotBindingConstants { public static final String CHANNEL_CHARGING = "charging"; public static final String CHANNEL_RSSI = "rssi"; public static final String CHANNEL_POWER_STATUS = "powerstatus"; - public static final String CHANNEL_SELECTED_MAP = "seletedmap"; + public static final String CHANNEL_SELECTED_MAP = "selectedmap"; public static final String CHANNEL_AVAILABLE_MAPS_JSON = "availablemapsjson"; } From b903ca5fb30ee181a8c10104ac0b02e584e6d4c7 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 17:22:47 +0200 Subject: [PATCH 08/45] added protocol detection and refactored classname to fit naming Signed-off-by: Bernhard Kreuz --- .../romyrobot/internal/api/RomyApi.java | 12 ++++++++ .../internal/api/RomyApiFactory.java | 16 ++++++++-- ...release_3_14_3068.java => RomyApi_v6.java} | 29 ++++++++++++++++--- .../romyrobot/internal/romyRobotHandler.java | 18 ++++++++---- .../internal/romyRobotHandlerFactory.java | 9 +++++- 5 files changed, 72 insertions(+), 12 deletions(-) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/{RomyApiAGON_1_2_4_release_3_14_3068.java => RomyApi_v6.java} (92%) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 480dd22bf98b..90c8a3e312d3 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -118,6 +118,18 @@ public interface RomyApi { */ String getAvailableMapsJson(); + /** + * + * @return a String listing the available maps + */ + int getProtocolVersionMajor(); + + /** + * + * @return a String listing the available maps + */ + int getProtocolVersionMinor(); + /** * * @param command command to execute diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java index 6c5c4006e8d0..6dc91d441ac4 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java @@ -36,7 +36,19 @@ public RomyApiFactory(@Reference HttpClientFactory httpClientFactory) { this.httpClient = httpClientFactory.getCommonHttpClient(); } - public RomyApi getHttpApi(RomyRobotConfiguration config) { - return new RomyApiAGON_1_2_4_release_3_14_3068(this.httpClient, config); + public RomyApi getHttpApi(RomyRobotConfiguration config) throws Exception { + int version = -1; + RomyApi lowestSupportedApi = new RomyApi_v6(this.httpClient, config); + try { + version = lowestSupportedApi.getFirmwareVersion(); + } catch (Exception exp) { + throw new Exception("Problem fetching the firmware version from RomyRobot: " + exp.getMessage()); + } + // will start to make sense once a breaking API Version > 6 is introduced + if (version >= 6) { + return lowestSupportedApi; + } else { + return lowestSupportedApi; + } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java similarity index 92% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 3bf73b697cae..26d33791bc1e 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -21,7 +21,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { +public class RomyApi_v6 implements RomyApi { private @NonNull String hostname; private @NonNull RomyRobotConfiguration config; @@ -36,18 +36,24 @@ public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { private int rssi; private String strategy; private String suctionMode; - private String selectedMap; + private String selectedMap; + + // that was the newest version when this code was written + private int protocolVersionMajor = 6; + private int protocolVersionMinor = 49; + private HashMap availableMaps = new HashMap(); private static final String CMD_GET_ROBOT_ID = "get/robot_id"; private static final String CMD_GET_STATUS = "get/status"; private static final String CMD_GET_MAPS = "get/maps"; private static final String CMD_GET_WIFI_STATUS = "get/wifi_status"; private static final String CMD_GET_POWER_STATUS = "get/power_status"; + private static final String CMD_GET_PROTOCOL_VERSION = "get/protocol_version"; private static final @NonNull String UNKNOWN = "UNKNOWN"; protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, + public RomyApi_v6(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { this.config = config; if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { @@ -90,7 +96,12 @@ public void refresh() throws Exception { returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_WIFI_STATUS, null); jsonNode = new ObjectMapper().readTree(returnContent); - rssi = jsonNode.get("rssi").asInt(); + rssi = jsonNode.get("rssi").asInt(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); + protocolVersionMajor = new ObjectMapper().readTree(returnContent).get("version_major").intValue(); + protocolVersionMinor = new ObjectMapper().readTree(returnContent).get("version_minor").intValue(); + } private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { @@ -303,4 +314,14 @@ public void executeCommand(String command) throws Exception { public HashMap getAvailableMaps() { return availableMaps; } + + @Override + public int getProtocolVersionMajor() { + return protocolVersionMajor; + } + + @Override + public int getProtocolVersionMinor() { + return protocolVersionMinor; + } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index ac431b89ba30..237ab4f90432 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -56,7 +56,7 @@ public class RomyRobotHandler extends BaseThingHandler { private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory, - RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { + RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) throws Exception { super(thing); this.apiFactory = apiFactory; this.stateDescriptionProvider = stateDescriptionProvider; @@ -75,10 +75,18 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma } if (CHANNEL_STRATEGY.equals(channelUID.getId())) { updateState(CHANNEL_STRATEGY, new StringType(command.toString())); - getRomyApi().setStrategy(command.toString()); + try { + getRomyApi().setStrategy(command.toString()); + } catch (Exception e) { + logger.error("error updating strategy: {}", e); + } } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); - getRomyApi().setSuctionMode(command.toString()); + try { + getRomyApi().setSuctionMode(command.toString()); + } catch (Exception e) { + logger.error("error updating suctionmode: {}", e); + } } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { updateState(CHANNEL_COMMAND, new StringType(command.toString())); try { @@ -132,13 +140,13 @@ public void updateMapsList(HashMap maps) { stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SELECTED_MAP), options); } - private RomyApi setupAPI(RomyApiFactory apiFactory) { + private RomyApi setupAPI(RomyApiFactory apiFactory) throws Exception { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); return apiFactory.getHttpApi(config); } - private RomyApi getRomyApi() { + private RomyApi getRomyApi() throws Exception { if (romyDevice == null) { romyDevice = apiFactory.getHttpApi(config); } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index f13675139a5b..c3c158b420b7 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -27,6 +27,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 RomyRobotHandlerFactory} is responsible for creating things and thing @@ -41,6 +43,7 @@ public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); private RomyApiFactory apiFactory; private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; + private final Logger logger = LoggerFactory.getLogger(RomyRobotHandlerFactory.class); @Activate public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory, @@ -59,7 +62,11 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { - return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + try { + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + } catch (Exception e) { + logger.error("could not create handler {}", e); + } } return null; From 416d5617cb68a8f26f8a21338b387c2fc66e8d10 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 17:27:12 +0200 Subject: [PATCH 09/45] spotless + unused import removed Signed-off-by: Bernhard Kreuz --- .../romyrobot/internal/api/RomyApi.java | 12 +++--- .../internal/api/RomyApiFactory.java | 28 +++++++------- .../romyrobot/internal/api/RomyApi_v6.java | 37 +++++++++---------- .../romyrobot/internal/romyRobotHandler.java | 16 ++++---- .../internal/romyRobotHandlerFactory.java | 8 ++-- 5 files changed, 49 insertions(+), 52 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 90c8a3e312d3..1c8dcfedd973 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -118,18 +118,18 @@ public interface RomyApi { */ String getAvailableMapsJson(); - /** + /** * * @return a String listing the available maps */ - int getProtocolVersionMajor(); - - /** + int getProtocolVersionMajor(); + + /** * * @return a String listing the available maps */ - int getProtocolVersionMinor(); - + int getProtocolVersionMinor(); + /** * * @param command command to execute diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java index 6dc91d441ac4..56fb39cbf876 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java @@ -36,19 +36,19 @@ public RomyApiFactory(@Reference HttpClientFactory httpClientFactory) { this.httpClient = httpClientFactory.getCommonHttpClient(); } - public RomyApi getHttpApi(RomyRobotConfiguration config) throws Exception { - int version = -1; - RomyApi lowestSupportedApi = new RomyApi_v6(this.httpClient, config); - try { - version = lowestSupportedApi.getFirmwareVersion(); - } catch (Exception exp) { - throw new Exception("Problem fetching the firmware version from RomyRobot: " + exp.getMessage()); - } - // will start to make sense once a breaking API Version > 6 is introduced - if (version >= 6) { - return lowestSupportedApi; - } else { - return lowestSupportedApi; - } + public RomyApi getHttpApi(RomyRobotConfiguration config) throws Exception { + int version = -1; + RomyApi lowestSupportedApi = new RomyApi_v6(this.httpClient, config); + try { + version = lowestSupportedApi.getProtocolVersionMajor(); + } catch (Exception exp) { + throw new Exception("Problem fetching the firmware version from RomyRobot: " + exp.getMessage()); + } + // will start to make sense once a breaking API Version > 6 is introduced + if (version >= 6) { + return lowestSupportedApi; + } else { + return lowestSupportedApi; + } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 26d33791bc1e..6c96408df716 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -36,11 +36,11 @@ public class RomyApi_v6 implements RomyApi { private int rssi; private String strategy; private String suctionMode; - private String selectedMap; - - // that was the newest version when this code was written - private int protocolVersionMajor = 6; - private int protocolVersionMinor = 49; + private String selectedMap; + + // that was the newest version when this code was written + private int protocolVersionMajor = 6; + private int protocolVersionMinor = 49; private HashMap availableMaps = new HashMap(); private static final String CMD_GET_ROBOT_ID = "get/robot_id"; @@ -49,12 +49,10 @@ public class RomyApi_v6 implements RomyApi { private static final String CMD_GET_WIFI_STATUS = "get/wifi_status"; private static final String CMD_GET_POWER_STATUS = "get/power_status"; private static final String CMD_GET_PROTOCOL_VERSION = "get/protocol_version"; - private static final @NonNull String UNKNOWN = "UNKNOWN"; protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - public RomyApi_v6(final @NonNull HttpClient httpClient, - final @NonNull RomyRobotConfiguration config) { + public RomyApi_v6(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { this.config = config; if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { this.hostname = config.hostname; @@ -96,12 +94,11 @@ public void refresh() throws Exception { returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_WIFI_STATUS, null); jsonNode = new ObjectMapper().readTree(returnContent); - rssi = jsonNode.get("rssi").asInt(); - - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); + rssi = jsonNode.get("rssi").asInt(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); protocolVersionMajor = new ObjectMapper().readTree(returnContent).get("version_major").intValue(); protocolVersionMinor = new ObjectMapper().readTree(returnContent).get("version_minor").intValue(); - } private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { @@ -315,13 +312,13 @@ public HashMap getAvailableMaps() { return availableMaps; } - @Override - public int getProtocolVersionMajor() { - return protocolVersionMajor; - } + @Override + public int getProtocolVersionMajor() { + return protocolVersionMajor; + } - @Override - public int getProtocolVersionMinor() { - return protocolVersionMinor; - } + @Override + public int getProtocolVersionMinor() { + return protocolVersionMinor; + } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 237ab4f90432..3151e8b20588 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -76,17 +76,17 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma if (CHANNEL_STRATEGY.equals(channelUID.getId())) { updateState(CHANNEL_STRATEGY, new StringType(command.toString())); try { - getRomyApi().setStrategy(command.toString()); - } catch (Exception e) { - logger.error("error updating strategy: {}", e); - } + getRomyApi().setStrategy(command.toString()); + } catch (Exception e) { + logger.error("error updating strategy: {}", e); + } } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); try { - getRomyApi().setSuctionMode(command.toString()); - } catch (Exception e) { - logger.error("error updating suctionmode: {}", e); - } + getRomyApi().setSuctionMode(command.toString()); + } catch (Exception e) { + logger.error("error updating suctionmode: {}", e); + } } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { updateState(CHANNEL_COMMAND, new StringType(command.toString())); try { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index c3c158b420b7..c049064ffc2a 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -63,10 +63,10 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { try { - return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); - } catch (Exception e) { - logger.error("could not create handler {}", e); - } + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + } catch (Exception e) { + logger.error("could not create handler {}", e); + } } return null; From d282015fbfc5b2a611a4ef2391b55da5fc4d18ac Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Fri, 30 Jun 2023 09:58:18 +0200 Subject: [PATCH 10/45] discovery started Signed-off-by: Manuel Dipolt --- ...ts.java => RomyRobotBindingConstants.java} | 0 ...ation.java => RomyRobotConfiguration.java} | 1 + ...obotHandler.java => RomyRobotHandler.java} | 0 ...tory.java => RomyRobotHandlerFactory.java} | 0 .../RomyRobotMDNSDiscoveryParticipant.java | 81 +++++++++++++++++++ .../resources/OH-INF/thing/thing-types.xml | 10 ++- 6 files changed, 90 insertions(+), 2 deletions(-) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/{romyRobotBindingConstants.java => RomyRobotBindingConstants.java} (100%) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/{romyRobotConfiguration.java => RomyRobotConfiguration.java} (96%) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/{romyRobotHandler.java => RomyRobotHandler.java} (100%) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/{romyRobotHandlerFactory.java => RomyRobotHandlerFactory.java} (100%) create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java similarity index 100% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotConfiguration.java similarity index 96% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotConfiguration.java index a79579a92b08..7ea7f52f9d34 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotConfiguration.java @@ -26,6 +26,7 @@ public class RomyRobotConfiguration { * Sample configuration parameters. Replace with your own. */ public String hostname = ""; + public String password = ""; public int refreshInterval = 600; public int port = 8080; public int timeout = 5; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java similarity index 100% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java similarity index 100% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java new file mode 100644 index 000000000000..b3803b36d058 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal.discovery; + +import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; +import static org.openhab.core.thing.Thing.*; + +import java.util.HashSet; +import java.util.Set; + +import javax.jmdns.ServiceInfo; + +import org.eclipse.jdt.annotation.NonNullByDefault; +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.mdns.MDNSDiscoveryParticipant; +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; + +/** + * This is a discovery participant which finds RomyRobots on the local network + * through their mDNS announcements. + * + * @author Manuel Dipolt - Initial contribution + * + */ +@NonNullByDefault +@Component +public class RomyRobotMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant { + + private final Logger logger = LoggerFactory.getLogger(RomyRobotMDNSDiscoveryParticipant.class); + + @Override + public String getServiceType() { + return "_aicu-http._tcp.local."; + } + + @Override + public Set getSupportedThingTypeUIDs() { + Set supportedThingTypeUIDs = new HashSet<>(); + supportedThingTypeUIDs.add(ROMYROBOT_DEVICE); + return supportedThingTypeUIDs; + } + + @Override + public @Nullable ThingUID getThingUID(ServiceInfo service) { + if (service != null) { + return new ThingUID(ROMYROBOT_DEVICE, service.getName()); + } + return null; + } + + @Override + public @Nullable DiscoveryResult createResult(ServiceInfo service) { + + // logger.error("~~~>>> {})", service.getName()); + + ThingUID thingUID = getThingUID(service); + if (thingUID != null) { + logger.info("Discovered ROMY vacuum cleaner robot: {}", service); + return DiscoveryResultBuilder.create(thingUID).withProperty(PROPERTY_SERIAL_NUMBER, service.getName()) + .withLabel("@text/discovery.bridge.label").withRepresentationProperty(PROPERTY_SERIAL_NUMBER) + .build(); + } + return null; + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index d26e4328af66..a0d95c4d4099 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -28,8 +28,14 @@ network-address - The host name or IP address of the RomyRobot Web API interface. Please take note that you have to first - open the URL in your browser and unlock the HTTP interface with the code you find under the dustbin. + The host name or IP address of your ROMY robot + + + password + + Please take note that the local http interface is locked per default you have to unlock it with the + code + you find under the dustbin. From 131eb0b2090cf305d3854ecc259de5dcb52035fe Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 7 Sep 2023 12:13:36 +0200 Subject: [PATCH 11/45] added to codeowners + clean up bundles/pom.xml Signed-off-by: Manuel Dipolt --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index eb8149bd1b1a..21a86eb5fd90 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -294,7 +294,7 @@ /bundles/org.openhab.binding.rme/ @kgoderis /bundles/org.openhab.binding.robonect/ @reyem /bundles/org.openhab.binding.roku/ @mlobstein -/bundles/org.openhab.binding.romyrobot/ @wzbfyb +/bundles/org.openhab.binding.romyrobot/ @wzbfyb @xeniter /bundles/org.openhab.binding.rotel/ @lolodomo /bundles/org.openhab.binding.russound/ @openhab/add-ons-maintainers /bundles/org.openhab.binding.sagercaster/ @clinique From 5ab17cb954635248792fa5ae1883eb46bff9d3c5 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 7 Sep 2023 14:18:52 +0200 Subject: [PATCH 12/45] increased version Signed-off-by: Manuel Dipolt --- bundles/org.openhab.binding.romyrobot/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.romyrobot/pom.xml b/bundles/org.openhab.binding.romyrobot/pom.xml index ff5583a4f27d..22da51eed713 100644 --- a/bundles/org.openhab.binding.romyrobot/pom.xml +++ b/bundles/org.openhab.binding.romyrobot/pom.xml @@ -7,7 +7,7 @@ org.openhab.addons.bundles org.openhab.addons.reactor.bundles - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT org.openhab.binding.romyrobot From 2d4a59f25d16c4c35e246ddb2d4933e4c5fb1e8c Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 7 Sep 2023 16:34:16 +0200 Subject: [PATCH 13/45] wip Signed-off-by: Manuel Dipolt --- .../internal/RomyRobotBindingConstants.java | 2 +- .../romyrobot/internal/api/RomyApi.java | 6 +++ .../romyrobot/internal/api/RomyApi_v6.java | 23 ++++++--- .../RomyRobotMDNSDiscoveryParticipant.java | 51 ++++++++++++++++--- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java index d7b992cbc3d8..da0207262a42 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java @@ -24,7 +24,7 @@ @NonNullByDefault public class RomyRobotBindingConstants { - private static final String BINDING_ID = "romyrobot"; + private static final String BINDING_ID = "aicu"; // List of all Thing Type UIDs public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "romyrobot"); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 1c8dcfedd973..d806117b65a7 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -40,6 +40,12 @@ public interface RomyApi { */ String getFirmwareVersion(); + /** + * + * @return Firmware Version of robot + */ + String getName(); + /** * * @return Status / Mode robot is currently in diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 6c96408df716..dd3a0975f25c 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -27,6 +27,7 @@ public class RomyApi_v6 implements RomyApi { private @NonNull RomyRobotConfiguration config; protected HttpRequestSender http; private String firmwareVersion = "UNKNOWN"; + private String name; private String mode; private String activePumpVolume; private String charging; @@ -76,17 +77,20 @@ protected String getBaseUrl() { public void refresh() throws Exception { String returnContent; returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); - firmwareVersion = new ObjectMapper().readTree(returnContent).get("firmware").asText(); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + firmwareVersion = jsonNode.get("firmware").asText(); if (firmwareVersion == null) { throw new Exception("There was a problem in the HTTP communication: firmware was empty."); } + name = jsonNode.get("name").asText(); + mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); parseMaps(mapsJson); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); - JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + jsonNode = new ObjectMapper().readTree(returnContent); mode = jsonNode.get("mode").asText(); activePumpVolume = jsonNode.get("active_pump_volume").asText(); charging = jsonNode.get("charging").asText(); @@ -104,7 +108,7 @@ public void refresh() throws Exception { private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { JsonNode node = new ObjectMapper().readTree(jsonString); JsonNode maps = node.get("maps"); - if (maps.isArray()) { + if (!maps.textValue().isBlank() && maps.isArray()) { availableMaps.clear(); for (final JsonNode field : maps) { String value = field.get("map_meta_data").textValue(); @@ -114,9 +118,11 @@ private void parseMaps(String jsonString) throws JsonMappingException, JsonProce availableMaps.put(key, value); } } - } - if (availableMaps.size() == 1 || selectedMap == null) { - selectedMap = availableMaps.values().iterator().next(); + if (availableMaps.size() == 1 || selectedMap == null) { + selectedMap = availableMaps.values().iterator().next(); + } + } else { + logger.warn("ROMY has no maps yet, please start a explore to create one!"); } } @@ -125,6 +131,11 @@ public String getFirmwareVersion() { return firmwareVersion; } + @Override + public String getName() { + return name; + } + @Override public String getModeString() { return mode; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index b3803b36d058..5cdb9f4a6a07 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -22,12 +22,17 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +import org.openhab.binding.romyrobot.internal.api.RomyApi; +import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; 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.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,6 +49,19 @@ public class RomyRobotMDNSDiscoveryParticipant implements MDNSDiscoveryParticipa private final Logger logger = LoggerFactory.getLogger(RomyRobotMDNSDiscoveryParticipant.class); + private RomyApiFactory apiFactory; + // private RomyRobotConfiguration config; + // private RomyApi romyDevice; + // private final HttpClient httpClient; + + @Activate + public RomyRobotMDNSDiscoveryParticipant( + @Reference RomyApiFactory apiFactory /* @Reference HttpClientFactory httpClientFactory */) { + logger.debug("Activating ROMY Discovery service"); + this.apiFactory = apiFactory; + // this.httpClient = httpClientFactory.getCommonHttpClient(); + } + @Override public String getServiceType() { return "_aicu-http._tcp.local."; @@ -58,20 +76,41 @@ public Set getSupportedThingTypeUIDs() { @Override public @Nullable ThingUID getThingUID(ServiceInfo service) { - if (service != null) { - return new ThingUID(ROMYROBOT_DEVICE, service.getName()); - } - return null; + return new ThingUID(ROMYROBOT_DEVICE, service.getName()); } @Override public @Nullable DiscoveryResult createResult(ServiceInfo service) { - // logger.error("~~~>>> {})", service.getName()); - ThingUID thingUID = getThingUID(service); if (thingUID != null) { logger.info("Discovered ROMY vacuum cleaner robot: {}", service); + + // get IP address + String address = ""; + String[] hostAddresses = service.getHostAddresses(); + // logger.info("hostAddresses: {}", hostAddresses); + if ((hostAddresses != null) && (hostAddresses.length > 0)) { + address = hostAddresses[0]; + } + // logger.info("address: {}", address); + if (address.isEmpty()) { + // logger.error("ROMY discovered empty IP via MDNS!"); + return null; + } + + try { + RomyRobotConfiguration config = new RomyRobotConfiguration(); + config.hostname = address; + RomyApi romyDevice = apiFactory.getHttpApi(config); + romyDevice.refresh(); + logger.error("new ROMY discovered: {}", romyDevice.getName()); + } catch (Exception e) { + e.printStackTrace(); + logger.error("Error setting up ROMY api: {}", e.getMessage()); + return null; + } + return DiscoveryResultBuilder.create(thingUID).withProperty(PROPERTY_SERIAL_NUMBER, service.getName()) .withLabel("@text/discovery.bridge.label").withRepresentationProperty(PROPERTY_SERIAL_NUMBER) .build(); From ded9bd29aa6c4456ab1e37936bdbfd7e486a170c Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Mon, 11 Sep 2023 11:29:52 +0200 Subject: [PATCH 14/45] wip Signed-off-by: Manuel Dipolt --- .../RomyRobotMDNSDiscoveryParticipant.java | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 5cdb9f4a6a07..4cb731a91148 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -22,8 +22,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; -import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; @@ -50,16 +48,12 @@ public class RomyRobotMDNSDiscoveryParticipant implements MDNSDiscoveryParticipa private final Logger logger = LoggerFactory.getLogger(RomyRobotMDNSDiscoveryParticipant.class); private RomyApiFactory apiFactory; - // private RomyRobotConfiguration config; - // private RomyApi romyDevice; - // private final HttpClient httpClient; @Activate public RomyRobotMDNSDiscoveryParticipant( @Reference RomyApiFactory apiFactory /* @Reference HttpClientFactory httpClientFactory */) { logger.debug("Activating ROMY Discovery service"); this.apiFactory = apiFactory; - // this.httpClient = httpClientFactory.getCommonHttpClient(); } @Override @@ -82,39 +76,47 @@ public Set getSupportedThingTypeUIDs() { @Override public @Nullable DiscoveryResult createResult(ServiceInfo service) { - ThingUID thingUID = getThingUID(service); - if (thingUID != null) { - logger.info("Discovered ROMY vacuum cleaner robot: {}", service); - - // get IP address - String address = ""; - String[] hostAddresses = service.getHostAddresses(); - // logger.info("hostAddresses: {}", hostAddresses); - if ((hostAddresses != null) && (hostAddresses.length > 0)) { - address = hostAddresses[0]; - } - // logger.info("address: {}", address); - if (address.isEmpty()) { - // logger.error("ROMY discovered empty IP via MDNS!"); - return null; - } - - try { - RomyRobotConfiguration config = new RomyRobotConfiguration(); - config.hostname = address; - RomyApi romyDevice = apiFactory.getHttpApi(config); - romyDevice.refresh(); - logger.error("new ROMY discovered: {}", romyDevice.getName()); - } catch (Exception e) { - e.printStackTrace(); - logger.error("Error setting up ROMY api: {}", e.getMessage()); - return null; - } - - return DiscoveryResultBuilder.create(thingUID).withProperty(PROPERTY_SERIAL_NUMBER, service.getName()) - .withLabel("@text/discovery.bridge.label").withRepresentationProperty(PROPERTY_SERIAL_NUMBER) - .build(); + final ThingUID uid = getThingUID(service); + if (uid == null) { + logger.error("uid is null!"); + return null; } - return null; + + logger.info("Discovered ROMY vacuum cleaner robot: {}", service); + + // get IP address + String address = ""; + String robotname = ""; + String[] hostAddresses = service.getHostAddresses(); + + logger.info("hostAddresses: {}", hostAddresses); + + if ((hostAddresses != null) && (hostAddresses.length > 0)) { + address = hostAddresses[0]; + } + + /* + * if (address.isEmpty()) { + * logger.error("ROMY discovered empty IP via MDNS!"); + * return null; + * } + * + * try { + * RomyRobotConfiguration config = new RomyRobotConfiguration(); + * config.hostname = address; + * RomyApi romyDevice = apiFactory.getHttpApi(config); + * romyDevice.refresh(); + * robotname = romyDevice.getName(); + * logger.error("new ROMY discovered: {}", robotname); + * } catch (Exception e) { + * e.printStackTrace(); + * logger.error("Error setting up ROMY api: {}", e.getMessage()); + * return null; + * } + */ + + logger.error("blub123"); + return DiscoveryResultBuilder.create(uid).withProperty(PROPERTY_SERIAL_NUMBER, service.getName()) + .withLabel("robotname").withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build(); } } From eb8914b16c90f455c62ae66a61ea437041333623 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Mon, 18 Sep 2023 17:05:12 +0200 Subject: [PATCH 15/45] wip discovery Signed-off-by: Manuel Dipolt --- .../internal/RomyRobotBindingConstants.java | 5 +- .../romyrobot/internal/api/RomyApi_v6.java | 2 +- .../RomyRobotMDNSDiscoveryParticipant.java | 65 +++++++++++-------- .../resources/OH-INF/thing/thing-types.xml | 5 +- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java index da0207262a42..3e9abd315c60 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java @@ -24,13 +24,12 @@ @NonNullByDefault public class RomyRobotBindingConstants { - private static final String BINDING_ID = "aicu"; + private static final String BINDING_ID = "romyrobot"; // List of all Thing Type UIDs - public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "romyrobot"); + public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "aicu"); // List of all Channel ids - public static final String CHANNEL_FW_VERSION = "fwversion"; public static final String CHANNEL_COMMAND = "command"; public static final String CHANNEL_MODE = "mode"; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index dd3a0975f25c..c65c45ab432c 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -108,7 +108,7 @@ public void refresh() throws Exception { private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { JsonNode node = new ObjectMapper().readTree(jsonString); JsonNode maps = node.get("maps"); - if (!maps.textValue().isBlank() && maps.isArray()) { + if (maps != null && maps.textValue() != null && !maps.textValue().isBlank() && maps.isArray()) { availableMaps.clear(); for (final JsonNode field : maps) { String value = field.get("map_meta_data").textValue(); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 4cb731a91148..d42132ac816d 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -22,6 +22,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; @@ -86,37 +88,46 @@ public Set getSupportedThingTypeUIDs() { // get IP address String address = ""; - String robotname = ""; + String robotName = ""; + String robotLabel = ""; + String robotUniqeId = ""; String[] hostAddresses = service.getHostAddresses(); + logger.debug("hostAddresses: {}", hostAddresses); - logger.info("hostAddresses: {}", hostAddresses); + if ((hostAddresses == null) || (hostAddresses.length == 0)) { + logger.error("hostAddresses is null!"); + return null; + } - if ((hostAddresses != null) && (hostAddresses.length > 0)) { - address = hostAddresses[0]; + robotUniqeId = service.getName(); + if ((hostAddresses == null) || (hostAddresses.length == 0)) { + logger.error("hostAddresses is null!"); + return null; } - /* - * if (address.isEmpty()) { - * logger.error("ROMY discovered empty IP via MDNS!"); - * return null; - * } - * - * try { - * RomyRobotConfiguration config = new RomyRobotConfiguration(); - * config.hostname = address; - * RomyApi romyDevice = apiFactory.getHttpApi(config); - * romyDevice.refresh(); - * robotname = romyDevice.getName(); - * logger.error("new ROMY discovered: {}", robotname); - * } catch (Exception e) { - * e.printStackTrace(); - * logger.error("Error setting up ROMY api: {}", e.getMessage()); - * return null; - * } - */ - - logger.error("blub123"); - return DiscoveryResultBuilder.create(uid).withProperty(PROPERTY_SERIAL_NUMBER, service.getName()) - .withLabel("robotname").withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build(); + address = hostAddresses[0]; + logger.debug("address: {}", address); + + try { + RomyRobotConfiguration config = new RomyRobotConfiguration(); + config.hostname = address; + RomyApi romyDevice = apiFactory.getHttpApi(config); + romyDevice.refresh(); + robotName = romyDevice.getName(); + logger.debug("New ROMY with the name:{} discovered: {}", robotName); + } catch (Exception e) { + e.printStackTrace(); + logger.error("Error setting up ROMY api: {}", e.getMessage()); + return null; + } + + robotLabel = String.format("%s (%s)", robotName, address); + + DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperty(PROPERTY_SERIAL_NUMBER, robotUniqeId) + .withLabel(robotLabel).withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build(); + + logger.debug("DiscoveryResult: {}", result); + + return result; } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index a0d95c4d4099..f3cbcb96bdf7 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -4,7 +4,7 @@ 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"> - + A RomyRobot vacuum robot CleaningRobot @@ -34,8 +34,7 @@ password Please take note that the local http interface is locked per default you have to unlock it with the - code - you find under the dustbin. + code you find under the dustbin. From 637d050262f658e9af9b1e40bbd26dda4e9f631a Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Mon, 18 Sep 2023 18:11:24 +0200 Subject: [PATCH 16/45] wip hostname discovery Signed-off-by: Manuel Dipolt --- .../openhab/binding/romyrobot/internal/RomyRobotHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index 3151e8b20588..a68edde01739 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -143,6 +143,10 @@ public void updateMapsList(HashMap maps) { private RomyApi setupAPI(RomyApiFactory apiFactory) throws Exception { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); + // hack: + logger.error("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", + config.hostname, config.port, config.refreshInterval, config.timeout); + return apiFactory.getHttpApi(config); } From fa082dae99f4becc40c90fb7809af69f0a0bb8ed Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Tue, 19 Sep 2023 12:40:17 +0200 Subject: [PATCH 17/45] wip hostname discovery Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/api/RomyApi.java | 23 +++++++++ .../romyrobot/internal/api/RomyApi_v6.java | 47 +++++++++++++++---- .../RomyRobotMDNSDiscoveryParticipant.java | 7 ++- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index d806117b65a7..37398bbf82c4 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -23,6 +23,29 @@ */ public interface RomyApi { + + /** + * get robots firmwware version and name + * is available when robots http interface is locked + * + * @throws Exception + * + * @throws CommunicationApiException + * @throws UnauthorizedApiException + */ + void refresh_id() throws Exception; + + /** + * get robots api protocol version + * is available when robots http interface is locked + * + * @throws Exception + * + * @throws CommunicationApiException + * @throws UnauthorizedApiException + */ + void refresh_protocol_version() throws Exception; + /** * Sends all the GET requests and stores/cache the responses for use by the API to prevent the need for multiple * requests. diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index c65c45ab432c..c2bfab7ef118 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -74,23 +74,45 @@ protected String getBaseUrl() { } @Override - public void refresh() throws Exception { - String returnContent; - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + public void refresh_id() throws Exception { + String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); JsonNode jsonNode = new ObjectMapper().readTree(returnContent); firmwareVersion = jsonNode.get("firmware").asText(); if (firmwareVersion == null) { throw new Exception("There was a problem in the HTTP communication: firmware was empty."); } name = jsonNode.get("name").asText(); + } - mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); - parseMaps(mapsJson); - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); + @Override + public void refresh_protocol_version() throws Exception { + String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + firmwareVersion = jsonNode.get("firmware").asText(); + if (firmwareVersion == null) { + throw new Exception("There was a problem in the HTTP communication: firmware was empty."); + } + name = jsonNode.get("name").asText(); + } + + @Override + public void refresh() throws Exception { + /* + * String returnContent; + * returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + * JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + * firmwareVersion = jsonNode.get("firmware").asText(); + * if (firmwareVersion == null) { + * throw new Exception("There was a problem in the HTTP communication: firmware was empty."); + * } + * name = jsonNode.get("name").asText(); + */ + + String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); - jsonNode = new ObjectMapper().readTree(returnContent); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); mode = jsonNode.get("mode").asText(); activePumpVolume = jsonNode.get("active_pump_volume").asText(); charging = jsonNode.get("charging").asText(); @@ -100,9 +122,14 @@ public void refresh() throws Exception { jsonNode = new ObjectMapper().readTree(returnContent); rssi = jsonNode.get("rssi").asInt(); - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); - protocolVersionMajor = new ObjectMapper().readTree(returnContent).get("version_major").intValue(); - protocolVersionMinor = new ObjectMapper().readTree(returnContent).get("version_minor").intValue(); + mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + parseMaps(mapsJson); + + /* + * returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); + * protocolVersionMajor = new ObjectMapper().readTree(returnContent).get("version_major").intValue(); + * protocolVersionMinor = new ObjectMapper().readTree(returnContent).get("version_minor").intValue(); + */ } private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index d42132ac816d..3653b4a130f6 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -112,7 +112,9 @@ public Set getSupportedThingTypeUIDs() { RomyRobotConfiguration config = new RomyRobotConfiguration(); config.hostname = address; RomyApi romyDevice = apiFactory.getHttpApi(config); - romyDevice.refresh(); + // romyDevice.refresh(); + romyDevice.refresh_id(); + romyDevice.refresh_protocol_version(); robotName = romyDevice.getName(); logger.debug("New ROMY with the name:{} discovered: {}", robotName); } catch (Exception e) { @@ -124,7 +126,8 @@ public Set getSupportedThingTypeUIDs() { robotLabel = String.format("%s (%s)", robotName, address); DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperty(PROPERTY_SERIAL_NUMBER, robotUniqeId) - .withLabel(robotLabel).withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build(); + .withProperty("hostname", address).withLabel(robotLabel) + .withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build(); logger.debug("DiscoveryResult: {}", result); From 467440b1d70f1a67b4e481fad51cb496cab09658 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 09:18:18 +0200 Subject: [PATCH 18/45] initial commit of skeleton Signed-off-by: Bernhard Kreuz --- .../internal/romyRobotBindingConstants.java | 34 ++++++ .../internal/romyRobotConfiguration.java | 31 ++++++ .../romyrobot/internal/romyRobotHandler.java | 104 ++++++++++++++++++ .../internal/romyRobotHandlerFactory.java | 55 +++++++++ 4 files changed, 224 insertions(+) create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java new file mode 100644 index 000000000000..11441de67f11 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.thing.ThingTypeUID; + +/** + * The {@link romyRobotBindingConstants} class defines common constants, which are + * used across the whole binding. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotBindingConstants { + + private static final String BINDING_ID = "romyrobot"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_SAMPLE = new ThingTypeUID(BINDING_ID, "sample"); + + // List of all Channel ids + public static final String CHANNEL_1 = "channel1"; +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java new file mode 100644 index 000000000000..4f9d5fe10aa9 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link romyRobotConfiguration} class contains fields mapping thing configuration parameters. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotConfiguration { + + /** + * Sample configuration parameters. Replace with your own. + */ + public String hostname = ""; + public String password = ""; + public int refreshInterval = 600; +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java new file mode 100644 index 000000000000..5a3bea157a3a --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +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 romyRobotHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +public class romyRobotHandler extends BaseThingHandler { + + private final Logger logger = LoggerFactory.getLogger(romyRobotHandler.class); + + private @Nullable romyRobotConfiguration config; + + public romyRobotHandler(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() { + config = getConfigAs(romyRobotConfiguration.class); + + // TODO: Initialize the handler. + // The framework requires you to return from this method quickly, i.e. any network access must be done in + // the background initialization below. + // 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. + + // 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); + + // Example for background initialization: + scheduler.execute(() -> { + boolean thingReachable = true; // + // when done do: + if (thingReachable) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.OFFLINE); + } + }); + + // These logging types should be primarily used by bindings + // logger.trace("Example trace message"); + // logger.debug("Example debug message"); + // logger.warn("Example warn message"); + // + // Logging to INFO should be avoided normally. + // See https://www.openhab.org/docs/developer/guidelines.html#f-logging + + // Note: When initialization can NOT be done set the status with more details for further + // analysis. See also class ThingStatusDetail for all available status details. + // Add a description to give user information to understand why thing does not work as expected. E.g. + // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + // "Can not access device as username and/or password are invalid"); + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java new file mode 100644 index 000000000000..2e510bf57ee9 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.romyrobot.internal; + +import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; + +import java.util.Set; + +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 romyRobotHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Bernhard Kreuz - Initial contribution + */ +@NonNullByDefault +@Component(configurationPid = "binding.romyrobot", service = ThingHandlerFactory.class) +public class romyRobotHandlerFactory extends BaseThingHandlerFactory { + + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SAMPLE); + + @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_SAMPLE.equals(thingTypeUID)) { + return new romyRobotHandler(thing); + } + + return null; + } +} From dfcc8f16642ec983720f99f9cf4fb7851a461f16 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 10:00:52 +0200 Subject: [PATCH 19/45] defined initial thing types Signed-off-by: Bernhard Kreuz --- .../src/main/resources/OH-INF/thing/thing-types.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index f3cbcb96bdf7..17792fedb3fe 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -54,6 +54,11 @@ 5 true + + + Specifies the connection timeout in seconds. + 5 + From 313a8a42ed9d0cdafe92843d27ae9678c357c034 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 14:12:58 +0200 Subject: [PATCH 20/45] initial implementation to read most channels Signed-off-by: Bernhard Kreuz --- .../RomyApiAGON_1_2_4_release_3_14_3068.java | 240 ++++++++++++++++++ .../internal/romyRobotBindingConstants.java | 17 +- .../internal/romyRobotConfiguration.java | 7 +- .../romyrobot/internal/romyRobotHandler.java | 114 +++++---- .../internal/romyRobotHandlerFactory.java | 21 +- 5 files changed, 344 insertions(+), 55 deletions(-) create mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java new file mode 100644 index 000000000000..76eb1c6a0273 --- /dev/null +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -0,0 +1,240 @@ +package org.openhab.binding.romyrobot.internal.api; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNull; +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.romyrobot.internal.RomyRobotConfiguration; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { + + private @NonNull String hostname; + private @NonNull RomyRobotConfiguration config; + protected HttpRequestSender http; + private String firmwareVersion = "UNKNOWN"; + private String mode; + private String activePumpVolume; + private String charging; + private int batteryLevel; + private String powerStatus; + private String maps; + private int rssi; + private String strategy; + private String suctionMode; + private static final String CMD_GET_ROBOT_ID = "get/robot_id"; + private static final String CMD_GET_STATUS = "get/status"; + private static final String CMD_GET_MAPS = "get/maps"; + private static final String CMD_GET_WIFI_STATUS = "get/wifi_status"; + private static final String CMD_GET_POWER_STATUS = "get/power_status"; + private static final @NonNull String UNKNOWN = "UNKNOWN"; + + public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, + final @NonNull RomyRobotConfiguration config) { + this.config = config; + if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { + this.hostname = config.hostname; + } else { + this.hostname = "http://" + config.hostname; + } + + this.http = new HttpRequestSender(httpClient); + } + + /** + * Returns the hostname and port formatted URL as a String. + * + * @return String representation of the OpenSprinkler API URL. + */ + protected String getBaseUrl() { + return hostname + ":" + config.port + "/"; + } + + @Override + public void refresh() throws Exception { + String returnContent; + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + firmwareVersion = new ObjectMapper().readTree(returnContent).get("firmware").asText(); + if (firmwareVersion == null) { + throw new Exception("There was a problem in the HTTP communication: firmware was empty."); + } + maps = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); + powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + mode = jsonNode.get("mode").asText(); + activePumpVolume = jsonNode.get("active_pump_volume").asText(); + charging = jsonNode.get("charging").asText(); + batteryLevel = jsonNode.get("battery_level").asInt(); + + returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_WIFI_STATUS, null); + jsonNode = new ObjectMapper().readTree(returnContent); + rssi = jsonNode.get("rssi").asInt(); + } + + @Override + public String getFirmwareVersion() { + return firmwareVersion; + } + + @Override + public String getModeString() { + return mode; + } + + @Override + public String getActivePumpVolume() { + return activePumpVolume; + } + + @Override + public void setActivePumpVolume(@NonNull String volume) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'setActivePumpVolume'"); + } + + @Override + public String getStrategy() { + return strategy; + } + + @Override + public void setStrategy(@NonNull String strategy) { + this.strategy = strategy; + } + + @Override + public String getSuctionMode() { + return suctionMode; + } + + @Override + public void setSuctionMode(@NonNull String suctionMode) { + this.suctionMode = suctionMode; + } + + @Override + public int getBatteryLevel() { + return batteryLevel; + } + + @Override + public String getChargingStatus() { + return charging; + } + + @Override + public int getRssi() { + return rssi; + } + + @Override + public String getPowerStatus() { + return powerStatus; + } + + @Override + public String getAvailableMaps() { + return maps; + } + + /** + * This class contains helper methods for communicating HTTP GET and HTTP POST + * requests. + * + * @author Chris Graham - Initial contribution + * @author Florian Schmidt - Reduce visibility of Http communication to Api + */ + protected class HttpRequestSender { + private static final int HTTP_OK_CODE = 200; + private static final String USER_AGENT = "Mozilla/5.0"; + + private final HttpClient httpClient; + + public HttpRequestSender(HttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Given a URL and a set parameters, send a HTTP GET request to the URL location + * created by the URL and parameters. + * + * @param url The URL to send a GET request to. + * @param urlParameters List of parameters to use in the URL for the GET + * request. Null if no parameters. + * @return String contents of the response for the GET request. + * @throws Exception + */ + public String sendHttpGet(String url, @Nullable String urlParameters) throws Exception { + String location = null; + if (urlParameters != null) { + location = url + "?" + urlParameters; + } else { + location = url; + } + ContentResponse response; + try { + response = withGeneralProperties(httpClient.newRequest(location)) + .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); + } catch (Exception e) { + throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + } + if (response.getStatus() != HTTP_OK_CODE) { + throw new Exception( + "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); + } + String content = response.getContentAsString(); + if ("{\"result\":2}".equals(content)) { + throw new Exception("Unauthorized, check your robot was unlocked"); + } + return content; + } + + private Request withGeneralProperties(Request request) { + // TODO: request header configuration + /* + * request.header(HttpHeader.USER_AGENT, USER_AGENT); + * if (!config.basicUsername.isEmpty() && !config.basicPassword.isEmpty()) { + * String encoded = Base64.getEncoder().encodeToString( + * (config.basicUsername + ":" + config.basicPassword).getBytes(StandardCharsets.UTF_8)); + * request.header(HttpHeader.AUTHORIZATION, "Basic " + encoded); + * } + */ + return request; + } + + /** + * Given a URL and a set parameters, send a HTTP POST request to the URL + * location created by the URL and parameters. + * + * @param url The URL to send a POST request to. + * @param urlParameters List of parameters to use in the URL for the POST + * request. Null if no parameters. + * @return String contents of the response for the POST request. + * @throws Exception + */ + public String sendHttpPost(String url, String urlParameters) throws Exception { + ContentResponse response; + try { + response = withGeneralProperties(httpClient.newRequest(url)).timeout(config.timeout, TimeUnit.SECONDS) + .method(HttpMethod.POST).content(new StringContentProvider(urlParameters)).send(); + } catch (Exception e) { + throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + } + if (response.getStatus() != HTTP_OK_CODE) { + throw new Exception( + "Error sending HTTP POST request to " + url + ". Got response code: " + response.getStatus()); + } + return response.getContentAsString(); + } + } +} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index 11441de67f11..332f0d1ca315 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -22,13 +22,24 @@ * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotBindingConstants { +public class RomyRobotBindingConstants { private static final String BINDING_ID = "romyrobot"; // List of all Thing Type UIDs - public static final ThingTypeUID THING_TYPE_SAMPLE = new ThingTypeUID(BINDING_ID, "sample"); + public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "romyrobot"); // List of all Channel ids - public static final String CHANNEL_1 = "channel1"; + + public static final String CHANNEL_FW_VERSION = "fwversion"; + public static final String CHANNEL_COMMAND = "command"; + public static final String CHANNEL_MODE = "mode"; + public static final String CHANNEL_ACTIVE_PUMP_VOLUME = "activepumpvolume"; + public static final String CHANNEL_STRATEGY = "strategy"; + public static final String CHANNEL_SUCTION_MODE = "suctionmode"; + public static final String CHANNEL_BATTERY = "battery"; + public static final String CHANNEL_CHARGING = "charging"; + public static final String CHANNEL_RSSI = "rssi"; + public static final String CHANNEL_POWER_STATUS = "powerstatus"; + public static final String CHANNEL_AVAILABLE_MAPS = "availablemaps"; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java index 4f9d5fe10aa9..a79579a92b08 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java @@ -15,17 +15,18 @@ import org.eclipse.jdt.annotation.NonNullByDefault; /** - * The {@link romyRobotConfiguration} class contains fields mapping thing configuration parameters. + * The {@link RomyRobotConfiguration} class contains fields mapping thing configuration parameters. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotConfiguration { +public class RomyRobotConfiguration { /** * Sample configuration parameters. Replace with your own. */ public String hostname = ""; - public String password = ""; public int refreshInterval = 600; + public int port = 8080; + public int timeout = 5; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 5a3bea157a3a..1d6cc20ef536 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -12,13 +12,25 @@ */ package org.openhab.binding.romyrobot.internal; -import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; +import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; +import static org.openhab.core.library.unit.Units.PERCENT; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.validation.constraints.NotNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.api.RomyApi; +import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; +import org.openhab.core.library.types.DecimalType; +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; @@ -26,25 +38,30 @@ import org.slf4j.LoggerFactory; /** - * The {@link romyRobotHandler} is responsible for handling commands, which are + * The {@link RomyRobotHandler} is responsible for handling commands, which are * sent to one of the channels. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault -public class romyRobotHandler extends BaseThingHandler { +public class RomyRobotHandler extends BaseThingHandler { - private final Logger logger = LoggerFactory.getLogger(romyRobotHandler.class); + private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); - private @Nullable romyRobotConfiguration config; + private @NotNull RomyRobotConfiguration config; + private @Nullable ScheduledFuture pollingJob; + private @Nullable RomyApi romyDevice; + private @Nullable RomyApiFactory apiFactory; - public romyRobotHandler(Thing thing) { + public RomyRobotHandler(Thing thing, RomyApiFactory apiFactory) { super(thing); + this.apiFactory = apiFactory; + config = getConfigAs(RomyRobotConfiguration.class); } @Override public void handleCommand(ChannelUID channelUID, Command command) { - if (CHANNEL_1.equals(channelUID.getId())) { + if (CHANNEL_FW_VERSION.equals(channelUID.getId())) { if (command instanceof RefreshType) { // TODO: handle data refresh } @@ -60,45 +77,56 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void initialize() { - config = getConfigAs(romyRobotConfiguration.class); - - // TODO: Initialize the handler. - // The framework requires you to return from this method quickly, i.e. any network access must be done in - // the background initialization below. - // 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. - - // 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. + config = getConfigAs(RomyRobotConfiguration.class); updateStatus(ThingStatus.UNKNOWN); + pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); + } - // Example for background initialization: - scheduler.execute(() -> { - boolean thingReachable = true; // - // when done do: - if (thingReachable) { + public void refreshVacuum() { + RomyApi localApi = romyDevice; + if (localApi == null) { + setupAPI(); + localApi = romyDevice; + } + if (localApi != null) { + try { + localApi.refresh(); updateStatus(ThingStatus.ONLINE); - } else { - updateStatus(ThingStatus.OFFLINE); + this.updateChannels(); + + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); } - }); - - // These logging types should be primarily used by bindings - // logger.trace("Example trace message"); - // logger.debug("Example debug message"); - // logger.warn("Example warn message"); - // - // Logging to INFO should be avoided normally. - // See https://www.openhab.org/docs/developer/guidelines.html#f-logging - - // Note: When initialization can NOT be done set the status with more details for further - // analysis. See also class ThingStatusDetail for all available status details. - // Add a description to give user information to understand why thing does not work as expected. E.g. - // updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - // "Can not access device as username and/or password are invalid"); + } + } + + private void updateChannels() { + if (romyDevice != null) { + updateState(CHANNEL_FW_VERSION, StringType.valueOf(romyDevice.getFirmwareVersion())); + updateState(CHANNEL_MODE, StringType.valueOf(romyDevice.getModeString())); + updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(romyDevice.getActivePumpVolume())); + updateState(CHANNEL_BATTERY, QuantityType.valueOf(romyDevice.getBatteryLevel(), PERCENT)); + updateState(CHANNEL_CHARGING, StringType.valueOf(romyDevice.getChargingStatus())); + updateState(CHANNEL_POWER_STATUS, StringType.valueOf(romyDevice.getPowerStatus())); + updateState(CHANNEL_RSSI, new DecimalType(romyDevice.getRssi())); + updateState(CHANNEL_STRATEGY, StringType.valueOf(romyDevice.getStrategy())); + updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(romyDevice.getSuctionMode())); + updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(romyDevice.getAvailableMaps())); + } + } + + private void setupAPI() { + logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", + config.hostname, config.port, config.refreshInterval, config.timeout); + try { + romyDevice = apiFactory.getHttpApi(config); + RomyApi localApi = romyDevice; + + } catch (Exception exp) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not create an API connection to RomyRobot. Error received: " + exp); + return; + } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index 2e510bf57ee9..30d7a84b3d11 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -12,30 +12,39 @@ */ package org.openhab.binding.romyrobot.internal; -import static org.openhab.binding.romyrobot.internal.romyRobotBindingConstants.*; +import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.ROMYROBOT_DEVICE; import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; 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 romyRobotHandlerFactory} is responsible for creating things and thing + * The {@link RomyRobotHandlerFactory} is responsible for creating things and thing * handlers. * * @author Bernhard Kreuz - Initial contribution */ @NonNullByDefault @Component(configurationPid = "binding.romyrobot", service = ThingHandlerFactory.class) -public class romyRobotHandlerFactory extends BaseThingHandlerFactory { +public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { - private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SAMPLE); + private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); + private RomyApiFactory apiFactory; + + @Activate + public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory) { + this.apiFactory = apiFactory; + } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -46,8 +55,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (THING_TYPE_SAMPLE.equals(thingTypeUID)) { - return new romyRobotHandler(thing); + if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { + return new RomyRobotHandler(thing, apiFactory); } return null; From b5d3584db9a22108c4147bb70fe4645a5bb37822 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Thu, 25 May 2023 14:25:42 +0200 Subject: [PATCH 21/45] fixed notnull warnings Signed-off-by: Bernhard Kreuz --- .../romyrobot/internal/romyRobotHandler.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 1d6cc20ef536..100f238d72a0 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -45,15 +45,14 @@ */ @NonNullByDefault public class RomyRobotHandler extends BaseThingHandler { - private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); private @NotNull RomyRobotConfiguration config; private @Nullable ScheduledFuture pollingJob; private @Nullable RomyApi romyDevice; - private @Nullable RomyApiFactory apiFactory; + private @NotNull RomyApiFactory apiFactory; - public RomyRobotHandler(Thing thing, RomyApiFactory apiFactory) { + public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory) { super(thing); this.apiFactory = apiFactory; config = getConfigAs(RomyRobotConfiguration.class); @@ -82,17 +81,18 @@ public void initialize() { pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); } - public void refreshVacuum() { + public void refreshVacuum() { + RomyApiFactory apiFactory = getApiFactory(); RomyApi localApi = romyDevice; if (localApi == null) { - setupAPI(); + setupAPI(apiFactory); localApi = romyDevice; } if (localApi != null) { try { localApi.refresh(); updateStatus(ThingStatus.ONLINE); - this.updateChannels(); + this.updateChannels(localApi); } catch (Exception e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, @@ -101,27 +101,30 @@ public void refreshVacuum() { } } - private void updateChannels() { + private RomyApiFactory getApiFactory() { + return apiFactory; + } + + private void updateChannels(RomyApi device) { if (romyDevice != null) { - updateState(CHANNEL_FW_VERSION, StringType.valueOf(romyDevice.getFirmwareVersion())); - updateState(CHANNEL_MODE, StringType.valueOf(romyDevice.getModeString())); - updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(romyDevice.getActivePumpVolume())); - updateState(CHANNEL_BATTERY, QuantityType.valueOf(romyDevice.getBatteryLevel(), PERCENT)); - updateState(CHANNEL_CHARGING, StringType.valueOf(romyDevice.getChargingStatus())); - updateState(CHANNEL_POWER_STATUS, StringType.valueOf(romyDevice.getPowerStatus())); - updateState(CHANNEL_RSSI, new DecimalType(romyDevice.getRssi())); - updateState(CHANNEL_STRATEGY, StringType.valueOf(romyDevice.getStrategy())); - updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(romyDevice.getSuctionMode())); - updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(romyDevice.getAvailableMaps())); + updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); + updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); + updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); + updateState(CHANNEL_BATTERY, QuantityType.valueOf(device.getBatteryLevel(), PERCENT)); + updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); + updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); + updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); + updateState(CHANNEL_STRATEGY, StringType.valueOf(device.getStrategy())); + updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(device.getSuctionMode())); + updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(device.getAvailableMaps())); } } - private void setupAPI() { + private void setupAPI(RomyApiFactory apiFactory) { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); try { romyDevice = apiFactory.getHttpApi(config); - RomyApi localApi = romyDevice; } catch (Exception exp) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, From 4e32908c2b13843958c9376cefec68716f88f3bb Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 14:32:57 +0200 Subject: [PATCH 22/45] implemented clean all, start, continue, go_home and stop. implemented loading of maps Signed-off-by: Bernhard Kreuz --- .../RomyApiAGON_1_2_4_release_3_14_3068.java | 84 ++++++++++-- .../internal/romyRobotBindingConstants.java | 3 +- .../romyrobot/internal/romyRobotHandler.java | 125 +++++++++++------- .../internal/romyRobotHandlerFactory.java | 7 +- .../resources/OH-INF/thing/thing-types.xml | 1 + 5 files changed, 158 insertions(+), 62 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java index 76eb1c6a0273..174eaefb221f 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -1,5 +1,8 @@ package org.openhab.binding.romyrobot.internal.api; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNull; @@ -10,7 +13,11 @@ import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -25,10 +32,12 @@ public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { private String charging; private int batteryLevel; private String powerStatus; - private String maps; + private String mapsJson; private int rssi; private String strategy; private String suctionMode; + private String selectedMap; + private HashMap availableMaps = new HashMap(); private static final String CMD_GET_ROBOT_ID = "get/robot_id"; private static final String CMD_GET_STATUS = "get/status"; private static final String CMD_GET_MAPS = "get/maps"; @@ -36,6 +45,8 @@ public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { private static final String CMD_GET_POWER_STATUS = "get/power_status"; private static final @NonNull String UNKNOWN = "UNKNOWN"; + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { this.config = config; @@ -65,7 +76,8 @@ public void refresh() throws Exception { if (firmwareVersion == null) { throw new Exception("There was a problem in the HTTP communication: firmware was empty."); } - maps = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); + parseMaps(mapsJson); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); @@ -81,6 +93,25 @@ public void refresh() throws Exception { rssi = jsonNode.get("rssi").asInt(); } + private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { + JsonNode node = new ObjectMapper().readTree(jsonString); + JsonNode maps = node.get("maps"); + if (maps.isArray()) { + availableMaps.clear(); + for (final JsonNode field : maps) { + String key = field.get("map_meta_data").textValue(); + String value = field.get("map_id").asInt() + ""; + String permanentFlag = field.get("permanent_flag").textValue(); + if ("true".equalsIgnoreCase(permanentFlag)) { + availableMaps.put(key, value); + } + } + } + if (availableMaps.size() == 1 || selectedMap == null) { + selectedMap = availableMaps.values().iterator().next(); + } + } + @Override public String getFirmwareVersion() { return firmwareVersion; @@ -97,9 +128,8 @@ public String getActivePumpVolume() { } @Override - public void setActivePumpVolume(@NonNull String volume) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'setActivePumpVolume'"); + public void setActivePumpVolume(String volume) { + this.activePumpVolume = volume; } @Override @@ -108,7 +138,7 @@ public String getStrategy() { } @Override - public void setStrategy(@NonNull String strategy) { + public void setStrategy(String strategy) { this.strategy = strategy; } @@ -118,7 +148,7 @@ public String getSuctionMode() { } @Override - public void setSuctionMode(@NonNull String suctionMode) { + public void setSuctionMode(String suctionMode) { this.suctionMode = suctionMode; } @@ -143,8 +173,8 @@ public String getPowerStatus() { } @Override - public String getAvailableMaps() { - return maps; + public String getAvailableMapsJson() { + return mapsJson; } /** @@ -237,4 +267,40 @@ public String sendHttpPost(String url, String urlParameters) throws Exception { return response.getContentAsString(); } } + + @Override + public void executeCommand(String command) throws Exception { + if ("REFRESH".equalsIgnoreCase(command)) { + return; + } + // String query = "/$" + command; + String query = null; + List params = new ArrayList(); + if ("clean_start_or_continue".equalsIgnoreCase(command) || "clean_all".equalsIgnoreCase(command) + || "clean_spot".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { + if (suctionMode != null && !"REFRESH".equals(suctionMode)) { + params.add("cleaning_parameter_set=" + suctionMode); + } + if (strategy != null && !"REFRESH".equals(strategy)) { + params.add("cleaning_strategy_mode=" + strategy); + + } + if (activePumpVolume != null) { + params.add("pump_volume=" + activePumpVolume); + } + if (params.size() > 0) { + query = String.join("&", params); + } + } else if ("redo_explore".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { + params.add("map_id" + selectedMap); + } + String url = getBaseUrl() + "set/" + command; + logger.info("executing RomyRobot command: {} at url {}", query, url); + http.sendHttpGet(url, query); + } + + @Override + public HashMap getAvailableMaps() { + return availableMaps; + } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index 332f0d1ca315..f44f78988320 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -41,5 +41,6 @@ public class RomyRobotBindingConstants { public static final String CHANNEL_CHARGING = "charging"; public static final String CHANNEL_RSSI = "rssi"; public static final String CHANNEL_POWER_STATUS = "powerstatus"; - public static final String CHANNEL_AVAILABLE_MAPS = "availablemaps"; + public static final String CHANNEL_SELECTED_MAP = "seletedmap"; + public static final String CHANNEL_AVAILABLE_MAPS_JSON = "availablemapsjson"; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 100f238d72a0..ac431b89ba30 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -15,13 +15,14 @@ import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; import static org.openhab.core.library.unit.Units.PERCENT; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import javax.validation.constraints.NotNull; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.library.types.DecimalType; @@ -34,6 +35,7 @@ import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; +import org.openhab.core.types.StateOption; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,34 +45,47 @@ * * @author Bernhard Kreuz - Initial contribution */ -@NonNullByDefault + public class RomyRobotHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); - private @NotNull RomyRobotConfiguration config; - private @Nullable ScheduledFuture pollingJob; - private @Nullable RomyApi romyDevice; - private @NotNull RomyApiFactory apiFactory; + private RomyRobotConfiguration config; + private ScheduledFuture pollingJob; + private RomyApi romyDevice; + private RomyApiFactory apiFactory; + private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; - public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory) { + public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory, + RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { super(thing); this.apiFactory = apiFactory; + this.stateDescriptionProvider = stateDescriptionProvider; config = getConfigAs(RomyRobotConfiguration.class); + romyDevice = setupAPI(apiFactory); } @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (CHANNEL_FW_VERSION.equals(channelUID.getId())) { - if (command instanceof RefreshType) { - // TODO: handle data refresh + public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command command) { + if (command instanceof RefreshType) { + try { + getRomyApi().refresh(); + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "RomyRobot refresh threw exception."); + } + } + if (CHANNEL_STRATEGY.equals(channelUID.getId())) { + updateState(CHANNEL_STRATEGY, new StringType(command.toString())); + getRomyApi().setStrategy(command.toString()); + } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { + updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); + getRomyApi().setSuctionMode(command.toString()); + } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { + updateState(CHANNEL_COMMAND, new StringType(command.toString())); + try { + getRomyApi().executeCommand(command.toString()); + } catch (Exception e) { + logger.error("error executing command against RomyRobot", e); } - - // 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"); } } @@ -81,32 +96,21 @@ public void initialize() { pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); } - public void refreshVacuum() { - RomyApiFactory apiFactory = getApiFactory(); - RomyApi localApi = romyDevice; - if (localApi == null) { - setupAPI(apiFactory); - localApi = romyDevice; - } - if (localApi != null) { - try { - localApi.refresh(); - updateStatus(ThingStatus.ONLINE); - this.updateChannels(localApi); + public void refreshVacuum() { - } catch (Exception e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); - } + try { + getRomyApi().refresh(); + updateStatus(ThingStatus.ONLINE); + this.updateChannels(getRomyApi()); + + } catch (Exception e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, + "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); } } - private RomyApiFactory getApiFactory() { - return apiFactory; - } - - private void updateChannels(RomyApi device) { - if (romyDevice != null) { + private void updateChannels(RomyApi device) { + if (device != null) { updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); @@ -114,22 +118,43 @@ private void updateChannels(RomyApi device) { updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); - updateState(CHANNEL_STRATEGY, StringType.valueOf(device.getStrategy())); - updateState(CHANNEL_SUCTION_MODE, StringType.valueOf(device.getSuctionMode())); - updateState(CHANNEL_AVAILABLE_MAPS, StringType.valueOf(device.getAvailableMaps())); + updateState(CHANNEL_AVAILABLE_MAPS_JSON, StringType.valueOf(device.getAvailableMapsJson())); + updateMapsList(device.getAvailableMaps()); + } + } + + public void updateMapsList(HashMap maps) { + logger.trace("RomyRobot updating maps list with {} options", maps.size()); + List options = new ArrayList<>(); + for (String key : maps.keySet()) { + options.add(new StateOption(key, maps.get(key))); } + stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SELECTED_MAP), options); } - private void setupAPI(RomyApiFactory apiFactory) { + private RomyApi setupAPI(RomyApiFactory apiFactory) { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); - try { + return apiFactory.getHttpApi(config); + } + + private RomyApi getRomyApi() { + if (romyDevice == null) { romyDevice = apiFactory.getHttpApi(config); + } + return romyDevice; + } - } catch (Exception exp) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not create an API connection to RomyRobot. Error received: " + exp); - return; + @Override + public void dispose() { + RomyApi localApi = romyDevice; + if (localApi != null) { + romyDevice = null; + } + ScheduledFuture localFuture = pollingJob; + if (localFuture != null) { + localFuture.cancel(true); + pollingJob = null; } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index 30d7a84b3d11..f13675139a5b 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -40,10 +40,13 @@ public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); private RomyApiFactory apiFactory; + private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; @Activate - public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory) { + public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory, + @Reference RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { this.apiFactory = apiFactory; + this.stateDescriptionProvider = stateDescriptionProvider; } @Override @@ -56,7 +59,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { - return new RomyRobotHandler(thing, apiFactory); + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); } return null; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml index 17792fedb3fe..b4803c649ca8 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.romyrobot/src/main/resources/OH-INF/thing/thing-types.xml @@ -58,6 +58,7 @@ Specifies the connection timeout in seconds. 5 + true From 4445f142e3894d4584f3057451bcbb072467d91d Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 14:44:57 +0200 Subject: [PATCH 23/45] fixed wrong assignement of selected map options Signed-off-by: Bernhard Kreuz --- .../internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java | 4 ++-- .../binding/romyrobot/internal/romyRobotBindingConstants.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java index 174eaefb221f..3bf73b697cae 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java @@ -99,8 +99,8 @@ private void parseMaps(String jsonString) throws JsonMappingException, JsonProce if (maps.isArray()) { availableMaps.clear(); for (final JsonNode field : maps) { - String key = field.get("map_meta_data").textValue(); - String value = field.get("map_id").asInt() + ""; + String value = field.get("map_meta_data").textValue(); + String key = field.get("map_id").asInt() + ""; String permanentFlag = field.get("permanent_flag").textValue(); if ("true".equalsIgnoreCase(permanentFlag)) { availableMaps.put(key, value); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java index f44f78988320..d7b992cbc3d8 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java @@ -41,6 +41,6 @@ public class RomyRobotBindingConstants { public static final String CHANNEL_CHARGING = "charging"; public static final String CHANNEL_RSSI = "rssi"; public static final String CHANNEL_POWER_STATUS = "powerstatus"; - public static final String CHANNEL_SELECTED_MAP = "seletedmap"; + public static final String CHANNEL_SELECTED_MAP = "selectedmap"; public static final String CHANNEL_AVAILABLE_MAPS_JSON = "availablemapsjson"; } From e4b84fc3c53928b12aee3c1f978545ccaf6ddf41 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 17:22:47 +0200 Subject: [PATCH 24/45] added protocol detection and refactored classname to fit naming Signed-off-by: Bernhard Kreuz --- .../romyrobot/internal/api/RomyApi.java | 12 + .../RomyApiAGON_1_2_4_release_3_14_3068.java | 306 ------------------ .../romyrobot/internal/romyRobotHandler.java | 18 +- .../internal/romyRobotHandlerFactory.java | 9 +- 4 files changed, 33 insertions(+), 312 deletions(-) delete mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 37398bbf82c4..b467739fd633 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -147,6 +147,18 @@ public interface RomyApi { */ String getAvailableMapsJson(); + /** + * + * @return a String listing the available maps + */ + int getProtocolVersionMajor(); + + /** + * + * @return a String listing the available maps + */ + int getProtocolVersionMinor(); + /** * * @return a String listing the available maps diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java deleted file mode 100644 index 3bf73b697cae..000000000000 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiAGON_1_2_4_release_3_14_3068.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.openhab.binding.romyrobot.internal.api; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jdt.annotation.NonNull; -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.romyrobot.internal.RomyRobotConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -public class RomyApiAGON_1_2_4_release_3_14_3068 implements RomyApi { - - private @NonNull String hostname; - private @NonNull RomyRobotConfiguration config; - protected HttpRequestSender http; - private String firmwareVersion = "UNKNOWN"; - private String mode; - private String activePumpVolume; - private String charging; - private int batteryLevel; - private String powerStatus; - private String mapsJson; - private int rssi; - private String strategy; - private String suctionMode; - private String selectedMap; - private HashMap availableMaps = new HashMap(); - private static final String CMD_GET_ROBOT_ID = "get/robot_id"; - private static final String CMD_GET_STATUS = "get/status"; - private static final String CMD_GET_MAPS = "get/maps"; - private static final String CMD_GET_WIFI_STATUS = "get/wifi_status"; - private static final String CMD_GET_POWER_STATUS = "get/power_status"; - private static final @NonNull String UNKNOWN = "UNKNOWN"; - - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - - public RomyApiAGON_1_2_4_release_3_14_3068(final @NonNull HttpClient httpClient, - final @NonNull RomyRobotConfiguration config) { - this.config = config; - if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { - this.hostname = config.hostname; - } else { - this.hostname = "http://" + config.hostname; - } - - this.http = new HttpRequestSender(httpClient); - } - - /** - * Returns the hostname and port formatted URL as a String. - * - * @return String representation of the OpenSprinkler API URL. - */ - protected String getBaseUrl() { - return hostname + ":" + config.port + "/"; - } - - @Override - public void refresh() throws Exception { - String returnContent; - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); - firmwareVersion = new ObjectMapper().readTree(returnContent).get("firmware").asText(); - if (firmwareVersion == null) { - throw new Exception("There was a problem in the HTTP communication: firmware was empty."); - } - mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); - parseMaps(mapsJson); - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); - powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); - - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); - JsonNode jsonNode = new ObjectMapper().readTree(returnContent); - mode = jsonNode.get("mode").asText(); - activePumpVolume = jsonNode.get("active_pump_volume").asText(); - charging = jsonNode.get("charging").asText(); - batteryLevel = jsonNode.get("battery_level").asInt(); - - returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_WIFI_STATUS, null); - jsonNode = new ObjectMapper().readTree(returnContent); - rssi = jsonNode.get("rssi").asInt(); - } - - private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { - JsonNode node = new ObjectMapper().readTree(jsonString); - JsonNode maps = node.get("maps"); - if (maps.isArray()) { - availableMaps.clear(); - for (final JsonNode field : maps) { - String value = field.get("map_meta_data").textValue(); - String key = field.get("map_id").asInt() + ""; - String permanentFlag = field.get("permanent_flag").textValue(); - if ("true".equalsIgnoreCase(permanentFlag)) { - availableMaps.put(key, value); - } - } - } - if (availableMaps.size() == 1 || selectedMap == null) { - selectedMap = availableMaps.values().iterator().next(); - } - } - - @Override - public String getFirmwareVersion() { - return firmwareVersion; - } - - @Override - public String getModeString() { - return mode; - } - - @Override - public String getActivePumpVolume() { - return activePumpVolume; - } - - @Override - public void setActivePumpVolume(String volume) { - this.activePumpVolume = volume; - } - - @Override - public String getStrategy() { - return strategy; - } - - @Override - public void setStrategy(String strategy) { - this.strategy = strategy; - } - - @Override - public String getSuctionMode() { - return suctionMode; - } - - @Override - public void setSuctionMode(String suctionMode) { - this.suctionMode = suctionMode; - } - - @Override - public int getBatteryLevel() { - return batteryLevel; - } - - @Override - public String getChargingStatus() { - return charging; - } - - @Override - public int getRssi() { - return rssi; - } - - @Override - public String getPowerStatus() { - return powerStatus; - } - - @Override - public String getAvailableMapsJson() { - return mapsJson; - } - - /** - * This class contains helper methods for communicating HTTP GET and HTTP POST - * requests. - * - * @author Chris Graham - Initial contribution - * @author Florian Schmidt - Reduce visibility of Http communication to Api - */ - protected class HttpRequestSender { - private static final int HTTP_OK_CODE = 200; - private static final String USER_AGENT = "Mozilla/5.0"; - - private final HttpClient httpClient; - - public HttpRequestSender(HttpClient httpClient) { - this.httpClient = httpClient; - } - - /** - * Given a URL and a set parameters, send a HTTP GET request to the URL location - * created by the URL and parameters. - * - * @param url The URL to send a GET request to. - * @param urlParameters List of parameters to use in the URL for the GET - * request. Null if no parameters. - * @return String contents of the response for the GET request. - * @throws Exception - */ - public String sendHttpGet(String url, @Nullable String urlParameters) throws Exception { - String location = null; - if (urlParameters != null) { - location = url + "?" + urlParameters; - } else { - location = url; - } - ContentResponse response; - try { - response = withGeneralProperties(httpClient.newRequest(location)) - .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); - } catch (Exception e) { - throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); - } - if (response.getStatus() != HTTP_OK_CODE) { - throw new Exception( - "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); - } - String content = response.getContentAsString(); - if ("{\"result\":2}".equals(content)) { - throw new Exception("Unauthorized, check your robot was unlocked"); - } - return content; - } - - private Request withGeneralProperties(Request request) { - // TODO: request header configuration - /* - * request.header(HttpHeader.USER_AGENT, USER_AGENT); - * if (!config.basicUsername.isEmpty() && !config.basicPassword.isEmpty()) { - * String encoded = Base64.getEncoder().encodeToString( - * (config.basicUsername + ":" + config.basicPassword).getBytes(StandardCharsets.UTF_8)); - * request.header(HttpHeader.AUTHORIZATION, "Basic " + encoded); - * } - */ - return request; - } - - /** - * Given a URL and a set parameters, send a HTTP POST request to the URL - * location created by the URL and parameters. - * - * @param url The URL to send a POST request to. - * @param urlParameters List of parameters to use in the URL for the POST - * request. Null if no parameters. - * @return String contents of the response for the POST request. - * @throws Exception - */ - public String sendHttpPost(String url, String urlParameters) throws Exception { - ContentResponse response; - try { - response = withGeneralProperties(httpClient.newRequest(url)).timeout(config.timeout, TimeUnit.SECONDS) - .method(HttpMethod.POST).content(new StringContentProvider(urlParameters)).send(); - } catch (Exception e) { - throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); - } - if (response.getStatus() != HTTP_OK_CODE) { - throw new Exception( - "Error sending HTTP POST request to " + url + ". Got response code: " + response.getStatus()); - } - return response.getContentAsString(); - } - } - - @Override - public void executeCommand(String command) throws Exception { - if ("REFRESH".equalsIgnoreCase(command)) { - return; - } - // String query = "/$" + command; - String query = null; - List params = new ArrayList(); - if ("clean_start_or_continue".equalsIgnoreCase(command) || "clean_all".equalsIgnoreCase(command) - || "clean_spot".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { - if (suctionMode != null && !"REFRESH".equals(suctionMode)) { - params.add("cleaning_parameter_set=" + suctionMode); - } - if (strategy != null && !"REFRESH".equals(strategy)) { - params.add("cleaning_strategy_mode=" + strategy); - - } - if (activePumpVolume != null) { - params.add("pump_volume=" + activePumpVolume); - } - if (params.size() > 0) { - query = String.join("&", params); - } - } else if ("redo_explore".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { - params.add("map_id" + selectedMap); - } - String url = getBaseUrl() + "set/" + command; - logger.info("executing RomyRobot command: {} at url {}", query, url); - http.sendHttpGet(url, query); - } - - @Override - public HashMap getAvailableMaps() { - return availableMaps; - } -} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index ac431b89ba30..237ab4f90432 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -56,7 +56,7 @@ public class RomyRobotHandler extends BaseThingHandler { private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory, - RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { + RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) throws Exception { super(thing); this.apiFactory = apiFactory; this.stateDescriptionProvider = stateDescriptionProvider; @@ -75,10 +75,18 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma } if (CHANNEL_STRATEGY.equals(channelUID.getId())) { updateState(CHANNEL_STRATEGY, new StringType(command.toString())); - getRomyApi().setStrategy(command.toString()); + try { + getRomyApi().setStrategy(command.toString()); + } catch (Exception e) { + logger.error("error updating strategy: {}", e); + } } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); - getRomyApi().setSuctionMode(command.toString()); + try { + getRomyApi().setSuctionMode(command.toString()); + } catch (Exception e) { + logger.error("error updating suctionmode: {}", e); + } } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { updateState(CHANNEL_COMMAND, new StringType(command.toString())); try { @@ -132,13 +140,13 @@ public void updateMapsList(HashMap maps) { stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SELECTED_MAP), options); } - private RomyApi setupAPI(RomyApiFactory apiFactory) { + private RomyApi setupAPI(RomyApiFactory apiFactory) throws Exception { logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", config.hostname, config.port, config.refreshInterval, config.timeout); return apiFactory.getHttpApi(config); } - private RomyApi getRomyApi() { + private RomyApi getRomyApi() throws Exception { if (romyDevice == null) { romyDevice = apiFactory.getHttpApi(config); } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index f13675139a5b..c3c158b420b7 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -27,6 +27,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 RomyRobotHandlerFactory} is responsible for creating things and thing @@ -41,6 +43,7 @@ public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); private RomyApiFactory apiFactory; private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; + private final Logger logger = LoggerFactory.getLogger(RomyRobotHandlerFactory.class); @Activate public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory, @@ -59,7 +62,11 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { - return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + try { + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + } catch (Exception e) { + logger.error("could not create handler {}", e); + } } return null; From 8136c86685e864d5bf5a83ba2e23273ed6445276 Mon Sep 17 00:00:00 2001 From: Bernhard Kreuz Date: Fri, 26 May 2023 17:27:12 +0200 Subject: [PATCH 25/45] spotless + unused import removed Signed-off-by: Bernhard Kreuz --- .../binding/romyrobot/internal/api/RomyApi.java | 12 ++++++------ .../romyrobot/internal/romyRobotHandler.java | 16 ++++++++-------- .../internal/romyRobotHandlerFactory.java | 8 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index b467739fd633..c5fa71164fc4 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -147,18 +147,18 @@ public interface RomyApi { */ String getAvailableMapsJson(); - /** + /** * * @return a String listing the available maps */ - int getProtocolVersionMajor(); - - /** + int getProtocolVersionMajor(); + + /** * * @return a String listing the available maps */ - int getProtocolVersionMinor(); - + int getProtocolVersionMinor(); + /** * * @return a String listing the available maps diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java index 237ab4f90432..3151e8b20588 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java @@ -76,17 +76,17 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma if (CHANNEL_STRATEGY.equals(channelUID.getId())) { updateState(CHANNEL_STRATEGY, new StringType(command.toString())); try { - getRomyApi().setStrategy(command.toString()); - } catch (Exception e) { - logger.error("error updating strategy: {}", e); - } + getRomyApi().setStrategy(command.toString()); + } catch (Exception e) { + logger.error("error updating strategy: {}", e); + } } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); try { - getRomyApi().setSuctionMode(command.toString()); - } catch (Exception e) { - logger.error("error updating suctionmode: {}", e); - } + getRomyApi().setSuctionMode(command.toString()); + } catch (Exception e) { + logger.error("error updating suctionmode: {}", e); + } } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { updateState(CHANNEL_COMMAND, new StringType(command.toString())); try { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java index c3c158b420b7..c049064ffc2a 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java @@ -63,10 +63,10 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { if (ROMYROBOT_DEVICE.equals(thingTypeUID)) { try { - return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); - } catch (Exception e) { - logger.error("could not create handler {}", e); - } + return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); + } catch (Exception e) { + logger.error("could not create handler {}", e); + } } return null; From 7a23053c284edfc4f4aa5a5066dc20f4482a2556 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Fri, 30 Jun 2023 09:58:18 +0200 Subject: [PATCH 26/45] discovery started Signed-off-by: Manuel Dipolt --- .../internal/romyRobotBindingConstants.java | 46 ----- .../internal/romyRobotConfiguration.java | 32 ---- .../romyrobot/internal/romyRobotHandler.java | 168 ------------------ .../internal/romyRobotHandlerFactory.java | 74 -------- 4 files changed, 320 deletions(-) delete mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java delete mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java delete mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java delete mode 100644 bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java deleted file mode 100644 index d7b992cbc3d8..000000000000 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotBindingConstants.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.romyrobot.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.ThingTypeUID; - -/** - * The {@link romyRobotBindingConstants} class defines common constants, which are - * used across the whole binding. - * - * @author Bernhard Kreuz - Initial contribution - */ -@NonNullByDefault -public class RomyRobotBindingConstants { - - private static final String BINDING_ID = "romyrobot"; - - // List of all Thing Type UIDs - public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "romyrobot"); - - // List of all Channel ids - - public static final String CHANNEL_FW_VERSION = "fwversion"; - public static final String CHANNEL_COMMAND = "command"; - public static final String CHANNEL_MODE = "mode"; - public static final String CHANNEL_ACTIVE_PUMP_VOLUME = "activepumpvolume"; - public static final String CHANNEL_STRATEGY = "strategy"; - public static final String CHANNEL_SUCTION_MODE = "suctionmode"; - public static final String CHANNEL_BATTERY = "battery"; - public static final String CHANNEL_CHARGING = "charging"; - public static final String CHANNEL_RSSI = "rssi"; - public static final String CHANNEL_POWER_STATUS = "powerstatus"; - public static final String CHANNEL_SELECTED_MAP = "selectedmap"; - public static final String CHANNEL_AVAILABLE_MAPS_JSON = "availablemapsjson"; -} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java deleted file mode 100644 index a79579a92b08..000000000000 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotConfiguration.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.romyrobot.internal; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * The {@link RomyRobotConfiguration} class contains fields mapping thing configuration parameters. - * - * @author Bernhard Kreuz - Initial contribution - */ -@NonNullByDefault -public class RomyRobotConfiguration { - - /** - * Sample configuration parameters. Replace with your own. - */ - public String hostname = ""; - public int refreshInterval = 600; - public int port = 8080; - public int timeout = 5; -} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java deleted file mode 100644 index 3151e8b20588..000000000000 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandler.java +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.romyrobot.internal; - -import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; -import static org.openhab.core.library.unit.Units.PERCENT; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import javax.validation.constraints.NotNull; - -import org.openhab.binding.romyrobot.internal.api.RomyApi; -import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; -import org.openhab.core.library.types.DecimalType; -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.StateOption; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The {@link RomyRobotHandler} is responsible for handling commands, which are - * sent to one of the channels. - * - * @author Bernhard Kreuz - Initial contribution - */ - -public class RomyRobotHandler extends BaseThingHandler { - private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); - - private RomyRobotConfiguration config; - private ScheduledFuture pollingJob; - private RomyApi romyDevice; - private RomyApiFactory apiFactory; - private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; - - public RomyRobotHandler(Thing thing, @NotNull RomyApiFactory apiFactory, - RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) throws Exception { - super(thing); - this.apiFactory = apiFactory; - this.stateDescriptionProvider = stateDescriptionProvider; - config = getConfigAs(RomyRobotConfiguration.class); - romyDevice = setupAPI(apiFactory); - } - - @Override - public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command command) { - if (command instanceof RefreshType) { - try { - getRomyApi().refresh(); - } catch (Exception e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "RomyRobot refresh threw exception."); - } - } - if (CHANNEL_STRATEGY.equals(channelUID.getId())) { - updateState(CHANNEL_STRATEGY, new StringType(command.toString())); - try { - getRomyApi().setStrategy(command.toString()); - } catch (Exception e) { - logger.error("error updating strategy: {}", e); - } - } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { - updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); - try { - getRomyApi().setSuctionMode(command.toString()); - } catch (Exception e) { - logger.error("error updating suctionmode: {}", e); - } - } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { - updateState(CHANNEL_COMMAND, new StringType(command.toString())); - try { - getRomyApi().executeCommand(command.toString()); - } catch (Exception e) { - logger.error("error executing command against RomyRobot", e); - } - } - } - - @Override - public void initialize() { - config = getConfigAs(RomyRobotConfiguration.class); - updateStatus(ThingStatus.UNKNOWN); - pollingJob = scheduler.scheduleWithFixedDelay(this::refreshVacuum, 2, config.refreshInterval, TimeUnit.SECONDS); - } - - public void refreshVacuum() { - - try { - getRomyApi().refresh(); - updateStatus(ThingStatus.ONLINE); - this.updateChannels(getRomyApi()); - - } catch (Exception e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); - } - } - - private void updateChannels(RomyApi device) { - if (device != null) { - updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); - updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); - updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); - updateState(CHANNEL_BATTERY, QuantityType.valueOf(device.getBatteryLevel(), PERCENT)); - updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); - updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); - updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); - updateState(CHANNEL_AVAILABLE_MAPS_JSON, StringType.valueOf(device.getAvailableMapsJson())); - updateMapsList(device.getAvailableMaps()); - } - } - - public void updateMapsList(HashMap maps) { - logger.trace("RomyRobot updating maps list with {} options", maps.size()); - List options = new ArrayList<>(); - for (String key : maps.keySet()) { - options.add(new StateOption(key, maps.get(key))); - } - stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SELECTED_MAP), options); - } - - private RomyApi setupAPI(RomyApiFactory apiFactory) throws Exception { - logger.debug("Initializing RomyRobot with config (Hostname: {}, Port: {}, Refresh: {}, Timeout {}).", - config.hostname, config.port, config.refreshInterval, config.timeout); - return apiFactory.getHttpApi(config); - } - - private RomyApi getRomyApi() throws Exception { - if (romyDevice == null) { - romyDevice = apiFactory.getHttpApi(config); - } - return romyDevice; - } - - @Override - public void dispose() { - RomyApi localApi = romyDevice; - if (localApi != null) { - romyDevice = null; - } - ScheduledFuture localFuture = pollingJob; - if (localFuture != null) { - localFuture.cancel(true); - pollingJob = null; - } - } -} diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java deleted file mode 100644 index c049064ffc2a..000000000000 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/romyRobotHandlerFactory.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.romyrobot.internal; - -import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.ROMYROBOT_DEVICE; - -import java.util.Set; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; -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; - -/** - * The {@link RomyRobotHandlerFactory} is responsible for creating things and thing - * handlers. - * - * @author Bernhard Kreuz - Initial contribution - */ -@NonNullByDefault -@Component(configurationPid = "binding.romyrobot", service = ThingHandlerFactory.class) -public class RomyRobotHandlerFactory extends BaseThingHandlerFactory { - - private static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(ROMYROBOT_DEVICE); - private RomyApiFactory apiFactory; - private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; - private final Logger logger = LoggerFactory.getLogger(RomyRobotHandlerFactory.class); - - @Activate - public RomyRobotHandlerFactory(@Reference RomyApiFactory apiFactory, - @Reference RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider) { - this.apiFactory = apiFactory; - this.stateDescriptionProvider = stateDescriptionProvider; - } - - @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 (ROMYROBOT_DEVICE.equals(thingTypeUID)) { - try { - return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); - } catch (Exception e) { - logger.error("could not create handler {}", e); - } - } - - return null; - } -} From 8e2d4e240f63fb469bd2c8ae5f1c3001e1039cb4 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 7 Sep 2023 12:13:36 +0200 Subject: [PATCH 27/45] added to codeowners + clean up bundles/pom.xml Signed-off-by: Manuel Dipolt --- bundles/pom.xml | 649 +----------------------------------------------- 1 file changed, 2 insertions(+), 647 deletions(-) diff --git a/bundles/pom.xml b/bundles/pom.xml index 1e7759b4a20a..1732255a2678 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -1,1325 +1,680 @@ - + 4.0.0 - org.openhab.addons - org.openhab.addons.reactor - 4.1.0-SNAPSHOT - org.openhab.addons.bundles - org.openhab.addons.reactor.bundles - pom openHAB Add-ons :: Bundles - - org.openhab.automation.groovyscripting - org.openhab.automation.jrubyscripting - org.openhab.automation.jsscripting - org.openhab.automation.jsscriptingnashorn - org.openhab.automation.jythonscripting - org.openhab.automation.pidcontroller - org.openhab.automation.pwm - - org.openhab.io.homekit - org.openhab.io.hueemulation - org.openhab.io.metrics - org.openhab.io.neeo - org.openhab.io.openhabcloud - - org.openhab.transform.bin2json - org.openhab.transform.exec - org.openhab.transform.jinja - org.openhab.transform.jsonpath - org.openhab.transform.map - org.openhab.transform.regex - org.openhab.transform.rollershutterposition - org.openhab.transform.scale - org.openhab.transform.vat - org.openhab.transform.xpath - org.openhab.transform.xslt - - org.openhab.binding.adorne - org.openhab.binding.ahawastecollection - org.openhab.binding.airq - org.openhab.binding.airquality - org.openhab.binding.airvisualnode - org.openhab.binding.alarmdecoder - org.openhab.binding.allplay - org.openhab.binding.amazondashbutton - org.openhab.binding.amazonechocontrol - org.openhab.binding.ambientweather - org.openhab.binding.amplipi - org.openhab.binding.androiddebugbridge - org.openhab.binding.androidtv - org.openhab.binding.anel - org.openhab.binding.anthem - org.openhab.binding.astro - org.openhab.binding.asuswrt - org.openhab.binding.atlona - org.openhab.binding.autelis - org.openhab.binding.automower - org.openhab.binding.avmfritz - org.openhab.binding.awattar - org.openhab.binding.benqprojector - org.openhab.binding.bigassfan - org.openhab.binding.bluetooth - org.openhab.binding.bluetooth.airthings - org.openhab.binding.bluetooth.am43 - org.openhab.binding.bluetooth.bluegiga - org.openhab.binding.bluetooth.bluez - org.openhab.binding.bluetooth.blukii - org.openhab.binding.bluetooth.daikinmadoka - org.openhab.binding.bluetooth.enoceanble - org.openhab.binding.bluetooth.generic - org.openhab.binding.bluetooth.govee - org.openhab.binding.bluetooth.radoneye - org.openhab.binding.bluetooth.roaming - org.openhab.binding.bluetooth.ruuvitag - org.openhab.binding.bondhome - org.openhab.binding.boschindego - org.openhab.binding.boschshc - org.openhab.binding.bosesoundtouch - org.openhab.binding.broadlinkthermostat - org.openhab.binding.bsblan - org.openhab.binding.bticinosmarther - org.openhab.binding.buienradar - org.openhab.binding.caddx - org.openhab.binding.cbus - org.openhab.binding.chatgpt - org.openhab.binding.chromecast - org.openhab.binding.cm11a - org.openhab.binding.comfoair - org.openhab.binding.coolmasternet - org.openhab.binding.coronastats - org.openhab.binding.daikin - org.openhab.binding.dali - org.openhab.binding.danfossairunit - 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 - org.openhab.binding.dmx - org.openhab.binding.dominoswiss - org.openhab.binding.doorbird - org.openhab.binding.draytonwiser - org.openhab.binding.dscalarm - org.openhab.binding.dsmr - org.openhab.binding.dwdpollenflug - org.openhab.binding.dwdunwetter - org.openhab.binding.easee - org.openhab.binding.echonetlite - org.openhab.binding.ecobee - org.openhab.binding.ecotouch - org.openhab.binding.ecovacs - org.openhab.binding.ecowatt - org.openhab.binding.ekey - org.openhab.binding.electroluxair - org.openhab.binding.elerotransmitterstick - org.openhab.binding.elroconnects - org.openhab.binding.energenie - org.openhab.binding.energidataservice - org.openhab.binding.enigma2 - org.openhab.binding.enocean - org.openhab.binding.enphase - org.openhab.binding.enturno - org.openhab.binding.epsonprojector - org.openhab.binding.etherrain - org.openhab.binding.evcc - org.openhab.binding.evohome - org.openhab.binding.exec - org.openhab.binding.feed - org.openhab.binding.feican - org.openhab.binding.fineoffsetweatherstation - org.openhab.binding.flicbutton - org.openhab.binding.fmiweather - org.openhab.binding.folderwatcher - org.openhab.binding.folding - org.openhab.binding.foobot - org.openhab.binding.freebox - org.openhab.binding.freeboxos - org.openhab.binding.fronius - org.openhab.binding.fsinternetradio - org.openhab.binding.ftpupload - org.openhab.binding.gardena - org.openhab.binding.gce - org.openhab.binding.generacmobilelink - org.openhab.binding.goecharger - org.openhab.binding.gpio - org.openhab.binding.globalcache - org.openhab.binding.gpstracker - org.openhab.binding.gree - org.openhab.binding.groupepsa - org.openhab.binding.groheondus - org.openhab.binding.guntamatic - org.openhab.binding.haassohnpelletstove - org.openhab.binding.harmonyhub - org.openhab.binding.haywardomnilogic - org.openhab.binding.hccrubbishcollection - org.openhab.binding.hdanywhere - org.openhab.binding.hdpowerview - org.openhab.binding.helios - org.openhab.binding.heliosventilation - org.openhab.binding.heos - org.openhab.binding.herzborg - org.openhab.binding.homeconnect - org.openhab.binding.homematic - org.openhab.binding.homewizard - org.openhab.binding.hpprinter - org.openhab.binding.http - org.openhab.binding.hue - org.openhab.binding.hydrawise - org.openhab.binding.hyperion - org.openhab.binding.iammeter - org.openhab.binding.iaqualink - org.openhab.binding.icalendar - org.openhab.binding.icloud - org.openhab.binding.ihc - org.openhab.binding.insteon - org.openhab.binding.ipcamera - org.openhab.binding.ipobserver - org.openhab.binding.intesis - org.openhab.binding.ipp - org.openhab.binding.irobot - org.openhab.binding.irtrans - org.openhab.binding.ism8 - org.openhab.binding.jablotron - org.openhab.binding.jeelink - org.openhab.binding.jellyfin - org.openhab.binding.juicenet - org.openhab.binding.kaleidescape - org.openhab.binding.keba - org.openhab.binding.km200 - org.openhab.binding.knx - org.openhab.binding.kodi - org.openhab.binding.konnected - org.openhab.binding.kostalinverter - org.openhab.binding.kvv - org.openhab.binding.lametrictime - org.openhab.binding.lcn - org.openhab.binding.leapmotion - org.openhab.binding.lghombot - org.openhab.binding.lgtvserial - org.openhab.binding.lgwebos - org.openhab.binding.lifx - org.openhab.binding.linky - org.openhab.binding.linuxinput - org.openhab.binding.liquidcheck - org.openhab.binding.lirc - org.openhab.binding.livisismarthome - org.openhab.binding.logreader - org.openhab.binding.loxone - org.openhab.binding.lutron - org.openhab.binding.luxom - org.openhab.binding.luxtronikheatpump - org.openhab.binding.magentatv - org.openhab.binding.mail - org.openhab.binding.max - org.openhab.binding.mcd - org.openhab.binding.mcp23017 - org.openhab.binding.meater - org.openhab.binding.mecmeter - org.openhab.binding.melcloud - org.openhab.binding.mercedesme - org.openhab.binding.meteoalerte - org.openhab.binding.meteoblue - org.openhab.binding.meteostick - org.openhab.binding.miele - org.openhab.binding.mielecloud - org.openhab.binding.mihome - org.openhab.binding.miio - org.openhab.binding.mikrotik - org.openhab.binding.millheat - org.openhab.binding.milight - org.openhab.binding.minecraft - org.openhab.binding.modbus - org.openhab.binding.modbus.e3dc - org.openhab.binding.modbus.sbc - org.openhab.binding.modbus.studer - org.openhab.binding.modbus.sunspec - org.openhab.binding.modbus.stiebeleltron - org.openhab.binding.modbus.helioseasycontrols - org.openhab.binding.monopriceaudio - org.openhab.binding.mpd - org.openhab.binding.mqtt - org.openhab.binding.mqtt.espmilighthub - org.openhab.binding.mqtt.generic - org.openhab.binding.mqtt.homeassistant - org.openhab.binding.mqtt.homie - org.openhab.binding.mqtt.ruuvigateway - org.openhab.binding.mybmw - org.openhab.binding.mycroft - org.openhab.binding.mynice org.openhab.binding.mystrom - org.openhab.binding.nanoleaf - org.openhab.binding.neato - org.openhab.binding.neeo - org.openhab.binding.neohub - org.openhab.binding.nest - org.openhab.binding.netatmo - org.openhab.binding.network - org.openhab.binding.networkupstools - org.openhab.binding.nibeheatpump - org.openhab.binding.nibeuplink - org.openhab.binding.nikobus - org.openhab.binding.nikohomecontrol - org.openhab.binding.nobohub - org.openhab.binding.novafinedust - org.openhab.binding.ntp - org.openhab.binding.nuki - org.openhab.binding.nuvo - org.openhab.binding.nzwateralerts - org.openhab.binding.oceanic - org.openhab.binding.ojelectronics - org.openhab.binding.omnikinverter - org.openhab.binding.omnilink - org.openhab.binding.onebusaway - org.openhab.binding.onewiregpio - org.openhab.binding.onewire - org.openhab.binding.onkyo - org.openhab.binding.opengarage - org.openhab.binding.opensprinkler - org.openhab.binding.openthermgateway - org.openhab.binding.openuv - org.openhab.binding.openweathermap - org.openhab.binding.openwebnet - org.openhab.binding.oppo - org.openhab.binding.orbitbhyve - org.openhab.binding.orvibo - org.openhab.binding.paradoxalarm - org.openhab.binding.pentair - org.openhab.binding.phc - org.openhab.binding.pilight - org.openhab.binding.pioneeravr - org.openhab.binding.pixometer - org.openhab.binding.pjlinkdevice - org.openhab.binding.playstation - org.openhab.binding.plclogo - org.openhab.binding.plex - org.openhab.binding.plugwise - org.openhab.binding.plugwiseha - org.openhab.binding.powermax - org.openhab.binding.proteusecometer - org.openhab.binding.prowl - org.openhab.binding.publictransportswitzerland - org.openhab.binding.pulseaudio - org.openhab.binding.pushbullet - org.openhab.binding.pushover - org.openhab.binding.pushsafer - org.openhab.binding.qbus - org.openhab.binding.qolsysiq - org.openhab.binding.radiothermostat - 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 - org.openhab.binding.robonect - org.openhab.binding.roku - org.openhab.binding.romyrobot - org.openhab.binding.rotel - org.openhab.binding.russound - org.openhab.binding.sagercaster - org.openhab.binding.samsungtv - org.openhab.binding.satel - org.openhab.binding.semsportal - org.openhab.binding.senechome - org.openhab.binding.seneye - org.openhab.binding.sensebox - org.openhab.binding.sensibo - org.openhab.binding.sensorcommunity - org.openhab.binding.serial - org.openhab.binding.serialbutton - org.openhab.binding.shelly - org.openhab.binding.silvercrestwifisocket - org.openhab.binding.siemensrds - org.openhab.binding.sinope - org.openhab.binding.sleepiq - org.openhab.binding.smaenergymeter - org.openhab.binding.smartmeter - org.openhab.binding.smartthings - org.openhab.binding.smhi - org.openhab.binding.smsmodem - org.openhab.binding.sncf - org.openhab.binding.snmp - org.openhab.binding.solaredge - org.openhab.binding.solarlog - org.openhab.binding.solarmax - org.openhab.binding.solarwatt - org.openhab.binding.solax - org.openhab.binding.somfymylink - org.openhab.binding.somfytahoma - org.openhab.binding.somneo - org.openhab.binding.sonnen - org.openhab.binding.sonos - org.openhab.binding.sonyaudio - org.openhab.binding.sonyprojector - org.openhab.binding.souliss - org.openhab.binding.speedtest - org.openhab.binding.spotify - org.openhab.binding.squeezebox - org.openhab.binding.surepetcare - org.openhab.binding.synopanalyzer - org.openhab.binding.systeminfo - org.openhab.binding.tacmi - org.openhab.binding.tado - org.openhab.binding.tankerkoenig - org.openhab.binding.tapocontrol org.openhab.binding.tasmotaplug org.openhab.binding.telegram - org.openhab.binding.teleinfo - org.openhab.binding.tellstick - org.openhab.binding.tesla - org.openhab.binding.tibber - org.openhab.binding.tivo - org.openhab.binding.touchwand - org.openhab.binding.tplinkrouter - org.openhab.binding.tplinksmarthome - org.openhab.binding.tr064 - org.openhab.binding.tradfri org.openhab.binding.unifi - org.openhab.binding.unifiedremote - org.openhab.binding.upnpcontrol - org.openhab.binding.upb - org.openhab.binding.urtsi - org.openhab.binding.valloxmv - org.openhab.binding.vdr - org.openhab.binding.vektiva - org.openhab.binding.velbus - org.openhab.binding.velux - org.openhab.binding.venstarthermostat - org.openhab.binding.ventaair - org.openhab.binding.verisure - org.openhab.binding.vesync - org.openhab.binding.vigicrues - org.openhab.binding.vitotronic - org.openhab.binding.vizio - org.openhab.binding.volvooncall - org.openhab.binding.volumio - org.openhab.binding.warmup - org.openhab.binding.weathercompany - org.openhab.binding.weatherunderground - org.openhab.binding.webexteams - org.openhab.binding.webthing - org.openhab.binding.wemo - org.openhab.binding.wifiled - org.openhab.binding.windcentrale - org.openhab.binding.wlanthermo - org.openhab.binding.wled - org.openhab.binding.wolfsmartset - org.openhab.binding.wundergroundupdatereceiver org.openhab.binding.x org.openhab.binding.xmltv - org.openhab.binding.xmppclient - org.openhab.binding.yamahamusiccast - org.openhab.binding.yamahareceiver - org.openhab.binding.yioremote - org.openhab.binding.yeelight - org.openhab.binding.zoneminder - org.openhab.binding.zway - - org.openhab.persistence.dynamodb - org.openhab.persistence.influxdb - org.openhab.persistence.inmemory - org.openhab.persistence.jdbc - org.openhab.persistence.jpa - org.openhab.persistence.mapdb - org.openhab.persistence.mongodb - org.openhab.persistence.rrd4j - - org.openhab.voice.googlestt - org.openhab.voice.googletts - org.openhab.voice.mactts - org.openhab.voice.marytts - org.openhab.voice.mimictts - org.openhab.voice.actiontemplatehli - org.openhab.voice.picotts - org.openhab.voice.pollytts - org.openhab.voice.porcupineks - org.openhab.voice.rustpotterks - org.openhab.voice.voicerss - org.openhab.voice.voskstt - org.openhab.voice.watsonstt - - - target/dependency - - - - org.lastnpe.eea - eea-all - ${eea.version} - - - - org.openhab.core.bom - org.openhab.core.bom.compile - pom - provided - - - org.openhab.core.bom - org.openhab.core.bom.openhab-core - pom - provided - - - commons-net - commons-net - - - - - org.openhab.core.bom - org.openhab.core.bom.test - pom - test - - - - org.apache.karaf.features - framework - ${karaf.version} - kar - true - - - * - * - - - - - - org.apache.karaf.features - standard - ${karaf.version} - features - xml - provided - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - true - - - - org.apache.karaf.tooling - karaf-maven-plugin - ${karaf.version} - true - - 80 - true - true - false - true - true - - - - compile - - features-generate-descriptor - - generate-resources - - ${feature.directory} - - - - karaf-feature-verification - - verify - - verify - - - - mvn:org.apache.karaf.features/framework/${karaf.version}/xml/features - mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features mvn:org.apache.karaf.features/specs/${karaf.version}/xml/features - file:${project.build.directory}/feature/feature.xml - - org.apache.karaf.features:framework - ${oh.java.version} - - framework - - - openhab-* - - false - true - first - - - - - - - - biz.aQute.bnd - bnd-maven-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar-no-fork - - - - - - org.apache.karaf.tooling - karaf-maven-plugin - - - - org.apache.maven.plugins - maven-dependency-plugin - 3.6.0 - - - embed-dependencies - - unpack-dependencies - - - runtime - jar - **/module-info.class - javax.activation,org.apache.karaf.features,org.lastnpe.eea - ${dep.noembedding} - ${project.build.directory}/classes - true - true - true - jar - - - - unpack-eea - - unpack - - - - - org.lastnpe.eea - eea-all - ${eea.version} - true - - - - - - - - - - - no-embed-dependencies - - - noEmbedDependencies.profile - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - embed-dependencies - none - - - - - - - From 1b3d767603dc5c0db5d58d8deed14aca86caa9c5 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 7 Sep 2023 16:34:16 +0200 Subject: [PATCH 28/45] wip Signed-off-by: Manuel Dipolt --- .../binding/romyrobot/internal/RomyRobotBindingConstants.java | 2 +- .../org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java index 3e9abd315c60..790b65352f39 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java @@ -24,7 +24,7 @@ @NonNullByDefault public class RomyRobotBindingConstants { - private static final String BINDING_ID = "romyrobot"; + private static final String BINDING_ID = "aicu"; // List of all Thing Type UIDs public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "aicu"); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index c2bfab7ef118..66346fbe4c67 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -112,7 +112,7 @@ public void refresh() throws Exception { powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); - JsonNode jsonNode = new ObjectMapper().readTree(returnContent); + jsonNode = new ObjectMapper().readTree(returnContent); mode = jsonNode.get("mode").asText(); activePumpVolume = jsonNode.get("active_pump_volume").asText(); charging = jsonNode.get("charging").asText(); From 4447c78a04b405f484211d7e4319fa228aa90377 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Mon, 11 Sep 2023 11:29:52 +0200 Subject: [PATCH 29/45] wip Signed-off-by: Manuel Dipolt --- .../internal/discovery/RomyRobotMDNSDiscoveryParticipant.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 3653b4a130f6..3e466d8e2512 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -22,8 +22,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; -import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; From 6df0d861f8af4c5d73be42b45b9e6d9422ed6ba2 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Mon, 18 Sep 2023 17:05:12 +0200 Subject: [PATCH 30/45] wip discovery Signed-off-by: Manuel Dipolt --- .../binding/romyrobot/internal/RomyRobotBindingConstants.java | 2 +- .../internal/discovery/RomyRobotMDNSDiscoveryParticipant.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java index 790b65352f39..3e9abd315c60 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotBindingConstants.java @@ -24,7 +24,7 @@ @NonNullByDefault public class RomyRobotBindingConstants { - private static final String BINDING_ID = "aicu"; + private static final String BINDING_ID = "romyrobot"; // List of all Thing Type UIDs public static final ThingTypeUID ROMYROBOT_DEVICE = new ThingTypeUID(BINDING_ID, "aicu"); diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 3e466d8e2512..3653b4a130f6 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -22,6 +22,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; +import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.config.discovery.DiscoveryResult; import org.openhab.core.config.discovery.DiscoveryResultBuilder; From 206712b181c4a4fe52958608900be178c2613fa2 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Tue, 19 Sep 2023 12:40:17 +0200 Subject: [PATCH 31/45] wip hostname discovery Signed-off-by: Manuel Dipolt --- .../org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 66346fbe4c67..c2bfab7ef118 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -112,7 +112,7 @@ public void refresh() throws Exception { powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_STATUS, null); - jsonNode = new ObjectMapper().readTree(returnContent); + JsonNode jsonNode = new ObjectMapper().readTree(returnContent); mode = jsonNode.get("mode").asText(); activePumpVolume = jsonNode.get("active_pump_volume").asText(); charging = jsonNode.get("charging").asText(); From 966010e651911b3d5aae8627085e4141944ccc93 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Tue, 19 Sep 2023 19:34:20 +0200 Subject: [PATCH 32/45] lock wip Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/api/RomyApi_v6.java | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index c2bfab7ef118..99edccb981f8 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -12,6 +12,7 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.util.StringContentProvider; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; import org.openhab.binding.romyrobot.internal.RomyRobotConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,17 +98,6 @@ public void refresh_protocol_version() throws Exception { @Override public void refresh() throws Exception { - /* - * String returnContent; - * returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); - * JsonNode jsonNode = new ObjectMapper().readTree(returnContent); - * firmwareVersion = jsonNode.get("firmware").asText(); - * if (firmwareVersion == null) { - * throw new Exception("There was a problem in the HTTP communication: firmware was empty."); - * } - * name = jsonNode.get("name").asText(); - */ - String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_POWER_STATUS, null); powerStatus = new ObjectMapper().readTree(returnContent).get("power_status").asText(); @@ -124,12 +114,6 @@ public void refresh() throws Exception { mapsJson = http.sendHttpGet(getBaseUrl() + CMD_GET_MAPS, null); parseMaps(mapsJson); - - /* - * returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); - * protocolVersionMajor = new ObjectMapper().readTree(returnContent).get("version_major").intValue(); - * protocolVersionMinor = new ObjectMapper().readTree(returnContent).get("version_minor").intValue(); - */ } private void parseMaps(String jsonString) throws JsonMappingException, JsonProcessingException { @@ -231,8 +215,7 @@ public String getAvailableMapsJson() { * @author Florian Schmidt - Reduce visibility of Http communication to Api */ protected class HttpRequestSender { - private static final int HTTP_OK_CODE = 200; - private static final String USER_AGENT = "Mozilla/5.0"; + //private static final String USER_AGENT = "Mozilla/5.0"; private final HttpClient httpClient; @@ -264,14 +247,20 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc } catch (Exception e) { throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); } - if (response.getStatus() != HTTP_OK_CODE) { + if (response.getStatus() == HttpStatus.FORBIDDEN_403 { + throw new Exception( + "Error sending HTTP GET request to " + url + ". Unauthorized, check your robot is unlocked or provide proper password!"); + } + if (response.getStatus() != HttpStatus.OK_200) { throw new Exception( "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); } - String content = response.getContentAsString(); + /*String content = response.getContentAsString(); if ("{\"result\":2}".equals(content)) { - throw new Exception("Unauthorized, check your robot was unlocked"); - } + throw new Exception( + "Unauthorized, check your robot is unlocked or provide proper password, http content:" + + content); + }*/ return content; } @@ -306,7 +295,7 @@ public String sendHttpPost(String url, String urlParameters) throws Exception { } catch (Exception e) { throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); } - if (response.getStatus() != HTTP_OK_CODE) { + if (response.getStatus() != HttpStatus.OK_200) { throw new Exception( "Error sending HTTP POST request to " + url + ". Got response code: " + response.getStatus()); } From 58b13d5ec81f8f1b9a44ca99736c4c330967e66f Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 4 Oct 2023 11:19:32 +0200 Subject: [PATCH 33/45] old wip Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/api/RomyApi_v6.java | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 99edccb981f8..ee73941da26a 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -1,5 +1,6 @@ package org.openhab.binding.romyrobot.internal.api; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -215,7 +216,7 @@ public String getAvailableMapsJson() { * @author Florian Schmidt - Reduce visibility of Http communication to Api */ protected class HttpRequestSender { - //private static final String USER_AGENT = "Mozilla/5.0"; + // private static final String USER_AGENT = "Mozilla/5.0"; private final HttpClient httpClient; @@ -242,26 +243,44 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc } ContentResponse response; try { + logger.error("location => " + location); response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); } - if (response.getStatus() == HttpStatus.FORBIDDEN_403 { - throw new Exception( - "Error sending HTTP GET request to " + url + ". Unauthorized, check your robot is unlocked or provide proper password!"); + if (response.getStatus() == HttpStatus.FORBIDDEN_403) { + logger.error("url => " + url); + URL netUrl = new URL(url); + String host = netUrl.getHost(); + logger.error("host => " + host); + try { + logger.info( + "looks like http interface is locked, try to unlock it now with password from config..."); + String unlock = netUrl.getProtocol() + netUrl.getHost() + ":" + netUrl.getPort() + + "/set/unlock_http?password=" + config.password; + logger.error("unlock => " + unlock); + response = withGeneralProperties(httpClient.newRequest(unlock)) + .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); + } catch (Exception e) { + throw new Exception("Request to unlock RomyRobot device with password " + config.password + + " failed: " + e.getMessage()); + } } if (response.getStatus() != HttpStatus.OK_200) { throw new Exception( "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); } - /*String content = response.getContentAsString(); - if ("{\"result\":2}".equals(content)) { - throw new Exception( - "Unauthorized, check your robot is unlocked or provide proper password, http content:" - + content); - }*/ - return content; + /* + * String content = response.getContentAsString(); + * if ("{\"result\":2}".equals(content)) { + * throw new Exception( + * "Unauthorized, check your robot is unlocked or provide proper password, http content:" + * + content); + * } + * return content; + */ + return response.getContentAsString(); } private Request withGeneralProperties(Request request) { From 8a275d11a0c2e341c109db210c89cec5b04ebfb6 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 4 Oct 2023 14:26:28 +0200 Subject: [PATCH 34/45] correct http request to unlock properly Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/RomyRobotHandler.java | 3 +- .../romyrobot/internal/api/RomyApi_v6.java | 28 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index a68edde01739..c6f2f77f8a75 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -113,7 +113,8 @@ public void refreshVacuum() { } catch (Exception e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Could not sync status with RomyRobot, check your robot is unlocked " + e.getMessage()); + "Could not sync status with RomyRobot, check your robot is unlocked to unlock it please provide password, you can find it under the dustbin (look for QR Code)" + + e.getMessage()); } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index ee73941da26a..d64cf52822b1 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -216,8 +216,6 @@ public String getAvailableMapsJson() { * @author Florian Schmidt - Reduce visibility of Http communication to Api */ protected class HttpRequestSender { - // private static final String USER_AGENT = "Mozilla/5.0"; - private final HttpClient httpClient; public HttpRequestSender(HttpClient httpClient) { @@ -250,6 +248,9 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); } if (response.getStatus() == HttpStatus.FORBIDDEN_403) { + + // forbiden, looks like http interface is locked, try to unlock it + // ------------------------------------------------------------------ logger.error("url => " + url); URL netUrl = new URL(url); String host = netUrl.getHost(); @@ -257,8 +258,8 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc try { logger.info( "looks like http interface is locked, try to unlock it now with password from config..."); - String unlock = netUrl.getProtocol() + netUrl.getHost() + ":" + netUrl.getPort() - + "/set/unlock_http?password=" + config.password; + String unlock = netUrl.getProtocol() + "://" + netUrl.getHost() + ":" + netUrl.getPort() + + "/set/unlock_http?pass=" + config.password; logger.error("unlock => " + unlock); response = withGeneralProperties(httpClient.newRequest(unlock)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); @@ -266,20 +267,21 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc throw new Exception("Request to unlock RomyRobot device with password " + config.password + " failed: " + e.getMessage()); } + + // send request again after unlocking + // ------------------------------------- + try { + logger.error("location => " + location); + response = withGeneralProperties(httpClient.newRequest(location)) + .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); + } catch (Exception e) { + throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + } } if (response.getStatus() != HttpStatus.OK_200) { throw new Exception( "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); } - /* - * String content = response.getContentAsString(); - * if ("{\"result\":2}".equals(content)) { - * throw new Exception( - * "Unauthorized, check your robot is unlocked or provide proper password, http content:" - * + content); - * } - * return content; - */ return response.getContentAsString(); } From ce8395fe58b8d42cca2d74783b100c3de601ef76 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 4 Oct 2023 17:15:52 +0200 Subject: [PATCH 35/45] cleanup Signed-off-by: Manuel Dipolt --- .../internal/discovery/RomyRobotMDNSDiscoveryParticipant.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 3653b4a130f6..e7d011285257 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -111,8 +111,7 @@ public Set getSupportedThingTypeUIDs() { try { RomyRobotConfiguration config = new RomyRobotConfiguration(); config.hostname = address; - RomyApi romyDevice = apiFactory.getHttpApi(config); - // romyDevice.refresh(); + RomyApi romyDevice = apiFactory.getHttpApi(config); romyDevice.refresh_id(); romyDevice.refresh_protocol_version(); robotName = romyDevice.getName(); From 0c0e3c040186d8c0cc35604e6d281d010eef8bf1 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 4 Oct 2023 17:43:30 +0200 Subject: [PATCH 36/45] adding romy again Signed-off-by: Manuel Dipolt --- bundles/pom.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/bundles/pom.xml b/bundles/pom.xml index 1732255a2678..0c0096df4e0d 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -561,9 +561,7 @@ mvn:org.apache.karaf.features/framework/${karaf.version}/xml/features mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features - mvn:org.apache.karaf.features/specs/${karaf.version}/xml/features - file:${project.build.directory}/feature/feature.xml From 49c557937792a02f4c4aca132c368686a5853274 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 11 Oct 2023 14:18:16 +0200 Subject: [PATCH 37/45] cleanup Signed-off-by: Manuel Dipolt --- .../internal/discovery/RomyRobotMDNSDiscoveryParticipant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index e7d011285257..5d0e66c15638 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -111,7 +111,7 @@ public Set getSupportedThingTypeUIDs() { try { RomyRobotConfiguration config = new RomyRobotConfiguration(); config.hostname = address; - RomyApi romyDevice = apiFactory.getHttpApi(config); + RomyApi romyDevice = apiFactory.getHttpApi(config); romyDevice.refresh_id(); romyDevice.refresh_protocol_version(); robotName = romyDevice.getName(); From 34523a337cab783e0cdcb06c74806a40626d0632 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 18 Oct 2023 11:40:26 +0200 Subject: [PATCH 38/45] cleanup Signed-off-by: Manuel Dipolt --- .../binding/romyrobot/internal/api/RomyApi.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index c5fa71164fc4..f1b93a4bc18e 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -149,28 +149,16 @@ public interface RomyApi { /** * - * @return a String listing the available maps - */ - int getProtocolVersionMajor(); - - /** - * - * @return a String listing the available maps + * @return Minor Interface Version */ int getProtocolVersionMinor(); /** * - * @return a String listing the available maps + * @return Major Interface Version */ int getProtocolVersionMajor(); - /** - * - * @return a String listing the available maps - */ - int getProtocolVersionMinor(); - /** * * @param command command to execute From 70138860ebccac8c0515cc5b7d0201e910ef7c6e Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 18 Oct 2023 16:13:34 +0200 Subject: [PATCH 39/45] wip cleanup Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/RomyRobotHandler.java | 6 +++--- .../romyrobot/internal/api/RomyApi_v6.java | 19 +++++++++++++++++++ .../RomyRobotMDNSDiscoveryParticipant.java | 1 - 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index c6f2f77f8a75..e8e403736a40 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -78,21 +78,21 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma try { getRomyApi().setStrategy(command.toString()); } catch (Exception e) { - logger.error("error updating strategy: {}", e); + logger.error("error updating strategy: {}", e.getMessage()); } } else if (CHANNEL_SUCTION_MODE.equals(channelUID.getId())) { updateState(CHANNEL_SUCTION_MODE, new StringType(command.toString())); try { getRomyApi().setSuctionMode(command.toString()); } catch (Exception e) { - logger.error("error updating suctionmode: {}", e); + logger.error("error updating suctionmode: {}", e.getMessage()); } } else if (CHANNEL_COMMAND.equals(channelUID.getId())) { updateState(CHANNEL_COMMAND, new StringType(command.toString())); try { getRomyApi().executeCommand(command.toString()); } catch (Exception e) { - logger.error("error executing command against RomyRobot", e); + logger.error("error executing command against RomyRobot", e.getMessage()); } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index d64cf52822b1..69799bb80f90 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -1,3 +1,15 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.romyrobot.internal.api; import java.net.URL; @@ -23,6 +35,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +/** + * The {@link RomyApi_v6} interface defines the functions which are + * controllable on the Romy API interface Version 6. + * + * @author Bernhard Kreuz - Initial contribution + */ + public class RomyApi_v6 implements RomyApi { private @NonNull String hostname; diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 5d0e66c15638..674a6f54b075 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -117,7 +117,6 @@ public Set getSupportedThingTypeUIDs() { robotName = romyDevice.getName(); logger.debug("New ROMY with the name:{} discovered: {}", robotName); } catch (Exception e) { - e.printStackTrace(); logger.error("Error setting up ROMY api: {}", e.getMessage()); return null; } From eaf57152b22391c6bfec605fa1bf010696751e97 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 18 Oct 2023 16:33:20 +0200 Subject: [PATCH 40/45] wip cleanup Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/RomyRobotHandler.java | 2 +- .../internal/RomyRobotHandlerFactory.java | 2 +- .../romyrobot/internal/api/RomyApi_v6.java | 15 +++++---------- .../RomyRobotMDNSDiscoveryParticipant.java | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index e8e403736a40..e1a3f497ef0f 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -92,7 +92,7 @@ public void handleCommand(@NotNull ChannelUID channelUID, @NotNull Command comma try { getRomyApi().executeCommand(command.toString()); } catch (Exception e) { - logger.error("error executing command against RomyRobot", e.getMessage()); + logger.error("error executing command against RomyRobot", e); } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java index c049064ffc2a..4d3924311a89 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandlerFactory.java @@ -65,7 +65,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { try { return new RomyRobotHandler(thing, apiFactory, stateDescriptionProvider); } catch (Exception e) { - logger.error("could not create handler {}", e); + logger.error("could not create handler {}", e.getMessage()); } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 69799bb80f90..86e7a26660f3 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -259,8 +259,7 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc location = url; } ContentResponse response; - try { - logger.error("location => " + location); + try { response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { @@ -269,17 +268,14 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc if (response.getStatus() == HttpStatus.FORBIDDEN_403) { // forbiden, looks like http interface is locked, try to unlock it - // ------------------------------------------------------------------ - logger.error("url => " + url); + // ------------------------------------------------------------------ URL netUrl = new URL(url); - String host = netUrl.getHost(); - logger.error("host => " + host); + String host = netUrl.getHost(); try { logger.info( "looks like http interface is locked, try to unlock it now with password from config..."); String unlock = netUrl.getProtocol() + "://" + netUrl.getHost() + ":" + netUrl.getPort() - + "/set/unlock_http?pass=" + config.password; - logger.error("unlock => " + unlock); + + "/set/unlock_http?pass=" + config.password; response = withGeneralProperties(httpClient.newRequest(unlock)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { @@ -289,8 +285,7 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc // send request again after unlocking // ------------------------------------- - try { - logger.error("location => " + location); + try { response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index 674a6f54b075..caa060ee1a32 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -115,7 +115,7 @@ public Set getSupportedThingTypeUIDs() { romyDevice.refresh_id(); romyDevice.refresh_protocol_version(); robotName = romyDevice.getName(); - logger.debug("New ROMY with the name:{} discovered: {}", robotName); + logger.debug("New ROMY with the name: {}", robotName); } catch (Exception e) { logger.error("Error setting up ROMY api: {}", e.getMessage()); return null; From a4b038131c38d42a44e0d6d565247abf3cfd1166 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Wed, 18 Oct 2023 16:43:36 +0200 Subject: [PATCH 41/45] wip cleanup Signed-off-by: Manuel Dipolt --- .../binding/romyrobot/internal/api/RomyApi_v6.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 86e7a26660f3..7ef859320430 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -259,7 +259,7 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc location = url; } ContentResponse response; - try { + try { response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { @@ -268,14 +268,14 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc if (response.getStatus() == HttpStatus.FORBIDDEN_403) { // forbiden, looks like http interface is locked, try to unlock it - // ------------------------------------------------------------------ + // ------------------------------------------------------------------ URL netUrl = new URL(url); - String host = netUrl.getHost(); + String host = netUrl.getHost(); try { logger.info( "looks like http interface is locked, try to unlock it now with password from config..."); String unlock = netUrl.getProtocol() + "://" + netUrl.getHost() + ":" + netUrl.getPort() - + "/set/unlock_http?pass=" + config.password; + + "/set/unlock_http?pass=" + config.password; response = withGeneralProperties(httpClient.newRequest(unlock)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { @@ -285,7 +285,7 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc // send request again after unlocking // ------------------------------------- - try { + try { response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { From 80505de9a5a75a6247bf0e1d3ab8e66c434799db Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Thu, 2 Nov 2023 11:08:45 +0100 Subject: [PATCH 42/45] version readout fixed Signed-off-by: Manuel Dipolt --- .../binding/romyrobot/internal/api/RomyApi_v6.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java index 7ef859320430..985607aa8042 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java @@ -107,13 +107,10 @@ public void refresh_id() throws Exception { @Override public void refresh_protocol_version() throws Exception { - String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); + String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); JsonNode jsonNode = new ObjectMapper().readTree(returnContent); - firmwareVersion = jsonNode.get("firmware").asText(); - if (firmwareVersion == null) { - throw new Exception("There was a problem in the HTTP communication: firmware was empty."); - } - name = jsonNode.get("name").asText(); + protocolVersionMajor = jsonNode.get("version_major").intValue(); + protocolVersionMinor = jsonNode.get("version_minor").intValue(); } @Override @@ -258,6 +255,8 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc } else { location = url; } + + logger.debug("sendHttpGet location:{}", location); ContentResponse response; try { response = withGeneralProperties(httpClient.newRequest(location)) From 40da662b4a412d4fbd842aa409ad823c5f88ff99 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Fri, 3 Nov 2023 09:49:56 +0100 Subject: [PATCH 43/45] codestyle cleanup Signed-off-by: Manuel Dipolt --- .../org.openhab.binding.romyrobot/README.md | 1 + .../romyrobot/internal/RomyRobotHandler.java | 4 +-- .../romyrobot/internal/api/RomyApi.java | 6 ++-- .../internal/api/RomyApiFactory.java | 8 +++-- .../api/{RomyApi_v6.java => RomyApiV6.java} | 36 +++++++++---------- .../RomyRobotMDNSDiscoveryParticipant.java | 5 ++- 6 files changed, 30 insertions(+), 30 deletions(-) rename bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/{RomyApi_v6.java => RomyApiV6.java} (91%) diff --git a/bundles/org.openhab.binding.romyrobot/README.md b/bundles/org.openhab.binding.romyrobot/README.md index 5a732d17155a..7372ab7f720e 100644 --- a/bundles/org.openhab.binding.romyrobot/README.md +++ b/bundles/org.openhab.binding.romyrobot/README.md @@ -76,6 +76,7 @@ _*.sitemap examples are optional._ ```java Example thing configuration goes here. ``` + ### Item Configuration ```java diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index e1a3f497ef0f..0221ad8f11ad 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -45,7 +45,7 @@ * * @author Bernhard Kreuz - Initial contribution */ - +// TODO @NonNullByDefault public class RomyRobotHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); @@ -105,12 +105,10 @@ public void initialize() { } public void refreshVacuum() { - try { getRomyApi().refresh(); updateStatus(ThingStatus.ONLINE); this.updateChannels(getRomyApi()); - } catch (Exception e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Could not sync status with RomyRobot, check your robot is unlocked to unlock it please provide password, you can find it under the dustbin (look for QR Code)" diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index f1b93a4bc18e..70ba0335ab92 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -21,7 +21,7 @@ * * @author Bernhard Kreuz - Initial contribution */ - +// TODO @NonNullByDefault public interface RomyApi { /** @@ -33,7 +33,7 @@ public interface RomyApi { * @throws CommunicationApiException * @throws UnauthorizedApiException */ - void refresh_id() throws Exception; + void refreshID() throws Exception; /** * get robots api protocol version @@ -44,7 +44,7 @@ public interface RomyApi { * @throws CommunicationApiException * @throws UnauthorizedApiException */ - void refresh_protocol_version() throws Exception; + void refreshProtocolVersion() throws Exception; /** * Sends all the GET requests and stores/cache the responses for use by the API to prevent the need for multiple diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java index 56fb39cbf876..9ef0defe1fce 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiFactory.java @@ -19,6 +19,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 RomyApiFactory} class is used for creating instances of @@ -31,6 +33,8 @@ public class RomyApiFactory { private HttpClient httpClient; + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Activate public RomyApiFactory(@Reference HttpClientFactory httpClientFactory) { this.httpClient = httpClientFactory.getCommonHttpClient(); @@ -38,11 +42,11 @@ public RomyApiFactory(@Reference HttpClientFactory httpClientFactory) { public RomyApi getHttpApi(RomyRobotConfiguration config) throws Exception { int version = -1; - RomyApi lowestSupportedApi = new RomyApi_v6(this.httpClient, config); + RomyApi lowestSupportedApi = new RomyApiV6(this.httpClient, config); try { version = lowestSupportedApi.getProtocolVersionMajor(); } catch (Exception exp) { - throw new Exception("Problem fetching the firmware version from RomyRobot: " + exp.getMessage()); + logger.error("Problem fetching the firmware version from RomyRobot: {}", exp.getMessage()); } // will start to make sense once a breaking API Version > 6 is introduced if (version >= 6) { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java similarity index 91% rename from bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java rename to bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java index 985607aa8042..6a17b648641a 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi_v6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java @@ -36,13 +36,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; /** - * The {@link RomyApi_v6} interface defines the functions which are + * The {@link RomyApiV6} interface defines the functions which are * controllable on the Romy API interface Version 6. * * @author Bernhard Kreuz - Initial contribution */ -public class RomyApi_v6 implements RomyApi { +public class RomyApiV6 implements RomyApi { private @NonNull String hostname; private @NonNull RomyRobotConfiguration config; @@ -74,7 +74,7 @@ public class RomyApi_v6 implements RomyApi { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - public RomyApi_v6(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { + public RomyApiV6(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { this.config = config; if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { this.hostname = config.hostname; @@ -95,18 +95,18 @@ protected String getBaseUrl() { } @Override - public void refresh_id() throws Exception { + public void refreshID() throws Exception { String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_ROBOT_ID, null); JsonNode jsonNode = new ObjectMapper().readTree(returnContent); firmwareVersion = jsonNode.get("firmware").asText(); if (firmwareVersion == null) { - throw new Exception("There was a problem in the HTTP communication: firmware was empty."); + logger.error("There was a problem in the HTTP communication: firmware was empty."); } name = jsonNode.get("name").asText(); } @Override - public void refresh_protocol_version() throws Exception { + public void refreshProtocolVersion() throws Exception { String returnContent = http.sendHttpGet(getBaseUrl() + CMD_GET_PROTOCOL_VERSION, null); JsonNode jsonNode = new ObjectMapper().readTree(returnContent); protocolVersionMajor = jsonNode.get("version_major").intValue(); @@ -262,14 +262,14 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { - throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + logger.error("Request to RomyRobot device failed: {}", e.getMessage()); + return ""; } - if (response.getStatus() == HttpStatus.FORBIDDEN_403) { + if (response.getStatus() == HttpStatus.FORBIDDEN_403) { // forbiden, looks like http interface is locked, try to unlock it // ------------------------------------------------------------------ URL netUrl = new URL(url); - String host = netUrl.getHost(); try { logger.info( "looks like http interface is locked, try to unlock it now with password from config..."); @@ -278,8 +278,8 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc response = withGeneralProperties(httpClient.newRequest(unlock)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { - throw new Exception("Request to unlock RomyRobot device with password " + config.password - + " failed: " + e.getMessage()); + logger.error("Request to unlock RomyRobot device with password {} failed: {}", config.password, + e.getMessage()); } // send request again after unlocking @@ -288,12 +288,11 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc response = withGeneralProperties(httpClient.newRequest(location)) .timeout(config.timeout, TimeUnit.SECONDS).method(HttpMethod.GET).send(); } catch (Exception e) { - throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + logger.error("Request to RomyRobot device failed: {}", e.getMessage()); } } if (response.getStatus() != HttpStatus.OK_200) { - throw new Exception( - "Error sending HTTP GET request to " + url + ". Got response code: " + response.getStatus()); + logger.error("Error sending HTTP GET request to {}. Got response code: {}", url, response.getStatus()); } return response.getContentAsString(); } @@ -327,11 +326,11 @@ public String sendHttpPost(String url, String urlParameters) throws Exception { response = withGeneralProperties(httpClient.newRequest(url)).timeout(config.timeout, TimeUnit.SECONDS) .method(HttpMethod.POST).content(new StringContentProvider(urlParameters)).send(); } catch (Exception e) { - throw new Exception("Request to RomyRobot device failed: " + e.getMessage()); + logger.error("Request to RomyRobot device failed: {}", e.getMessage()); + return ""; } if (response.getStatus() != HttpStatus.OK_200) { - throw new Exception( - "Error sending HTTP POST request to " + url + ". Got response code: " + response.getStatus()); + logger.error("Error sending HTTP POST request to {}. Got response code: {}", url, response.getStatus()); } return response.getContentAsString(); } @@ -352,12 +351,11 @@ public void executeCommand(String command) throws Exception { } if (strategy != null && !"REFRESH".equals(strategy)) { params.add("cleaning_strategy_mode=" + strategy); - } if (activePumpVolume != null) { params.add("pump_volume=" + activePumpVolume); } - if (params.size() > 0) { + if (params.isEmpty()) { query = String.join("&", params); } } else if ("redo_explore".equalsIgnoreCase(command) || "clean_map".equalsIgnoreCase(command)) { diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index caa060ee1a32..d1cefbd03605 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -77,7 +77,6 @@ public Set getSupportedThingTypeUIDs() { @Override public @Nullable DiscoveryResult createResult(ServiceInfo service) { - final ThingUID uid = getThingUID(service); if (uid == null) { logger.error("uid is null!"); @@ -112,8 +111,8 @@ public Set getSupportedThingTypeUIDs() { RomyRobotConfiguration config = new RomyRobotConfiguration(); config.hostname = address; RomyApi romyDevice = apiFactory.getHttpApi(config); - romyDevice.refresh_id(); - romyDevice.refresh_protocol_version(); + romyDevice.refreshID(); + romyDevice.refreshProtocolVersion(); robotName = romyDevice.getName(); logger.debug("New ROMY with the name: {}", robotName); } catch (Exception e) { From 90df8a0fe1060dc85f1c256ef575cc30af4ba793 Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Fri, 3 Nov 2023 11:01:49 +0100 Subject: [PATCH 44/45] more checkstyle cleanup Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/RomyRobotHandler.java | 42 ++++++++----------- .../romyrobot/internal/api/RomyApi.java | 4 +- .../romyrobot/internal/api/RomyApiV6.java | 16 ++----- .../RomyRobotMDNSDiscoveryParticipant.java | 15 +++---- 4 files changed, 29 insertions(+), 48 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java index 0221ad8f11ad..8992e3323c65 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/RomyRobotHandler.java @@ -23,6 +23,8 @@ import javax.validation.constraints.NotNull; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.romyrobot.internal.api.RomyApi; import org.openhab.binding.romyrobot.internal.api.RomyApiFactory; import org.openhab.core.library.types.DecimalType; @@ -45,12 +47,12 @@ * * @author Bernhard Kreuz - Initial contribution */ -// TODO @NonNullByDefault +@NonNullByDefault public class RomyRobotHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(RomyRobotHandler.class); private RomyRobotConfiguration config; - private ScheduledFuture pollingJob; + private @Nullable ScheduledFuture pollingJob; private RomyApi romyDevice; private RomyApiFactory apiFactory; private RomyRobotStateDescriptionOptionsProvider stateDescriptionProvider; @@ -117,17 +119,15 @@ public void refreshVacuum() { } private void updateChannels(RomyApi device) { - if (device != null) { - updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); - updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); - updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); - updateState(CHANNEL_BATTERY, QuantityType.valueOf(device.getBatteryLevel(), PERCENT)); - updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); - updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); - updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); - updateState(CHANNEL_AVAILABLE_MAPS_JSON, StringType.valueOf(device.getAvailableMapsJson())); - updateMapsList(device.getAvailableMaps()); - } + updateState(CHANNEL_FW_VERSION, StringType.valueOf(device.getFirmwareVersion())); + updateState(CHANNEL_MODE, StringType.valueOf(device.getModeString())); + updateState(CHANNEL_ACTIVE_PUMP_VOLUME, StringType.valueOf(device.getActivePumpVolume())); + updateState(CHANNEL_BATTERY, QuantityType.valueOf(device.getBatteryLevel(), PERCENT)); + updateState(CHANNEL_CHARGING, StringType.valueOf(device.getChargingStatus())); + updateState(CHANNEL_POWER_STATUS, StringType.valueOf(device.getPowerStatus())); + updateState(CHANNEL_RSSI, new DecimalType(device.getRssi())); + updateState(CHANNEL_AVAILABLE_MAPS_JSON, StringType.valueOf(device.getAvailableMapsJson())); + updateMapsList(device.getAvailableMaps()); } public void updateMapsList(HashMap maps) { @@ -150,22 +150,16 @@ private RomyApi setupAPI(RomyApiFactory apiFactory) throws Exception { } private RomyApi getRomyApi() throws Exception { - if (romyDevice == null) { - romyDevice = apiFactory.getHttpApi(config); - } + romyDevice = apiFactory.getHttpApi(config); return romyDevice; } @Override public void dispose() { - RomyApi localApi = romyDevice; - if (localApi != null) { - romyDevice = null; - } - ScheduledFuture localFuture = pollingJob; - if (localFuture != null) { - localFuture.cancel(true); - pollingJob = null; + final ScheduledFuture pollingJob = this.pollingJob; + if (pollingJob != null) { + pollingJob.cancel(true); + this.pollingJob = null; } } } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index 70ba0335ab92..a13de7b56c6b 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -15,13 +15,15 @@ import java.util.HashMap; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link RomyApi} interface defines the functions which are * controllable on the Romy API interface. * * @author Bernhard Kreuz - Initial contribution */ -// TODO @NonNullByDefault +@NonNullByDefault public interface RomyApi { /** diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java index 6a17b648641a..7eeb7f747f75 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; @@ -44,8 +43,8 @@ public class RomyApiV6 implements RomyApi { - private @NonNull String hostname; - private @NonNull RomyRobotConfiguration config; + private String hostname; + private RomyRobotConfiguration config; protected HttpRequestSender http; private String firmwareVersion = "UNKNOWN"; private String name; @@ -74,7 +73,7 @@ public class RomyApiV6 implements RomyApi { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - public RomyApiV6(final @NonNull HttpClient httpClient, final @NonNull RomyRobotConfiguration config) { + public RomyApiV6(final HttpClient httpClient, final RomyRobotConfiguration config) { this.config = config; if (config.hostname.startsWith("http://") || config.hostname.startsWith("https://")) { this.hostname = config.hostname; @@ -298,15 +297,6 @@ public String sendHttpGet(String url, @Nullable String urlParameters) throws Exc } private Request withGeneralProperties(Request request) { - // TODO: request header configuration - /* - * request.header(HttpHeader.USER_AGENT, USER_AGENT); - * if (!config.basicUsername.isEmpty() && !config.basicPassword.isEmpty()) { - * String encoded = Base64.getEncoder().encodeToString( - * (config.basicUsername + ":" + config.basicPassword).getBytes(StandardCharsets.UTF_8)); - * request.header(HttpHeader.AUTHORIZATION, "Basic " + encoded); - * } - */ return request; } diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java index d1cefbd03605..ce25e41ddf74 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/discovery/RomyRobotMDNSDiscoveryParticipant.java @@ -15,6 +15,7 @@ import static org.openhab.binding.romyrobot.internal.RomyRobotBindingConstants.*; import static org.openhab.core.thing.Thing.*; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -89,21 +90,15 @@ public Set getSupportedThingTypeUIDs() { String address = ""; String robotName = ""; String robotLabel = ""; - String robotUniqeId = ""; + String robotUniqeId = service.getName(); String[] hostAddresses = service.getHostAddresses(); - logger.debug("hostAddresses: {}", hostAddresses); - if ((hostAddresses == null) || (hostAddresses.length == 0)) { - logger.error("hostAddresses is null!"); - return null; - } - - robotUniqeId = service.getName(); - if ((hostAddresses == null) || (hostAddresses.length == 0)) { - logger.error("hostAddresses is null!"); + if (hostAddresses.length == 0) { + logger.error("hostAddresses is empty!"); return null; } + logger.debug("hostAddresses: {}", Arrays.toString(hostAddresses)); address = hostAddresses[0]; logger.debug("address: {}", address); From 9d7de4cc8795ab89244bf4d51f9d0485c281377d Mon Sep 17 00:00:00 2001 From: Manuel Dipolt Date: Fri, 3 Nov 2023 14:45:07 +0100 Subject: [PATCH 45/45] more checkstyle cleanup... Signed-off-by: Manuel Dipolt --- .../romyrobot/internal/api/RomyApi.java | 9 +++++ .../romyrobot/internal/api/RomyApiV6.java | 39 ++++++++++--------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java index a13de7b56c6b..bffa08468d18 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApi.java @@ -16,6 +16,7 @@ import java.util.HashMap; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; /** * The {@link RomyApi} interface defines the functions which are @@ -63,24 +64,28 @@ public interface RomyApi { * * @return Firmware Version of robot */ + @Nullable String getFirmwareVersion(); /** * * @return Firmware Version of robot */ + @Nullable String getName(); /** * * @return Status / Mode robot is currently in */ + @Nullable String getModeString(); /** * * @return currently set pump volume */ + @Nullable String getActivePumpVolume(); /** @@ -93,6 +98,7 @@ public interface RomyApi { * * @return cleaning strategy */ + @Nullable String getStrategy(); /** @@ -105,6 +111,7 @@ public interface RomyApi { * * @return suction mode, see thing xml for details */ + @Nullable String getSuctionMode(); /** @@ -123,6 +130,7 @@ public interface RomyApi { * * @return weither the vacuum is charging */ + @Nullable String getChargingStatus(); /** @@ -135,6 +143,7 @@ public interface RomyApi { * * @return current power status of the vacuum */ + @Nullable String getPowerStatus(); /** diff --git a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java index 7eeb7f747f75..695e49fabbe0 100644 --- a/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java +++ b/bundles/org.openhab.binding.romyrobot/src/main/java/org/openhab/binding/romyrobot/internal/api/RomyApiV6.java @@ -18,6 +18,7 @@ import java.util.List; 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.eclipse.jetty.client.api.ContentResponse; @@ -40,24 +41,24 @@ * * @author Bernhard Kreuz - Initial contribution */ - +@NonNullByDefault public class RomyApiV6 implements RomyApi { private String hostname; private RomyRobotConfiguration config; protected HttpRequestSender http; - private String firmwareVersion = "UNKNOWN"; - private String name; - private String mode; - private String activePumpVolume; - private String charging; + private @Nullable String firmwareVersion; + private @Nullable String name; + private @Nullable String mode; + private @Nullable String activePumpVolume; + private @Nullable String charging; private int batteryLevel; - private String powerStatus; - private String mapsJson; + private @Nullable String powerStatus; + private String mapsJson = ""; private int rssi; - private String strategy; - private String suctionMode; - private String selectedMap; + private @Nullable String strategy; + private @Nullable String suctionMode; + private @Nullable String selectedMap; // that was the newest version when this code was written private int protocolVersionMajor = 6; @@ -154,22 +155,22 @@ private void parseMaps(String jsonString) throws JsonMappingException, JsonProce } @Override - public String getFirmwareVersion() { + public @Nullable String getFirmwareVersion() { return firmwareVersion; } @Override - public String getName() { + public @Nullable String getName() { return name; } @Override - public String getModeString() { + public @Nullable String getModeString() { return mode; } @Override - public String getActivePumpVolume() { + public @Nullable String getActivePumpVolume() { return activePumpVolume; } @@ -179,7 +180,7 @@ public void setActivePumpVolume(String volume) { } @Override - public String getStrategy() { + public @Nullable String getStrategy() { return strategy; } @@ -189,7 +190,7 @@ public void setStrategy(String strategy) { } @Override - public String getSuctionMode() { + public @Nullable String getSuctionMode() { return suctionMode; } @@ -204,7 +205,7 @@ public int getBatteryLevel() { } @Override - public String getChargingStatus() { + public @Nullable String getChargingStatus() { return charging; } @@ -214,7 +215,7 @@ public int getRssi() { } @Override - public String getPowerStatus() { + public @Nullable String getPowerStatus() { return powerStatus; }