Fujitsu Airstage Control

In this tutorial, I would like to share with you how I configured Openhab to control my Fujitsu Airstage air conditioner.

My indoor unit: Fujitsu ASYG12KMCF (Comes with WIFI, no other/additional dongle required)

Note: I only want to control my air conditioner on the local network and am NOT using the Fujitsu cloud connection.

The air conditioning system offers a REST interface, which unfortunately is not officially documented. I used the following repository as reference: GitHub - danielkaldheim/ha_airstage: Connects your Fujitsu Airstage air conditioner to Home Assistant.

REST Request to retrieve the current status:
The device_id is the MAC address of your device, without colons.

curl --location 'http://192.168.xxx.xx/GetParam' \
--header 'Content-Type: text/plain' \
--data '{
    "device_id": "94BBxxxxxx529",
    "device_sub_id": 0,
    "req_id": "",
    "modified_by": "",
    "set_level": "03",
    "list": [
        "iu_set_tmp",
        "iu_onoff",
        "iu_op_mode"
    ]
}'

REST Reqeust to tun on the AC:
iu_onoff 1 represents ON, whereby iu_onoff = represents OFF

curl --location 'http://192.168.xxx.xx/SetParam' \
--header 'Content-Type: text/plain' \
--data '{
    "device_id": "94BBxxxxxx529",
    "device_sub_id": 0,
    "req_id": "",
    "modified_by": "",
    "set_level": "02",
    "value": {
        "iu_onoff": "1"
    }
}'

REST Request to change the target temperatur:
The target temperatur needs to be handed over multiplied by 10, e.g 190 for 19°C

curl --location 'http://192.168.178.55/SetParam' \
--header 'Content-Type: text/plain' \
--data '{
    "device_id": "94BB4393442F",
    "device_sub_id": 0,
    "req_id": "",
    "modified_by": "",
    "set_level": "02",
    "value": {
        "iu_set_tmp": "190"
    }
}'

REST Request to change the mode:
“AUTO”: “0”,
“COOL”: “1”,
“DRY”: “2”,
“FAN”: “3”,
“HEAT”: “4”

curl --location 'http://192.168.178.55/SetParam' \
--header 'Content-Type: text/plain' \
--data '{
    "device_id": "94BB4393442F",
    "device_sub_id": 0,
    "req_id": "",
    "modified_by": "",
    "set_level": "02",
    "value": {
        "iu_op_mode":"1"
    }
}'

Setup in Openhab:

I’m using the HTTP Binding, JSONPATH Transformation & Java Script. Please install the same, if not done already.

HTTP Thing configuration:

Channels:

Off/On:

  • State URL Extension: GetParam
  • Command URL Extenson: SetParam
  • State Content: { “device_id”: “yourMAC”, “device_sub_id”: 0, “req_id”: “”, “modified_by”: “”, “set_level”: “03”, “list”: [ “iu_onoff” ] }
  • State Transformation: JS:airstageOnoffState.js
  • Command Transformation: JS:airstageSendOnoff.js
  • Mode: Read & Write

Temperature:

  • State URL Extension: GetParam
  • Command URL Extenson: SetParam
  • State Content: { “device_id”: “yourMAC”, “device_sub_id”: 0, “req_id”: “”, “modified_by”: “”, “set_level”: “03”, “list”: [ “iu_set_tmp” ] }
  • State Transformation: JSONPATH:$.value.iu_set_tmp ∩ JS:airstageDivideBy10.js
  • Command Transformation: JS:airstageSendTemp.js
  • Mode: Read & Write

Mode:

  • State URL Extension: GetParam
  • Command URL Extenson: SetParam
  • State Content: { “device_id”: “yourMAC”, “device_sub_id”: 0, “req_id”: “”, “modified_by”: “”, “set_level”: “03”, “list”: [ “iu_op_mode” ] }
  • State Transformation: JS:airstageModeState.js
  • Command Transformation: JS:airstageMode.js
  • Mode: Read & Write

JS files to be stored in your openHAB-conf\transform folder:

airstageDivideBy10.js

(function(i) {
    if (isNaN(i)) return i;
    return parseFloat(i) / 10.0;
})(input)

airstageMode.js

