Are there here anyone planning to make a binding for this one?
I still have that error message on macOS. First of all I had to change the following line:
UpdateResult = executeCommandLine('curl@@-sSH@@"Content-Type: application/json"@@-XPOST@@' + CommandURL + '@@-d@@'+ CommandData, 10000)`
To (included additional code for proper understanding):
var String CommandURL = 'https://home.sensibo.com/api/v2/pods/' + PodID + '/acStates?apiKey=' + APIKey
var String CommandState = '{"acState":{"on":' + PodBoolean + ','
var String CommandMode = '"mode":"' + SensiboMode.state + '",'
var String CommandFan = '"fanLevel":"' + SensiboFan.state + '",'
var String CommandSwing = ""
if (SensiboSwing.state != "")
{ CommandSwing = '"swing":"' + SensiboSwing.state + '"}}' }
var String CommandTemp = '"targetTemperature":' + (SensiboTarget.state as DecimalType).intValue + ','
var String CommandTempUnit = '"temperatureUnit":"C",'
var String CommandData = CommandState + CommandMode + CommandFan + CommandTemp + CommandTempUnit + 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
...
UpdateResult = executeCommandLine(CommandExec, 10000)
As before it was throwing different error messages like URL is incorrect, syntax is incorrect etc. For some reason macOS doesn’t like @@. After replacing @@ with just spaces and slightly changing the structure of the curl request it started sending requests to Sensibo. But it returns ‘400 BadRequest - Sensibo 400 BadRequest POST data is not valid JSON’. At the same time if I execute the same command from the command line it works perfectly
curl -sSH "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"acState":{"on":true,"mode":"cool","fanLevel":"auto","targetTemperature":24,"temperatureUnit":"C","swing":"stopped"}}' https://home.sensibo.com/api/v2/pods/<PodID>/acStates?apiKey=<APIKey>
PodID and APIKey have been removed for obvious reasons, but that line executed from CLI works perfectly. It turns on A/C and returns proper response from Sensibo. While this command executed in openHAB it just gives ‘POST data is not valid JSON’. Don’t understand why… Anything I’m missing?
Tried to use
logInfo("Sensibo Exec:", CommandExec)
And it gives the perfect CLI line, but still doesn’t work from the code.
Any help would be highly appreciated! I’m really new to openHAB and Java…
Did you end up getting it working I having the same result
<html><head><title>400 BadRequest - Sensibo</title></head><body><h>400 BadRequest</h><p>POST data is not valid JSON</p><body></html>
Yes, I managed to fix it. It was the issue with syntax. Here is the correct line that works for me,
var CommandExec = 'curl@@-sSH@@"Accept: application/json"@@-H@@"Content-Type: application/json"@@-X@@POST@@-d@@' + CommandData + '@@' + CommandURL
Let me know if you want the entire file.
Thanks that works great
So with the help I got here I got it all working. My goal is to have controls on my HASP plate (touch screen that replaces wall switched).
I needed the pod state to mainly be stored in the sensibo api so I changed the code a little. Instead of posting changes I will just post the files It updates every 5 min but I will change it to update when I change to that page on the touchscreen.
sitemap sensibo label="Sensibo" {
Frame label="Sensibo Living" {
Switch item=Sensibo_Living_State label="Sensibo_Living_State" mappings=["true"="ON", "false"="OFF"] icon="switch"
Switch item=Sensibo_Living_Mode label="Mode" icon="heating" mappings=[cool="Cool",heat="Heat",fan="Fan"]
Setpoint item=Sensibo_Living_Target label="Target [%.0f ºC]" icon="temperature" minValue=18 maxValue=26 step=1.0
Switch item=Sensibo_Living_Fan label="Fan" icon="fan" mappings=[low="Low",medium="Med",high="High",auto="Auto"]
Switch item=Sensibo_Living_Swing label="Swing" icon="fan" mappings=[stopped="Stop",fixedMiddle="Middle",fixedTop="High",rangeFull="Swing"]
Text item=Sensibo_Living_Temp label="Temperature [%.1f ºC]" icon="temperature"
Text item=Sensibo_Living_Humidity label="Humidity [%.0f %%]" icon="water"
// Text item=Sensibo_Living_Battery label="Battery [%d mV]" icon="energy"
}
Frame label="Sensibo Bedroom" {
Switch item=Sensibo_Bedroom_State label="Sensibo Bedroom State" mappings=["true"="ON", "false"="OFF"] icon="switch"
Switch item=Sensibo_Bedroom_Mode label="Mode" icon="heating" mappings=[cool="Cool",heat="Heat",fan="Fan"]
Setpoint item=Sensibo_Bedroom_Target label="Target [%.0f ºC]" icon="temperature" minValue=18 maxValue=26 step=1.0
Switch item=Sensibo_Bedroom_Fan label="Fan" icon="fan" mappings=[low="Low",medium="Med",high="High",auto="Auto"]
Switch item=Sensibo_Bedroom_Swing label="Swing" icon="fan" mappings=[stopped="Stop",fixedMiddle="Middle",fixedTop="High",rangeFull="Swing"]
Text item=Sensibo_Bedroom_Temp label="Temperature [%.1f ºC]" icon="temperature"
Text item=Sensibo_Bedroom_Humidity label="Humidity [%.0f %%]" icon="water"
// Text item=Sensibo_Bedroom_Battery label="Battery [%d mV]" icon="energy"
}
}
Items
String Sensibo_Living_State
Number Sensibo_Living_Temp
Number Sensibo_Living_Humidity
Number Sensibo_Living_Battery
Number Sensibo_Living_Target
String Sensibo_Living_Fan
String Sensibo_Living_Mode
String Sensibo_Living_Swing
String Sensibo_Bedroom_State
Number Sensibo_Bedroom_Temp
Number Sensibo_Bedroom_Humidity
Number Sensibo_Bedroom_Battery
Number Sensibo_Bedroom_Target
String Sensibo_Bedroom_Fan
String Sensibo_Bedroom_Mode
String Sensibo_Bedroom_Swing
Rules
You need to enter your own apikey and podid
/*** openHAB Sensibo Rules ***/
// Goto the website https://home.sensibo.com/me/api first and create APIKey
val String APIKey = ""
var PodID_01 = "" //Living
var PodID_02 = "" //Bedroom
rule "Read Sensibo State PodID_01"
when
System started or
Time cron "0 0/5 * * * ?" //Update states from senibo every 5 min
then
//Thread::sleep(1000)
try {
var String PodStatus
do {
Thread::sleep(5000)
PodStatus = executeCommandLine('curl -sSH "Accept: application/json" "https://home.sensibo.com/api/v2/pods/' + PodID_01 + '/acStates?apiKey=' + APIKey + '&limit=1&fields=acState"', 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))
postUpdate(Sensibo_Living_State, PodOn)
postUpdate(Sensibo_Living_Target, PodTarget)
postUpdate(Sensibo_Living_Mode, PodMode)
postUpdate(Sensibo_Living_Fan, PodFan)
if (PodStatus.contains('"swing": ')) {
val String PodSwing = (transform("JSONPATH", "$.result[0].acState.swing", PodStatus))
postUpdate(Sensibo_Living_Swing, PodSwing)
}
}
catch(Throwable t) {
logError("Sensibo read state", "Error was caught: {}", t)
}
end
rule "Read Sensibo Measurements PodID_01"
when
Time cron "0 0/5 * * * ?" //Update states from senibo every 5 min
then
try {
var String PodMeasurements
do {
PodMeasurements = executeCommandLine('curl -sSH "Accept: application/json" "https://home.sensibo.com/api/v2/pods/' + PodID_01 + '/measurements?apiKey=' + APIKey + '&fields=temperature,humidity,batteryVoltage"', 5000)
//logInfo("Sensibo result - PodMeasurements", PodMeasurements)
Thread::sleep(5000)
} while (!PodMeasurements.contains('"status": "success"'))
var PodTemperature = new Double(transform("JSONPATH", "$.result[0].temperature", PodMeasurements))
var PodHumidity = new Double(transform("JSONPATH", "$.result[0].humidity", PodMeasurements))
postUpdate(Sensibo_Living_Temp, PodTemperature)
postUpdate(Sensibo_Living_Humidity, PodHumidity)
if (!PodMeasurements.contains('"batteryVoltage": null')) {
val Number PodBattery = new Integer(transform("JSONPATH", "$.result[0].batteryVoltage", PodMeasurements))
postUpdate(Sensibo_Living_Battery, PodBattery)
}
}
catch(Throwable e) {
logError("Sensibo measurements", "Error was caught: {}", e)
}
end
rule "Write Sensibo State PodID_01"
when
Item Sensibo_Living_State received command or
Item Sensibo_Living_Mode received command or
Item Sensibo_Living_Fan received command or
Item Sensibo_Living_Swing received command or
Item Sensibo_Living_Target received command
then
try {
//Thread::sleep(1000) // Avoid race condition where state has not yet been updated
var CommandURL = 'https://home.sensibo.com/api/v2/pods/' + PodID_01 + '/acStates?apiKey=' + APIKey
var CommandState = '{"acState":{"on":' + Sensibo_Living_State.state + ','
var CommandMode = '"mode":"' + Sensibo_Living_Mode.state + '",'
var CommandFan = '"fanLevel":"' + Sensibo_Living_Fan.state + '",'
var CommandSwing = ""
if (Sensibo_Living_Swing.state != "")
{ CommandSwing = '"swing":"' + Sensibo_Living_Swing.state + '"}}' }
var String CommandTemp = '"targetTemperature":' + (Sensibo_Living_Target.state as DecimalType).intValue + ','
var String CommandTempUnit = '"temperatureUnit":"C",'
var String CommandData = CommandState + CommandMode + CommandFan + CommandTemp + CommandTempUnit + 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(CommandExec, 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
/*** Bedroom Sensibo ***/
rule "Read Sensibo State PodID_02"
when
System started or
Time cron "0 0/5 * * * ?" //Update states from senibo every 5 min
then
//Thread::sleep(1000)
try {
var String PodStatus
do {
Thread::sleep(5000)
PodStatus = executeCommandLine('curl -sSH "Accept: application/json" "https://home.sensibo.com/api/v2/pods/' + PodID_02 + '/acStates?apiKey=' + APIKey + '&limit=1&fields=acState"', 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))
postUpdate(Sensibo_Bedroom_State, PodOn)
postUpdate(Sensibo_Bedroom_Target, PodTarget)
postUpdate(Sensibo_Bedroom_Mode, PodMode)
postUpdate(Sensibo_Bedroom_Fan, PodFan)
if (PodStatus.contains('"swing": ')) {
val String PodSwing = (transform("JSONPATH", "$.result[0].acState.swing", PodStatus))
postUpdate(Sensibo_Bedroom_Swing, PodSwing)
}
}
catch(Throwable t) {
logError("Sensibo read state", "Error was caught: {}", t)
}
end
rule "Read Sensibo Measurements PodID_02"
when
Time cron "0 0/5 * * * ?" //Update states from senibo every 5 min
then
try {
var String PodMeasurements
do {
PodMeasurements = executeCommandLine('curl -sSH "Accept: application/json" "https://home.sensibo.com/api/v2/pods/' + PodID_02 + '/measurements?apiKey=' + APIKey + '&fields=temperature,humidity,batteryVoltage"', 5000)
//logInfo("Sensibo result - PodMeasurements", PodMeasurements)
Thread::sleep(5000)
} while (!PodMeasurements.contains('"status": "success"'))
var PodTemperature = new Double(transform("JSONPATH", "$.result[0].temperature", PodMeasurements))
var PodHumidity = new Double(transform("JSONPATH", "$.result[0].humidity", PodMeasurements))
postUpdate(Sensibo_Bedroom_Temp, PodTemperature)
postUpdate(Sensibo_Bedroom_Humidity, PodHumidity)
if (!PodMeasurements.contains('"batteryVoltage": null')) {
val Number PodBattery = new Integer(transform("JSONPATH", "$.result[0].batteryVoltage", PodMeasurements))
postUpdate(Sensibo_Bedroom_Battery, PodBattery)
}
}
catch(Throwable e) {
logError("Sensibo measurements Bedroom", "Error was caught: {}", e)
}
end
rule "Write Sensibo State PodID_02"
when
Item Sensibo_Bedroom_State received command or
Item Sensibo_Bedroom_Mode received command or
Item Sensibo_Bedroom_Fan received command or
Item Sensibo_Bedroom_Swing received command or
Item Sensibo_Bedroom_Target received command
then
try {
//Thread::sleep(1000) // Avoid race condition where state has not yet been updated
var CommandURL = 'https://home.sensibo.com/api/v2/pods/' + PodID_02 + '/acStates?apiKey=' + APIKey
var CommandState = '{"acState":{"on":' + Sensibo_Bedroom_State.state + ','
var CommandMode = '"mode":"' + Sensibo_Bedroom_Mode.state + '",'
var CommandFan = '"fanLevel":"' + Sensibo_Bedroom_Fan.state + '",'
var CommandSwing = ""
if (Sensibo_Bedroom_Swing.state != "")
{ CommandSwing = '"swing":"' + Sensibo_Bedroom_Swing.state + '"}}' }
var String CommandTemp = '"targetTemperature":' + (Sensibo_Bedroom_Target.state as DecimalType).intValue + ','
var String CommandTempUnit = '"temperatureUnit":"C",'
var String CommandData = CommandState + CommandMode + CommandFan + CommandTemp + CommandTempUnit + 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(CommandExec, 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
I hope this helps someone and this wan’t possible without the help from the other users above.
For anyone starting from scratch, and wanting a short cut to getting this working:
- Copy the files in to the correct folders (follow the file extension)
- Remove the battery lines in .items and .sitemap if you have a Sensibo Sky
- Make sure you have the JSONPath Transformation installed (Paper UI > Configuration > Bindings > Add (+) > Transformations
- Follow the documentation and add an API key (I called mine “apiKey”), then add the key to the top of the .rules file
- restart OpenHab (many ways to do this, I do sudo systemctl stop openhab2.service, then sudo systemctl start openhab2.service in console
Then it works beautifully. THANK YOU for the integration.
their is a binding now you can use
Had the same problem but managed to fix it in a more “elegant” way by replacing all the executeCommandLine with sendHttpGetRequest and sendHttpPostRequest methods. I guess those methods are more efficient than execute a curl command using a shell.
PodMeasurements = sendHttpGetRequest(“https://home.sensibo.com/api/v2/pods/” + PodID + “/measurements?apiKey=” + APIKey + “&fields=temperature,humidity,batteryVoltage”)
And for the update
UpdateResult = sendHttpPostRequest(CommandURL,“application/json”, CommandData)
Hello gents,
I noticed that since 2019-07-14 12:10:00 the Sensibo API call doesn’t work anymore. The Sensibo API was changed.
[ERROR] [rthome.model.script.Pod measurements] - Error reading from Sensibo API
The new call should be per:
sendHttpGetRequest("https://home.sensibo.com/api/v2/pods/" + PodID + "?fields=measurements&apiKey=" + APIKey + "")
This gives below new JSON formatted output
[arthome.model.script.Pod Measurement] - {"status": "success", "result": {"measurements": {"batteryVoltage": null, "temperature": 22.5, "humidity": 66.6, "time": {"secondsAgo": 540, "time": "2019-07-21T08:16:00Z"}, "rssi": "-64", "piezo": [null, null]}}}
I’m busy changing the API output interpretation but run into a “NumberFormatException” error.
val Number PodTemperature = new Double(transform("JSONPATH", "$.result[0].measurements.temperature", PodMeasurements))
val Number PodHumidity = new Double(transform("JSONPATH", "$.result[0].measurements.humidity", PodMeasurements))
java.lang.NumberFormatException: For input string: "{"status": "success", "result": {"measurements": {"batteryVoltage": null, "temperature": null, "humidity": null, "time": null, "rssi": null, "piezo": [null, null]}}}"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043) ~[?:?]
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) ~[?:?]
at java.lang.Double.parseDouble(Double.java:538) ~[?:?]
at java.lang.Double.<init>(Double.java:608) ~[?:?]
at sun.reflect.GeneratedConstructorAccessor333.newInstance(Unknown Source) ~[?:?]
Help on this last step is appreciated after which I will donate once again my rules script for this sensibo integration.
Regards,
Ferry
Is this still under development? I have some old v1 pods laying around that I’d love to use again. While looking for a OH3 solution I stumbled on this discussion. I’m a OH beginner, so I need to be taken by hand to make this work.
There are Sensibo bindings, but they are for the v2 Sky.
Anybody willing to port this to OH3?
Thanks!
That’s great! Sharing your Sensibo control files on GitHub is a helpful resource for others who want to control their Sensibo systems in a similar way. This could also be useful for developers who are interested in building applications that interact with Sensibo using a business information API. By making your code publicly available, you’re contributing to the developer community and potentially inspiring others to create innovative new tools.