executeCommandLine + curl difficulties

Hi all,
this ‘adventure’ started around 48 hours ago when the sensibo rules I have had in place for around 18 months and that was working fine suddenly stopped working.

Some detailed background:
The rule used -sSH options and no longer works. I have successfully changed the GET API calls to sensibo to work using the -sX GET curl options. see the example change below

WAS

executeCommandLine('curl -sSH "Accept: application/json"     "https://home.sensibo.com/api/v2/users/me/pods?apiKey=' + APIKey + '"', 10000)

NOW

executeCommandLine('curl -sX GET \"https://home.sensibo.com/api/v2/users/me/pods?apiKey=' + APIKey + '\"', 10000)

Next after retrieving the PodID value to be used using the APIKey I need to write values to Sensiblo I have become stuck, I can easily send the command using curl from the command line but the same command gets a 400 Bad Request response when using executeCommandLine in a rule, see the example rule below followed by the log extract. sending the command in CLI works.

Note: The commented out line has the original POST curl expression that was working and no longer does.

RULE:

rule "test on rule"
when
	Item Test received command ON
then
	logInfo("Test.rules", "Command was " + receivedCommand.toString)
	var String CommandURL = 'https://home.sensibo.com/api/v2/pods/' + PodID + '/acStates?apiKey=' + APIKey
	var String CommandData = '\'{"acState":{"on":true}}\''
	var String UpdateResult

	logInfo("Sensibo URL", CommandURL.toString)
	logInfo("Sensibo command", CommandData.toString)
	var String UpdateCMD = 'curl -sX POST ' + CommandURL + ' -d '+ CommandData
	logInfo("test curl command", UpdateCMD.toString)
	//UpdateResult = executeCommandLine('curl@@-sSH@@"Content-Type: application/json"@@-XPOST@@' + CommandURL + '@@-d@@'+ CommandData, 10000)
	UpdateResult = executeCommandLine(UpdateCMD, 10000)
	logInfo("Sensibo result", UpdateResult.toString)
end

LOG:

2019-07-16 14:26:45.134 [ome.event.ItemCommandEvent] - Item 'Test' received command ON

2019-07-16 14:26:45.473 [INFO ] [se.smarthome.model.script.Test.rules] - Command was ON

2019-07-16 14:26:45.474 [INFO ] [e.smarthome.model.script.Sensibo URL] - https://home.sensibo.com/api/v2/pods/<DEVICE_ID>/acStates?apiKey=<APIKEY>

2019-07-16 14:26:45.475 [INFO ] [arthome.model.script.Sensibo command] - '{"acState":{"on":true}}'

2019-07-16 14:26:45.477 [INFO ] [thome.model.script.test curl command] - curl -sX POST https://home.sensibo.com/api/v2/pods/<DEVICE_ID>/acStates?apiKey=<APIKEY>-d '{"acState":{"on":true}}'

2019-07-16 14:26:47.273 [INFO ] [marthome.model.script.Sensibo result] - <html><head><title>400 BadRequest - Sensibo</title></head><body><h>400 BadRequest</h><p>POST data is not valid JSON</p><body></html>

Using the output shown in the log

curl -sX POST https://home.sensibo.com/api/v2/pods/<DEVICE_ID>/acStates?apiKey=<APIKEY> -d '{"acState":{"on":true}}'

I am not sure why it stopped working but my attempts to re-enginer it using different curl options has come to a brick wall.
Look for some expert advise.

I do believe it is complaing about the data payload and I suspect its something to do with the single and double quotes that are becoming difficult to work with when wrapped in executeCommandLine.

Regards

Paul

This is my file rules, you try to compare

val String APIKey = "vqS6kBwfZKDt1eYoo46Al9bv71MbZs"

var PodID = "vGu2Fiat" 

