OH4 https request with http binding

Hi everyone,
I try to configure charging of the battery from grid, which requires the following http command:

curl --location 'https://192.168.178.78/lala.cgi' \
--header 'Content-Type: application/json' \
--data '{
    "ENERGY": {
        "SAFE_CHARGE_FORCE": "u8_01"
    }
}'

Now there are several options:

  1. create switch item without channel connection and trigger http post action in a rule
.items
Switch SenecHome_Battery_Charging "Charge battery from grid" 

.rules
rule "Charge battery from grid"
when
    Item SenecHome_Batterie_Laden received command ON
then
    val url = "https://192.168.178.78/lala.cgi"
    val content = '{"ENERGY":{"SAFE_CHARGE_FORCE": "u8_01"}}'
    sendHttpPostRequest(url, "application/json", content)
end

This does not work, because I get the following error:

2023-11-29 12:01:58.722 [ERROR] [enhab.core.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

The certificate of the senec is not valid / self signed or something similar. I am not really familiar with it.

next try:
2. configure a http switch thing
tried:

.things:
Thing http:url:senec_batt_charge "Senec Home Battery charging" [
    baseUrl="https://192.168.178.78/lala.cgi",
    commandMethod="POST",
    contentType="application/json",
    ignoreSSLErrors=true ] 
    {
        Channels:
            Type switch : Charge_Battery "Charge battery from grid" [
                commandTransformation="MAP:senec_batt.map",
                stateContent="",
                mode="WRITEONLY"
            ]
    }
senec_batt.map:
ON: {"ENERGY": {"SAFE_CHARGE_FORCE": "u8_01"}}
OFF: {"ENERGY": {"SAFE_CHARGE_PROHIBIT": "u8_01"}}

Actually, I could not find any configuration example for a switch on the www.
My apporach didn’t work, log tells:

Thing 'http:url:senec_batt_charge' changed from UNINITIALIZED to UNINITIALIZED (HANDLER_CONFIGURATION_PENDING): {baseURL=Der Parameter wird benötigt.}

sorry for German :wink:

Next try could be adding a new switch channel to the senec-home binding. But that would cost me a lot of time - I have absolutely no experience with binding development.

Someone can help me to get one of the first two solutions running?

My system: OH 4.1.0 M3

I’m going to guess that the problem is point to some sort of syntax error in your .things file. I hate fighting syntax errors which is why I don’t use file based configs any more. All I can suggest is set it up in the UI first and then once it works you can maybe translate that back to the .things file if you want to keep them.

1 Like

Have you tried to call your curl command by using a call to executeCommandLine ?

I try to fix syntax errors on my own - but without good examples for what I try to achieve, it is sometimes difficult to know, if I am on the right track.
Do you have any hint, where I could find good examples for .things configuration of Switch + http?

Will try it. Do you know, if I call curl that way, does it expect single quote or double quote notation?
But the other point is: From my perspective this solution would not really be openHAB-like. I typically try to stay within a concept for the sake of consistency before leaving it.

The HTTP binding docs? I assume there are some examples there.

I’ve long since given up on .things files because it’s nearly impossible to make a syntax error in the UI and I don’t have to look anything up to figure out the properties, what they mean, and the proper syntax. It’s all right there in front of me.

I want to spend my time addressing home automation problems, not syntax errors.

In your specific case, it’s most likely a mismatched opening/closing quote, [ ], or { }. If Google Translate translated the error correctly, it’s saying you don’t have a baseURL property. Since you clearly do something else must be wrong.

Here’s an example HTTP Thing with a Switch Channel created in the UI in case it helps.

UID: http:url:adguard
label: AdGuard
thingTypeUID: http:url
configuration:
  headers:
    - ""
  ignoreSSLErrors: true
  stateMethod: GET
  refresh: 30
  commandMethod: POST
  timeout: 3000
  authMode: BASIC_PREEMPTIVE
  baseURL: https://someipaddress:someport/control
  password: somepassword
  delay: 0
  contentType: application/json
  bufferSize: 2048
  username: someuser
channels:
  - id: protection_status
    channelTypeUID: http:switch
    label: Protection Status
    description: ""
    configuration:
      mode: READWRITE
      onValue: "true"
      commandTransformation: 'JINJA:{"protection_enabled": {{value}}}'
      offValue: "false"
      stateExtension: /status
      commandExtension: /dns_config
      stateTransformation: JSONPATH:$.protection_enabled

Some incomplete screenshots

So for your first attempt you ran into the condition of a self signed cert being used to establish the SSL connection.
In order for that to work you would have to trust that cert so you would need to export the cert from the device and import it into the cacerts file for your java install
Or possibly pass the correct argument to ignore certificate validation errors or alter the default .policy for your java to allow untrusted connections. I am not even sure that the later versions of java like 17 still allow that.
But as far as I know in order to establish an SSL connection within java the certificate has to be valid(pass CRL and valid date) and trusted or the security policy for the java instance has to be updated to allow for the vunarability.
It has been a while since I tried but I seem to recall curl has a option that will allow you to connect with a end point that has a untrusted certificate so that may just be the easier way as has been suggested.

I can execute this in the commandline:

curl --location "https://192.168.178.78/lala.cgi" --header "Content-Type: application/json" --data "{\"ENERGY\": {\"SAFE_CHARGE_FORCE\": \"u8_01\"}}" --insecure

and it works fine.

But escaping this gives me some headache. I tried in the rule:

executeCommandLine(Duration.ofSeconds(5), "curl --location \"https://192.168.178.78/lala.cgi\" --header \"Content-Type: application/json\" --data \"{\\\"ENERGY\\\": {\\\"SAFE_CHARGE_FORCE\\\": \\\"u8_01\\\"}}\" --insecure")

Still does not work as expected, it throws the following error:

2023-11-29 21:29:00.269 [WARN ] [rg.openhab.core.io.net.exec.ExecUtil] - Failed to execute commandLine '[curl --location "https://192.168.178.78/lala.cgi" --header "Content-Type: application/json" --data "{\"ENERGY\": {\"SAFE_CHARGE_FORCE\": \"u8_01\"}}" --insecure]'

which is strange, because the command line request looks exactly as expected (as the original one I sent over console)

Pay attention to the executeCommandLine docs. Each argument to the command should be passed as separate arguments to executeCommandLine. Also, use single quotes when the argument needs to include double quotes so you don’t need to escape them.

executeCommandLine(Duration.ofSeconds(5), "curl", "--location", '"https://192.168.178.78/lala.cgi\"',  "--header",  '"Content-Type: application/json\"',  "--data",  '"{"ENERGY": {"SAFE_CHARGE_FORCE": "u8_01"}}"',  "--insecure")

Thanks. As stated in my next comment, curl provides the --insecure option, which works fine for my use case.

Thanks for the hint. Obviously I didn’t know that. I try to get it running with that.
At least the error message is gone (but still, it does not start the battery charging…)

Evaluate the returned vakue/message of the curl command. It cam be assigned to a variable and error/warning/info logged.

return value from the curl command is:

curl: (3) URL using bad/illegal format or missing URL

I will try to get it fixed, or otherwise put the command in a .sh and call it. That should work, or not?

Yes that should work.

means that something is wrong with your command.

Unfortunately, I could not get it running by executeCommandLine.
I have chosen configuration through exec binding instead, because it seems more openHAB like than putting a shell script somewhere in the system.
First configured by UI, then doing the same in things conf file until the code in the UI looked the same (thanks, @rlkoshak for giving the hint to first try out with the UI - will do that more often in future. I am just worried about reconfiguring everything, if I have to move to a different device - or is there a solution for that?).

.things:

Thing exec:command:senec_battery_charging "Batterie laden aus Netz" [ command="curl --location \"https://192.168.178.78/lala.cgi\" --header \"Content-Type: application/json\" --data \"{\\\"ENERGY\\\": {\\\"SAFE_CHARGE_FORCE\\\": \\\"u8_01\\\"}}\" --insecure", interval=0, timeout=5, autorun=true ]

It is not allowed to use single quote for the command, therefore I had to escape both the backslash and the double quote.

misc/exec.whitelist:

curl --location "https://192.168.178.78/lala.cgi" --header "Content-Type: application/json" --data "{\"ENERGY\": {\"SAFE_CHARGE_FORCE\": \"u8_01\"}}" --insecure

this is the original request, which was as well successful in running in the console

.items:

Switch SenecHome_Batterie_Aufladen "Batterie Aufladen aus Netz" { channel="exec:command:senec_battery_charging:run" }

If I have more time, I still want to try out the http configuration, first through UI. It should work somehow…

The two are not mutually exclusive. It’s not unusual to have Exec calling a shell script somethwhere in the system.

Configuration is configuration. All that’s different is which files the configuration is stored in. openhab-cli backup captures all configuration, whether it’s managed (i.e. done in the UI) or in separate text files. And in fact in both cases the configs are kept as uman readable text files. They are just in different formats and in different locations.

It’s not unusual to have Exec calling a shell script somethwhere in the system.

I know some developers use to do it. I try to avoid it because of two reasons:

  • it is not fully transparent, what the automation is doing, unless you read the shell script
  • It will not be part of the backup done by openhab-cli backup

Or is there a misunderstanding on my side?

After I worked now some more on command execution, e.g. to restart bindings, I understand much better the overall logic of access rights and what the openhab user is allowed to do (and what not, by default). If someone else is reading this, I can recommend the following posts and topics:

I owe this topic still an answer, if I could get the switch with a http binding working. Didn’t have time to do it. Will work on it in the christmas vacation time.

That’s the case for anything. The same logic applies to libraries. Do you avoid their use because the code is not defined inline in the rule? That leads to a pretty miserable experience.

It will if that “somewhere else” is in /etc/openhab or /var/lib/openhab. Most people erroneously put them in /etc/openhab/scripts (which really has a different purpose) but anywhere in these two folders will get picked up by opnehab-cli. It doesn’t really make sense to put them anywhere else anyway.

Note that the working directory when OH runs a script is /var/lib/openhab. If you put the script in that folder you don’t need to use the full path to the script to call it.