(function(input) {
    var modes = {
        "AUTO": "0",
        "COOL": "1",
        "DRY": "2",
        "FAN": "3",
        "HEAT": "4"
    };
    
    var val = modes[input] || "0";

    var body = {
        "device_id": "yourMAC",
        "device_sub_id": 0,
        "req_id": "",
        "modified_by": "",
        "set_level": "02",
        "value": {
            "iu_op_mode": val
        }
    };
    return JSON.stringify(body);
})(input)

airstageModeState.js

(function(input) {
    var json = JSON.parse(input);
    var val = json.value.iu_op_mode; // Das ist z.B. "1"
    
    var map = {
        "0": "AUTO",
        "1": "COOL",
        "2": "DRY",
        "3": "FAN",
        "4": "HEAT"
    };
    
    return map[val] || "UNKNOWN";
})(input)

airstageOnoffState.js

(function(input) {
    var json = JSON.parse(input);
    var val = json.value.iu_onoff;
    return (val == "1") ? "ON" : "OFF";
})(input)

airstageSendOnoff.js

(function(input) {
    var val = (input == "ON") ? "1" : "0";
    
    var body = {
        "device_id": "yourMAC",
        "device_sub_id": 0,
        "req_id": "",
        "modified_by": "",
        "set_level": "02",
        "value": {
            "iu_onoff": val
        }
    };
    
    return JSON.stringify(body);
})(input)

airstageSendTemp.js

(function(input) {
    var numericValue = parseFloat(input);
    var transformedValue = (numericValue * 10).toFixed(0);

    var body = {
        "device_id": "yourMAC",
        "device_sub_id": 0,
        "req_id": "",
        "modified_by": "",
        "set_level": "02",
        "value": {
            "iu_set_tmp": transformedValue.toString()
        }
    };

    return JSON.stringify(body);
})(input)

In my specific case, I have three devices, which means that the file names of the JS files have been slightly modified.

UID: http:url:88d294d182
label: Fujitsu Airstage Wohnzimmer
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://192.168.178.54/
  delay: 0
  stateMethod: POST
  refresh: 60
  commandMethod: POST
  timeout: 3000
  bufferSize: 2048
channels:
  - id: last-failure
    channelTypeUID: http:request-date-time
    label: Last Failure
    configuration: {}
  - id: last-success
    channelTypeUID: http:request-date-time
    label: Last Success
    configuration: {}
  - id: Soll-Temperatur
    channelTypeUID: http:number
    label: Soll-Temperatur
    configuration:
      stateContent: '{     "device_id": "94BB4379C529",     "device_sub_id":
        0,     "req_id": "",     "modified_by": "",     "set_level":
        "03",     "list": [         "iu_set_tmp"     ] }'
      commandTransformation:
        - JS:airstageSendTemp_Wohnzimmer.js
      stateExtension: GetParam
      commandExtension: SetParam
      stateTransformation:
        - JSONPATH:$.value.iu_set_tmp ∩ JS:airstageDivideBy10.js
  - id: Schalten
    channelTypeUID: http:switch
    label: Aus/Ein
    configuration:
      onValue: ON
      stateContent: '{     "device_id":
        "94BB4379C529",     "device_sub_id":         0,     "req_id":
        "",     "modified_by": "",     "set_level":         "03",     "list":
        [         "iu_onoff"     ] }'
      commandTransformation:
        - JS:airstageOnoffState_Wohnzimmer.js
      offValue: OFF
      stateExtension: GetParam
      commandExtension: SetParam
      stateTransformation:
        - JS:airstageOnoffState.js
  - id: Mode
    channelTypeUID: http:string
    label: Mode
    configuration:
      stateContent: '{     "device_id": "94BB4379C529",     "device_sub_id":
        0,     "req_id": "",     "modified_by": "",     "set_level":
        "03",     "list": [         "iu_op_mode"     ] }'
      commandTransformation:
        - JS:airstageMode_Wohnzimmer.js
      stateExtension: GetParam
      commandExtension: SetParam
      stateTransformation:
        - JS:airstageModeState.js

1 Like

Thanks for posting! If you click on the code tab of your HTTP Thing you’ll get a text based version of the Thing. Posting that (either the YAML or the DSL) will make it easier for users to create their own Thing without error.

Thank you for the hint! I added the code to the initial post.