rule "Read Sensibo State"

  when
    System started or
    Time cron "0/15 * * ? * * *" //Update states from senibo every 15 sec
  then

  //Thread::sleep(1000)

  try {
    var String PodStatus 
      
    do {
      PodStatus = executeCommandLine('curl -sX GET "https://home.sensibo.com/api/v2/pods/' + PodID + '?apiKey=' + APIKey + '&fields=acState,measurements" -A -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0"', 5000)
      //logInfo("Sensibo result - PodStatus", PodStatus)
    } while (!PodStatus.contains('"status": "success"'))
    
    //val String PodOn = (transform("JSONPATH", "$.result[0].acState.on", PodStatus))
    //val String PodMode = (transform("JSONPATH", "$.result[0].acState.mode", PodStatus))
    //val Number PodTarget = new Integer(transform("JSONPATH", "$.result[0].acState.targetTemperature", PodStatus))
    //val String PodFan = (transform("JSONPATH", "$.result[0].acState.fanLevel", PodStatus))

	// power status
		val String PodOn = (transform("JSONPATH", "$.result.acState.on", PodStatus))
			if (PodOn == "true")
				{ postUpdate(Sensibo_State, ON) }

			if (PodOn == "false")
				{ postUpdate(Sensibo_State, OFF) }
    //postUpdate(Sensibo_State, PodOn)
	
	// mode status
		var String SensiboModeTransform = (transform("JSONPATH", "$.result..mode", PodStatus))

		var String SensiboModeTransformString = (SensiboModeTransform.replace('["', '').replace('"]', ''))
		postUpdate(Sensibo_Mode, SensiboModeTransformString)
	//postUpdate(Sensibo_Mode, PodMode)

    // set temperature
		if (PodStatus.contains('"targetTemperature": ')) {

			var String SensiboTargetTransform = (transform("JSONPATH", "$.result..targetTemperature", PodStatus))

			var String SensiboTargetTransformString = (SensiboTargetTransform.replace('[', '').replace(']', ''))

			val Number SensiboTargetValue = new Double(SensiboTargetTransformString)

			postUpdate(Sensibo_Target, SensiboTargetValue)

		}
	//postUpdate(Sensibo_Target, PodTarget)
    
	// fan status
		if (PodStatus.contains('"fanLevel": ')) {

			var String SensiboFanTransform = (transform("JSONPATH", "$.result..fanLevel", PodStatus))

			var String SensiboFanTransformString = (SensiboFanTransform.replace('["', '').replace('"]', ''))

			postUpdate(Sensibo_Fan, SensiboFanTransformString)

		}
    //postUpdate(Sensibo_Fan, PodFan)

	// swing status
		if (PodStatus.contains('"swing": ')) {
			var String SensiboSwingTransform = (transform("JSONPATH", "$.result..swing", PodStatus))

			var String SensiboSwingTransformString = (SensiboSwingTransform.replace('["', '').replace('"]', ''))

			postUpdate(Sensibo_Swing, SensiboSwingTransformString)
		}
    /*
	if (PodStatus.contains('"swing": ')) {
      val String PodSwing = (transform("JSONPATH", "$.result[0].acState.swing", PodStatus))
      postUpdate(Sensibo_Swing, PodSwing)
    }
	}
	*/
	
	// temperature
	var String SensiboTemperatureTransform = (transform("JSONPATH", "$.result.measurements.temperature", PodStatus))

	var String SensiboTemperatureTransformString = (SensiboTemperatureTransform.replace('[', '').replace(']', ''))

	var Number SensiboTemperatureValue = new Double(SensiboTemperatureTransformString)

	postUpdate(Sensibo_Temp, SensiboTemperatureValue)
	
	// humidity
	var String SensiboHumidityTransform = (transform("JSONPATH", "$.result.measurements.humidity", PodStatus))

	var String SensiboHumidityTransformString = (SensiboHumidityTransform.replace('[', '').replace(']', ''))

	var Number SensiboHumidityValue = new Double(SensiboHumidityTransformString)

	postUpdate(Sensibo_Humidity, SensiboHumidityValue)
	
  }
  catch(Throwable t) {
  //  logError("Sensibo read state", "Error was caught: {}", t)
  }

  end

rule "Write Sensibo"

  when
    Item Sensibo_State received command or
    Item Sensibo_Mode received command or
    Item Sensibo_Fan received command or
    Item Sensibo_Swing received command or
    Item Sensibo_Target received command
  then
  
  try {

    Thread::sleep(1000)         // Avoid race condition where state has not yet been updated

	var Boolean PodBoolean

    if (Sensibo_State.state == ON)
      { PodBoolean = true }
    else
      { PodBoolean = false }
	
    var CommandURL = 'https://home.sensibo.com/api/v2/pods/' + PodID + '/acStates?apiKey=' + APIKey

    var CommandState = '{"acState":{"on":' + PodBoolean + ','
    var CommandMode = '"mode":"' + Sensibo_Mode.state + '",'
    var CommandFan = '"fanLevel":"' + Sensibo_Fan.state + '",'
    var CommandSwing = ""

    if (Sensibo_Swing.state != "")
      { CommandSwing = '"swing":"' + Sensibo_Swing.state + '"}}' }

    var String CommandTemp = '"targetTemperature":' + (Sensibo_Target.state as DecimalType).intValue + ','
    var String CommandData = CommandState + CommandMode + CommandFan + CommandTemp + CommandSwing

    var String UpdateResult
    var Number Attempts = 0

    //var CommandExec = 'curl@@-sSH@@"Accept: application/json"@@-H@@"Content-Type: application/json"@@-X@@POST@@-d@@' + CommandData + '@@' + CommandURL
  
    do {
      Attempts += 1
      logInfo("Sensibo command", CommandData)
      UpdateResult = executeCommandLine('curl@@-sSH@@"Content-Type: application/json"@@-XPOST@@' + CommandURL + '@@-d@@'+ CommandData, 10000)
      logInfo("Sensibo result", UpdateResult)
	  Thread::sleep(5000)
    } while (!UpdateResult.contains('"status": "success"') && Attempts < 5)
  
    if (Attempts == 5) {
      logError("Sensibo write", "5 failures updating Sensibo")
    }      
  }

  catch(Throwable t) {
    logError("Sensibo write", "Error was caught: {}", t)
  }

end

Thanks I will check through to see why yours is working and mine is not.

I suggest you edit your post and remove the API and device ID, before someone decides to play around with your system.

Regards

Paul.

@kusanghi
If that is your real API key, then you will want to edit your post and remove it…

I have checked @kusanghi rule and the read (GET) curl command is similar to mine, although a little more complex. As I said the issue I am having is all about the ‘write call’
Using the code from @kusanghi I tried it out by making some minor changes and it does the same as mine fails to send commands to the sensibo.
Have you tried it recently to see if it is still working? Mine stopped about 48 hrs ago.

The write line is the same as my original one that stopped working

			UpdateResult = executeCommandLine('curl@@-sSH@@"Content-Type: application/json"@@-XPOST@@' + CommandURL + '@@-d@@'+ CommandData, 10000)

No further forward with this issue :frowning:

Regards

Paul