Rademacher Homepilot (DuoFern) via http-Binding

Hi again :slight_smile:
I still have issues with timing - Although I have “only” 52 different stateExtensions at the moment, I get the error that 133 channels take way too long to refresh. I posted this here in another topic. Yet, I don’t know how it counts 133 channels. The channel count is over 250, the stateExtensions 52, as mentioned (but still growing). I have the impression that something is a bit awkward with the caching… but maybe my fault at another place. Help is appreciated :slight_smile:

Anyhow, maybe another kind of handling the issue with less HTTP requests.
I found that in addition to

http://<HomePilotIP>/v4/devices?devtype=Sensor

there is the address

http://<HomePilotIP>/v4/devices?devtype=Actuator
http://<HomePilotIP>/v4/devices?devtype=Scene
http://<HomePilotIP>/v4/devices?devtype=Trigger

Update
I thought this would be working as I found devtype=Actuator in various other forums.
Actually, meanwhile I found that only devtype=Sensor really yields a different result. Anything else, e.g. just http://<HomePilotIP>/v4/devices or even http://<HomePilotIP>/v4/devices?devtype=Foo has the same response from HomePilot. Unless somebody knows something else.

Nevertheless, this does not change what I mentioned before - requesting http://<HomePilotIP>/v4/devices gives you an overview of all actuators states, including setpoint and measurement values of the thermostats and seems to be very useful!

Update 2
Now I really found how to get the scenes: http://<HomePilotIP>/v4/scenes. :smiley:

