]> git.basschouten.com Git - openhab-addons.git/commitdiff
[somfytahoma] Open to other portals (#10611)
authorlolodomo <lg.hc@free.fr>
Sun, 9 May 2021 18:16:14 +0000 (20:16 +0200)
committerGitHub <noreply@github.com>
Sun, 9 May 2021 18:16:14 +0000 (20:16 +0200)
* [somfytahoma] Open to other portals

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
* Review comment: suppress the advanced setting for cookie handling

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.somfytahoma/README.md
bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java
bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/config/SomfyTahomaConfig.java
bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java
bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/binding/binding.xml
bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/config/config.xml
bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/bridge.xml

index bb2536fec36e4b61d6390b797f9c2bf94e215ee4..f44a5ed69e12230431a0995571f15764c1ef08ca 100644 (file)
@@ -5,13 +5,14 @@ This binding integrates the
 and
 [Somfy Connexoon](https://www.somfy.fr/produits/1811429/)
 home automation systems.
+Any home automation system based on the OverKiz API is potentially supported.
 
 ## Supported Things
 
  Currently these things are supported:
 
-- bridge (Somfy Tahoma bridge, which can discover gateways, roller shutters, awnings, switches and action groups)
-- gateways (Somfy Tahoma gateway - gateway status)
+- bridge (cloud bridge, which can discover gateways, roller shutters, awnings, switches and action groups)
+- gateways (gateway status)
 - gates (control gate, get state)
 - roller shutters (UP, DOWN, STOP control of a roller shutter). IO Homecontrol devices are allowed to set exact position of a shutter (0-100%)
 - blinds (UP, DOWN, STOP control of a blind). IO Homecontrol devices are allowed to set exact position of a blinds (0-100%) as well as orientation of slats (0-100%)
@@ -46,10 +47,10 @@ Both Somfy Tahoma and Somfy Connexoon gateways have been confirmed working.
 
 To start a discovery, just
  
-- Add a new Somfy Tahoma bridge thing.
-- Configure the bridge with your email (login) and password to the TahomaLink cloud portal.
+- Add a new bridge thing.
+- Configure the bridge selecting your cloud portal (www.tahomalink.com by default) and setting your email (login) and password to the cloud portal.
  
-If the supplied TahomaLink credentials are correct, the automatic discovery can be used to scan and detect roller shutters, awnings, switches and action groups that will appear in your Inbox. 
+If the supplied credentials are correct, the automatic discovery can be used to scan and detect roller shutters, awnings, switches and action groups that will appear in your Inbox. 
 
 ## Thing Configuration
 
@@ -61,7 +62,7 @@ Please see the example below.
 | Thing                                                                         | Channel                      | Note                                                                                                                        |
 |-------------------------------------------------------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
 | bridge                                                                        | N.A                          | bridge does not expose any channel                                                                                          |
-| gateway                                                                       | status                       | status of your Tahoma gateway                                                                                               |
+| gateway                                                                       | status                       | status of your gateway                                                                                                      |
 | gateway                                                                       | scenarios                    | used to run the scenarios defined in the cloud portal                                                                       |
 | gate                                                                          | gate_command                 | used for controlling your gate (open, close, stop, pedestrian)                                                              |
 | gate                                                                          | gate_state                   | get state of your gate (open, closed, pedestrian)                                                                           |
index 5e5fe956189021d65669d6b3c156a555e0adc66e..8d27c2f73010b97a02447b9cb62c80db32369be4 100644 (file)
@@ -26,6 +26,7 @@ import org.openhab.core.thing.ThingTypeUID;
  * used across the whole binding.
  *
  * @author Ondrej Pecta - Initial contribution
+ * @author Laurent Garnier - Other portals integration
  */
 @NonNullByDefault
 public class SomfyTahomaBindingConstants {
@@ -280,13 +281,14 @@ public class SomfyTahomaBindingConstants {
     public static final String SHUTTER = "shutter";
 
     // Constants
-    public static final String TAHOMA_API_URL = "https://www.tahomalink.com/enduser-mobile-web/enduserAPI/";
-    public static final String TAHOMA_EVENTS_URL = TAHOMA_API_URL + "events/";
-    public static final String SETUP_URL = TAHOMA_API_URL + "setup/";
+    public static final String TAHOMA_PORTAL = "www.tahomalink.com";
+    public static final String API_BASE_URL = "/enduser-mobile-web/enduserAPI/";
+    public static final String EVENTS_URL = "events/";
+    public static final String SETUP_URL = "setup/";
     public static final String GATEWAYS_URL = SETUP_URL + "gateways/";
     public static final String DEVICES_URL = SETUP_URL + "devices/";
     public static final String REFRESH_URL = DEVICES_URL + "states/refresh";
-    public static final String EXEC_URL = TAHOMA_API_URL + "exec/";
+    public static final String EXEC_URL = "exec/";
     public static final String DELETE_URL = EXEC_URL + "current/setup/";
     public static final String TAHOMA_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36";
     public static final int TAHOMA_TIMEOUT = 5;
@@ -415,6 +417,7 @@ public class SomfyTahomaBindingConstants {
             put(29, "TAHOMA_V2");
             put(30, "KIZBOX_V2_3H");
             put(31, "KIZBOX_V2_2H");
+            put(32, "COZYTOUCH");
             put(34, "CONNEXOON");
             put(35, "JSW_CAMERA");
             put(37, "KIZBOX_MINI_DAUGHTERBOARD");
index 5ead6ad4d366e8d3ba6635cbe1b1f2a33c91dacb..8f377521820b4501c71985f68b95a113952c7f4a 100644 (file)
 package org.openhab.binding.somfytahoma.internal.config;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants;
 
 /**
  * The {@link SomfyTahomaConfig} is is the base class for configuration
  * information held by devices and modules.
  *
  * @author Ondrej Pecta - Initial contribution
+ * @author Laurent Garnier - new parameter portalUrl
  */
 @NonNullByDefault
 public class SomfyTahomaConfig {
+    private String cloudPortal = SomfyTahomaBindingConstants.TAHOMA_PORTAL;
     private String email = "";
     private String password = "";
     private int refresh = 30;
@@ -29,6 +32,10 @@ public class SomfyTahomaConfig {
     private int retries = 10;
     private int retryDelay = 1000;
 
+    public String getCloudPortal() {
+        return cloudPortal;
+    }
+
     public String getEmail() {
         return email;
     }
@@ -53,6 +60,10 @@ public class SomfyTahomaConfig {
         return retryDelay;
     }
 
+    public void setCloudPortal(String cloudPortal) {
+        this.cloudPortal = cloudPortal;
+    }
+
     public void setEmail(String email) {
         this.email = email;
     }
index daa3b4c417d6dac1d6284e0a81e9a4d0a4f421ac..e722b74cab40f1944c8d0637b0f9a479162d57d6 100644 (file)
@@ -73,6 +73,7 @@ import com.google.gson.JsonSyntaxException;
  * sent to one of the channels.
  *
  * @author Ondrej Pecta - Initial contribution
+ * @author Laurent Garnier - Other portals integration
  */
 @NonNullByDefault
 public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
@@ -193,8 +194,6 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     }
 
     public synchronized void login() {
-        String url;
-
         if (thingConfig.getEmail().isEmpty() || thingConfig.getPassword().isEmpty()) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
                     "Can not access device as username and/or password are null");
@@ -214,11 +213,10 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
         reLoginNeeded = false;
 
         try {
-            url = TAHOMA_API_URL + "login";
             String urlParameters = "userId=" + urlEncode(thingConfig.getEmail()) + "&userPassword="
                     + urlEncode(thingConfig.getPassword());
 
-            ContentResponse response = sendRequestBuilder(url, HttpMethod.POST)
+            ContentResponse response = sendRequestBuilder("login", HttpMethod.POST)
                     .content(new StringContentProvider(urlParameters),
                             "application/x-www-form-urlencoded; charset=UTF-8")
                     .send();
@@ -235,7 +233,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
             } else if (data.isSuccess()) {
                 logger.debug("SomfyTahoma version: {}", data.getVersion());
                 String id = registerEvents();
-                if (id != null && !id.equals(UNAUTHORIZED)) {
+                if (id != null && !UNAUTHORIZED.equals(id)) {
                     eventsId = id;
                     logger.debug("Events id: {}", eventsId);
                     updateStatus(ThingStatus.ONLINE);
@@ -254,7 +252,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Received invalid data (login)");
         } catch (ExecutionException e) {
             if (isAuthenticationChallenge(e)) {
-                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Authentication challenge");
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                        "Error logging in (check your credentials)");
                 setTooManyRequests();
             } else {
                 logger.debug("Cannot get login cookie", e);
@@ -270,14 +269,15 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     }
 
     private void setTooManyRequests() {
-        logger.debug("Too many requests error, suspending activity for {} seconds", SUSPEND_TIME);
+        logger.debug("Too many requests or bad credentials for the cloud portal, suspending activity for {} seconds",
+                SUSPEND_TIME);
         tooManyRequests = true;
         scheduler.schedule(this::enableLogin, SUSPEND_TIME, TimeUnit.SECONDS);
     }
 
     private @Nullable String registerEvents() {
-        SomfyTahomaRegisterEventsResponse response = invokeCallToURL(TAHOMA_EVENTS_URL + "register", "",
-                HttpMethod.POST, SomfyTahomaRegisterEventsResponse.class);
+        SomfyTahomaRegisterEventsResponse response = invokeCallToURL(EVENTS_URL + "register", "", HttpMethod.POST,
+                SomfyTahomaRegisterEventsResponse.class);
         return response != null ? response.getId() : null;
     }
 
@@ -294,8 +294,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     }
 
     private List<SomfyTahomaEvent> getEvents() {
-        SomfyTahomaEvent[] response = invokeCallToURL(TAHOMA_API_URL + "events/" + eventsId + "/fetch", "",
-                HttpMethod.POST, SomfyTahomaEvent[].class);
+        SomfyTahomaEvent[] response = invokeCallToURL(EVENTS_URL + eventsId + "/fetch", "", HttpMethod.POST,
+                SomfyTahomaEvent[].class);
         return response != null ? List.of(response) : List.of();
     }
 
@@ -357,13 +357,13 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     }
 
     public List<SomfyTahomaActionGroup> listActionGroups() {
-        SomfyTahomaActionGroup[] list = invokeCallToURL(TAHOMA_API_URL + "actionGroups", "", HttpMethod.GET,
+        SomfyTahomaActionGroup[] list = invokeCallToURL("actionGroups", "", HttpMethod.GET,
                 SomfyTahomaActionGroup[].class);
         return list != null ? List.of(list) : List.of();
     }
 
     public @Nullable SomfyTahomaSetup getSetup() {
-        SomfyTahomaSetup setup = invokeCallToURL(TAHOMA_API_URL + "setup", "", HttpMethod.GET, SomfyTahomaSetup.class);
+        SomfyTahomaSetup setup = invokeCallToURL("setup", "", HttpMethod.GET, SomfyTahomaSetup.class);
         if (setup != null) {
             saveDevicePlaces(setup.getDevices());
         }
@@ -591,7 +591,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     private void logout() {
         try {
             eventsId = "";
-            sendGetToTahomaWithCookie(TAHOMA_API_URL + "logout");
+            sendGetToTahomaWithCookie("logout");
         } catch (ExecutionException | TimeoutException e) {
             logger.debug("Cannot send logout command!", e);
         } catch (InterruptedException e) {
@@ -626,7 +626,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
 
     private String sendMethodToTahomaWithCookie(String url, HttpMethod method, String urlParameters)
             throws InterruptedException, ExecutionException, TimeoutException {
-        logger.trace("Sending {} to url: {} with data: {}", method.asString(), url, urlParameters);
+        logger.trace("Sending {} to url: {} with data: {}", method.asString(), getApiFullUrl(url), urlParameters);
         Request request = sendRequestBuilder(url, method);
         if (!urlParameters.isEmpty()) {
             request = request.content(new StringContentProvider(urlParameters), "application/json;charset=UTF-8");
@@ -644,10 +644,15 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
         return response.getContentAsString();
     }
 
-    private Request sendRequestBuilder(String url, HttpMethod method) {
-        return httpClient.newRequest(url).method(method).header(HttpHeader.ACCEPT_LANGUAGE, "en-US,en")
-                .header(HttpHeader.ACCEPT_ENCODING, "gzip, deflate").header("X-Requested-With", "XMLHttpRequest")
-                .timeout(TAHOMA_TIMEOUT, TimeUnit.SECONDS).agent(TAHOMA_AGENT);
+    private Request sendRequestBuilder(String subUrl, HttpMethod method) {
+        return httpClient.newRequest(getApiFullUrl(subUrl)).method(method)
+                .header(HttpHeader.ACCEPT_LANGUAGE, "en-US,en").header(HttpHeader.ACCEPT_ENCODING, "gzip, deflate")
+                .header("X-Requested-With", "XMLHttpRequest").timeout(TAHOMA_TIMEOUT, TimeUnit.SECONDS)
+                .agent(TAHOMA_AGENT);
+    }
+
+    private String getApiFullUrl(String subUrl) {
+        return "https://" + thingConfig.getCloudPortal() + API_BASE_URL + subUrl;
     }
 
     public void sendCommand(String io, String command, String params, String url) {
@@ -672,7 +677,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     }
 
     private boolean sendCommandInternal(String io, String command, String params, String url) {
-        String value = params.equals("[]") ? command : command + " " + params.replace("\"", "");
+        String value = "[]".equals(params) ? command : command + " " + params.replace("\"", "");
         String urlParameters = "{\"label\":\"" + getThingLabelByURL(io) + " - " + value
                 + " - openHAB\",\"actions\":[{\"deviceURL\":\"" + io + "\",\"commands\":[{\"name\":\"" + command
                 + "\",\"parameters\":" + params + "}]}]}";
@@ -799,11 +804,10 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
     @Override
     public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
         super.handleConfigurationUpdate(configurationParameters);
-        if (configurationParameters.containsKey("email")) {
-            thingConfig.setEmail(configurationParameters.get("email").toString());
-        }
-        if (configurationParameters.containsKey("password")) {
-            thingConfig.setPassword(configurationParameters.get("password").toString());
+        if (configurationParameters.containsKey("email") || configurationParameters.containsKey("password")
+                || configurationParameters.containsKey("portalUrl")) {
+            reLoginNeeded = true;
+            tooManyRequests = false;
         }
     }
 
@@ -841,11 +845,11 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
             if (isAuthenticationChallenge(e)) {
                 reLogin();
             } else {
-                logger.debug("Cannot call url: {} with params: {}!", url, urlParameters, e);
+                logger.debug("Cannot call url: {} with params: {}!", getApiFullUrl(url), urlParameters, e);
                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
             }
         } catch (TimeoutException e) {
-            logger.debug("Timeout when calling url: {} with params: {}!", url, urlParameters, e);
+            logger.debug("Timeout when calling url: {} with params: {}!", getApiFullUrl(url), urlParameters, e);
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
         } catch (InterruptedException e) {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
index 44eba9c875f1efbe08c2fee1867b65b1abda1d04..5c0a631b071bb3b58403fbd90b17428737dd2be5 100644 (file)
@@ -4,6 +4,7 @@
        xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
 
        <name>SomfyTahoma Binding</name>
-       <description>This is the binding for SomfyTahoma.</description>
+       <description>This is the binding for Somfy Tahoma and Somfy Connexoon home automation systems and for any other system
+               based on the OverKiz API.</description>
 
 </binding:binding>
index 850f0de260045281a285b6865e6a357155036c9a..5bffde7cc5398c2d1e9abd3d06eca9bbd2265adf 100644 (file)
        </config-description>
 
        <config-description uri="bridge-type:somfytahoma:bridge">
+               <parameter name="cloudPortal" type="text" required="false">
+                       <label>Cloud Portal</label>
+                       <description>Cloud portal to connect to</description>
+                       <options>
+                               <option value="www.tahomalink.com">Somfy TaHoma / Somfy Connexoon IO / Somfy (Europe)</option>
+                               <option value="ha201-1.overkiz.com">Somfy Connexoon RTS / Somfy (Australia)</option>
+                               <option value="ha401-1.overkiz.com">Somfy (North America)</option>
+                               <option value="ha110-1.overkiz.com">Cozytouch</option>
+                               <option value="ha101-1.overkiz.com">eedomus</option>
+                               <option value="ha117-1.overkiz.com">Hi Kumo</option>
+                               <option value="ha112-1.overkiz.com">Rexel Energeasy Connect</option>
+                       </options>
+                       <default>www.tahomalink.com</default>
+                       <limitToOptions>false</limitToOptions>
+               </parameter>
+
                <parameter name="email" type="text" required="true">
                        <label>Email Address</label>
-                       <description>Email address for TahomaLink portal</description>
+                       <description>Email address for the portal</description>
                </parameter>
 
                <parameter name="password" type="text" required="true">
                        <context>password</context>
                        <label>Password</label>
-                       <description>Password for TahomaLink portal</description>
+                       <description>Password for the portal</description>
                </parameter>
 
                <parameter name="refresh" type="integer" required="false" min="10">
                        <label>Refresh</label>
-                       <description>Specifies the refresh time in seconds for polling events from Tahoma cloud</description>
+                       <description>Specifies the refresh time in seconds for polling events from the cloud</description>
                        <default>30</default>
                </parameter>
 
                <parameter name="statusTimeout" type="integer" required="false" min="60">
                        <label>Status Timeout</label>
-                       <description>Specifies the timeout in seconds after which the status is got from Tahoma cloud</description>
+                       <description>Specifies the timeout in seconds after which the status is got from the cloud</description>
                        <default>300</default>
                </parameter>
 
index 68b2488126a5714063957eecc398707f500ddd38..052c411b331eed5f5c7b4c103b625acdc397b77d 100644 (file)
@@ -6,8 +6,8 @@
 
        <!-- Bridge -->
        <bridge-type id="bridge">
-               <label>Somfy Tahoma Bridge</label>
-               <description>Somfy Tahoma bridge enabling communication with Somfy devices</description>
+               <label>Bridge</label>
+               <description>Bridge enabling communication with devices through a cloud portal</description>
 
                <config-description-ref uri="bridge-type:somfytahoma:bridge"/>
        </bridge-type>