Update 3 - breaking news!!
Following an idea, I checked what happens if I open the HomePilot configuration website and see what WireShark logs.

  • So first of all the news is: The config website is acually using the REST API as well meaning you can use the API for doing any action you can do on the config site!!!

  • If you configure Wireshark to filter for <HomePilotIP> and http you can see which addresses are used and which commands are being sent pretty easily when you just execute the action of your choice on the config website. With this, you can do anything on the HomePilot!

  • Some address extensions I found (some of which I have never seen documented at any place before):
    /v4/devices?devtype=Actuator (Actuators like switches etc.)
    /v4/devices?devtype=Camera (HomePilot supports cameras, but I don’t have one, so I can’t tell much about it.
    /v4/devices?devtype=Sensor This we knew already :slight_smile:
    /v4/devices?devtype=Transmitter (Transmitters with momentary events. I did not find a way to get actual events over the API, so this might still be interesting…)
    /v4/scenes mentioned before, the list of scenes incĺuding the Scene IDs (“SID”)
    /v4/groups/devicegroups (The list of device groups inside the HomePilot. Can’t tell much about it as I don’t use this feature).
    /automation/v2 The list of all automations, meaning triggers (“Auslöser”) including conditions and actions

  • with all this background, I found that it is actually possible to trigger a scene by a command, which gives you quite more control about the HomePilot system compared to controlling just the devices.
    It needs a certain JSON command, and other than device commands (which use PUT) it’s using the POST method. As the scenes are stateless, it does not really make sense to add them as Thing, but rather to use a script to trigger them.
    So, how to?
    – Look up the SID of your scene inside /v4/scenes.
    – Put it into this script:

var HTTP = Java.type("org.openhab.core.model.script.actions.HTTP");
var url = "http://<HomePilotIP>/scenes/<mySID>/actions";
var content = "application/json";
var cmd = "{\"request_type\":\"EXECUTESCENE\", \"trigger_event\":\"TRIGGER_SCENE_MANUALLY_EVT\"}"
var result = HTTP.sendHttpPostRequest(url, content, cmd, 10*1000);

…and watch it go! :smiley:

By the way: The scenes support two more trigger events (apart from TRIGGER_SCENE_MANUALLY_EVT, which is the manual trigger as you do by activating the scene in the config website):
SCENE_MODE_CMD (Not really sure what it is)
AUTOMATION_MODE_CMD (Probably the mode which is used by an internal trigger event).

UPDATE 4
In this short thread, we found a solution to automate the triggering of the scenes with just one rule and one item and you can call these rules by their clear names used in the HomePilot.

For having it all here, this is how it goes:

  • Create an String Item, e.g. HomePilot_Scene_Trigger.
  • Create a DSL rule which triggers on any update of this item:
val HomePilotIP = "192.168.1.5";
val timeout = 3000;
var sceneName = HomePilot_Scene_Trigger.state.toString;
var searchString = "$.scenes[?(@.name==\"" + sceneName + "\")].sid";
var scene_url = "http://" + HomePilotIP + "/v4/scenes";
var JsonSceneMap = sendHttpGetRequest(scene_url, timeout);
if (JsonSceneMap == null) {
  logError("homepilot.scenetrigger", "HTTP GET request to {} failed!", scene_url);
} else {
  var SID = transform("JSONPATH", searchString, JsonSceneMap);
  if (SID == "NULL") {
    logWarn("homepilot.scenetrigger", "Scene Name \'{}\' was not found!", sceneName);
  } else {
    logInfo("homepilot.scenetrigger", "Scene Name \'{}\' found --> SID {}.",sceneName, SID);
    var cmd_url = "http://" + HomePilotIP + "/scenes/" + SID + "/actions";
    var cmd = "{\"request_type\":\"EXECUTESCENE\", \"trigger_event\":\"TRIGGER_SCENE_MANUALLY_EVT\"}"
    var result = sendHttpPostRequest(cmd_url, "application/json", cmd, timeout);
    if (result == null) {
      logError("homepilot.scenetrigger", "HTTP POST request to {} failed!", cmd_url);
    } else {
      if (result == "{\"error_description\":\"OK\",\"error_code\":0}") {
        logInfo("homepilot.scenetrigger", "Scene trigger for \'{}\' was successful.",sceneName);
      } else {
        logError("homepilot.scenetrigger", "Scene trigger for \'{}\' failed, error message: {}.",sceneName, result);
      }
    }
  }
}
  • Anytime you update the Item with a scene name, it will lookup the SID and trigger the scene.
  • The only configuration to be done: the first two lines - set the IP of your HomePilot and the desired HTTP timeout. :slight_smile:
  • little update to the first version: now with handling of typical errors and console logging.

UPDATE 5
Found some more interesting sites of the HomePilot API:

  • http://<HomePilotIP>/automation/v2/options seems to be a list of capabilities and possible commands to many devices and actuators
  • http://<HomePilotIP>/service/system/twilight returns a JSON with the current Civil Dawn / Civil Dusk used by HomePilot as Unix Timestamps
  • http://<HomePilotIP>/automation as already mentioned, the whole dataset of automations and triggers. Most important, it contains the name strings of the automations and the automation IDs (it’s just called “ID” at this place).
  • http://<HomePilotIP>/automation/v2/<ID> the individual special information for the automation with the selected ID

Have an automation with manual trigger (offers more options than scenes, esp. timed and ordered commands!) and want to start this from OH? Here you go:

sendHttpPostRequest("http://<HomePilotIP>/automation/v2/<ID>/actions", 
                    "application/json", 
                    "{\"request_type\":\"EXECUTEAUTOMATION\"}", 
                    3000);

with usually being a 4-digit number. The automation must be set to be triggered manually, otherwise it won’t work.

UPDATE 6
Similar to the scene execution by name, here is manual automation (“Auslöser”) execution by name.

val HomePilotIP = "192.168.1.5";
val timeout = 3000;
var automationName = HomePilot_Automation_Trigger.state.toString;
var searchString = "$.automation[?(@.automation.name==\"" + automationName + "\")]automation.id";
var isManualString = "$.automation[?(@.automation.name==\"" + automationName + "\")]is_manual_executable";
var automation_url = "http://" + HomePilotIP + "/automation/v2";
var JsonAutomationMap = sendHttpGetRequest(automation_url, timeout);
if (JsonAutomationMap == null) {
  logError("homepilot.automationtrigger", "HTTP GET request to {} failed!", automation_url);
} else {
  var ID = transform("JSONPATH", searchString, JsonAutomationMap);
  if (ID == "NULL") {
    logWarn("homepilot.automationtrigger", "Automation Name \'{}\' was not found!", automationName);
  } else {
    logInfo("homepilot.automationtrigger", "Automation Name \'{}\' found --> ID {}.",automationName, ID);
    var isManual = transform("JSONPATH", isManualString, JsonAutomationMap);
    if (isManual != "true") {
      logWarn("homepilot.automationtrigger", "Automation \'{}\' is not manually executable!", automationName);
    } else {
      var cmd_url = "http://" + HomePilotIP + "/automation/v2/" + ID + "/actions";
      var cmd = "{\"request_type\":\"EXECUTEAUTOMATION\"}";
      var result = sendHttpPostRequest(cmd_url, "application/json", cmd, timeout);
      if (result == null) {
        logError("homepilot.automationtrigger", "HTTP POST request to {} failed!", cmd_url);
      } else {
        if (result == "{\"error_description\":\"OK\",\"error_code\":0}") {
          logInfo("homepilot.automationtrigger", "Automation trigger for \'{}\' was successful.",automationName);
        } else {
          logError("homepilot.automationtrigger", "Automation trigger for \'{}\' failed, error message: {}.",automationName, result);
        }
      }
    }
  }
}

All you need to do is to create a string item HomePilot_Automation_Trigger, use updates on this item to trigger the above script.
It will look up the automation name, check if it’s actually manually executable and then trigger it. The most common errors are handled and appear in the console.