Fujitsu Air Conditioning integration - Airstage dongle

@danielkaldheim has created a wonderful HACS integration which perfectly integrates local and cloud control of Fujitsu Airstage adapters.

https://github.com/danielkaldheim/ha_airstage

It is confirmed working with UTY-TFSXH3 (wall mounted split) and UTY-TFSXJ3 (ducted) Airstage adapters. It does not work with the older and possibly discontinued FGLAIR adapters (but there is a HA integration for local control for FGLAIR link)

Fujitsu Airstage wi-fi adapter integration possible best solution in post 76:

Fujitsu Air Conditioning integration - Airstage dongle - #93 by gorstj

--------
This thread is to a follow on from the Fujitsu FGLair integration thread.

FGLair is the old Fujitsu dongles/app and is being phased out (not available in the UK).

Airstage is the new dongle/app and this thread is to discuss any ideas/progress on an Airstage integration (hopefully local control)

https://community.home-assistant.io/t/add-support-for-fujitsu-wireless-air-conditioning-control-app-fglair/65999/302?u=gorstj

https://community.home-assistant.io/t/fujitsu-ac-units-integration-with-ha/572114/17?u=gorstj

@ravenland @Raekon @pietervanh

Best solution so far is in this post:

Fujitsu Air Conditioning integration - Airstage dongle - #15 by pietervanh

1 Like

@ravenland previously gave the post below:

Device ID can be obtained from various placed including the App, the name of the access point (remove the first two parts e.g. remove AP-WJ3E-xxxxxxxxxxxx, leaving the 12 digit device_id)

Using this I have the system state working on the command line now

Basic examples regarding local control on WH3E modules are like those:

  • system state
curl -vv -X POST --data '{"device_id":"${DEVICE_ID}","device_sub_id":0,"req_id":"","modified_by":"","set_level":"03","list":["iu_wifi_led","iu_af_inc_hrz","iu_af_inc_vrt","iu_indoor_tmp","iu_outdoor_tmp","iu_hmn_det","iu_main_ver","iu_eep_ver","iu_has_upd_main","iu_has_upd_eep","iu_fld_set80"]}' 'http://${LAN_IP}/GetParam'
  • mode set
curl -vv -X POST --data '{"device_id":"
${DEVICE_ID}","device_sub_id":0,"req_id":"","modified_by":"","set_level":"03","list":["iu_onoff","iu_op_mode","iu_fan_spd","iu_set_tmp","iu_af_dir_vrt","iu_af_swg_vrt","iu_af_dir_hrz","iu_af_swg_hrz","ou_low_noise","iu_fan_ctrl","iu_hmn_det_auto_save","iu_min_heat","iu_powerful","iu_economy","iu_err_code","iu_demand","iu_fltr_sign_reset"]}' 'http://${LAN_IP}/GetParam'
  • on/off (previous mode):
curl -vv -X POST --data '{"device_id":"${DEVICE_ID}","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"[[1|0]]"}}' 'http://${LAN_IP}/SetParam'
2 Likes

Hmm where are you sending this commands from?
Cause it’s basically what I have been trying. Same POST data.
You sending this from your phone over commandline with your phone directly connected to the Wifi AP?

Cause I always get a {“result”:“NG”,“error”:“0002”}

I’m just in the process of ordering a new Fujitsu aircon and from I what read round these parts it’s going to come with Airstage and not FGLair.

I’m also a webdev, so when it get’s installed I’ll be able to help out with this investigation.

Might not be till August though.

Is you unit in cloud mode or local mode? I wonder if people are getting errors if their units are in cloud mode?

My unit is in cloud mode. Which is needed to get the Airco to join local wlan.
So I can ping my airco on 192.168.2.xxx and access the endpoints fine.

If I put my laptop on the airco wifi ssid and do the same rest commands (different ip offcourse) it also replys with {“result”:“NG”,“error”:“0002”}

Must be something simple I’m overlooking.

I am getting the exact same thing, I wonder if our dongles are different or require authentication. It would be surprising if it did not need the user and password.

Well since those units are in my parents house and I have no permanent testing setup I might assume some things from my previous poking.

As mentioned in AirCon readme regarding the W4A1 especially there might be some other major differences across the modules. While my modules are “WH3E” @gorstj mentioned “WJ3E”; so maybe we are stumbling over those discrepancies further more and a plugin implementation will be even more difficult as it wont be like one-fits-all.

As mentioned above the device-code is basically the mac address; also written in the ssid. I have not done detailed tests yet but it seems necessary to include all necessary fields in the request, which might be different again across the modules and capabilities of the ac. I am doing those tests with curl on linux and given the necessary data fields I had no erratic behaviour yet; it even works without any (optional?) headers.

At least in my case there is no real distinction between cloud mode and local operation as the modules are always connected to lan even while doing temporary ad-hoc mode to a client. But while I sniffed those api calls in ad-hoc mode with an android device further tests always went via lan.

@pietervanh could you verify with different or empty params? Maybe your device has a different sub-id or not especially level 2 or something.

If it helps I can confirm my module is WH3E as well, so this makes it even more interesting!

It is nice to know we don’t have to worry about cloud vs local it is another thing we can remove from the list of potential reasons. Happy to do testing here as well if I can help at all.

I am having intermittent Wireshark issue, but at one point I did get an invalid header packet back. I am going to see if I can replicate this or if it was just unrelated.

It doesn’t matter.
Basically sending the exact same command I sniffed from wshark.
Even with complete same header as the iOS app uses.

Ok I have it working, and I am actually an idiot, it was malformed JSON, so that is at least consistent with eh WH3E module. I have just got it to return the query data. Granted it is giving me temps in Fahrenheit rather than Celsius but it is indeed a start.

So I wonder if it is due to module differences that it is not working.

Well that’s weird… Not sure if there is any special provisioning going on while connecting them via Airstage the first time but in my case there was just the normal onboarding workflow.
Btw we were not able to connect them via FGLair neither on iOS nor Android due to a broken workflow. Did you previously connect them to FGLair or is some other kind of lock present? Do they have an open webserver on 80?

Never tried FGLair.
Both my Airco’s have also WH3E in the SSID name. So I presume also a WH3E module.

Oh my I got a reply. I have 2 units. And I’m blind so I mixed up the macaddresses.
Thunderclient in VS Code didn’t work but the curl command from vs code terminal on ha works.
Both my airco’s under full control now.
Now going to try to set it up with the following integrations RESTful Sensor - Home Assistant
RESTful Command - Home Assistant



sensor:
  - platform: rest
    scan_interval: 60
    name: airco_living_temp
    resource: http://aircoip/GetParams
    method: POST
    payload: '{"device_id":"deviceid","device_sub_id":0,"req_id":"","modified_by":"","set_level":"03","list":["iu_indoor_tmp"]}'
    value_template: "{{ value_json['value']['iu_indoor_tmp'] }}"
    unit_of_measurement: "°F"

rest_command:
  airco_on:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"deviceid","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"1"}}'
  airco_off:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"deviceid","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"0"}}'

Works great not the nicest setup but it’s late and it works for now…

The SetTemp is in Celcius * 10
The Inside and Outside Temp /100 are in Farenheit

See post below with more fullfledged example

2 Likes

Anyways you get pretty far already with standard rest integration and some scripts and conditional cards

configuration.yaml just paste at bottom and offcourse replace the AIRCOIP and AIRCOMAC in the copied text → restart HA after for configuration to take

rest_command:
  airco_bedroom_on:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"1"}}'
  airco_bedroom_off:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"0"}}'
  airco_bedroom_eco_on:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_economy":"1"}}'
  airco_bedroom_eco_off:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_economy":"0"}}'
  airco_bedroom_fanctrl_on:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_fan_ctrl":"1"}}'
  airco_bedroom_fanctrl_off:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_fan_ctrl":"0"}}'
  airco_bedroom_pwrfull_on:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_powerfull":"1"}}'
  airco_bedroom_pwrfull_off:
    url: http://aircoip/SetParam
    method: POST
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_powerfull":"0"}}'
  airco_bedroom_set_temp:
    url: http://aircoip/SetParam
    method: POST
    payload: >
      {% set bedroomtemp = (states('input_number.setaircotempbedroom') | float  * 10) | int %}
      {"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_set_tmp":"{{ bedroomtemp }}"}}
  airco_bedroom_setmode:
    url: http://aircoip/SetParam
    method: POST
    payload: >
      {% set aircomodes = {"Auto": 0, "Cooling": 1,"Dry": 2,"Fan": 3,"Heating": 4} %}
      {% set opmode = aircomodes[states('input_select.setaircoopmodebedroom')]  %}
      {"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_op_mode":"{{ opmode }}"}}
  

rest:
  - resource: http://aircoip/GetParam
    scan_interval: 60
    payload: '{"device_id":"aircomac","device_sub_id":0,"req_id":"","modified_by":"","set_level":"03","list":["iu_set_tmp","iu_indoor_tmp","iu_outdoor_tmp","iu_onoff","iu_economy","iu_fan_ctrl","iu_fan_ctrl","iu_powerful","ou_low_noise"]}'
    binary_sensor:
      - name: "Airco Bedroom On"
        value_template: "{{ value_json['value']['iu_onoff'] }}"
      - name: "Airco Bedroom Economy"
        value_template: "{{ value_json['value']['iu_economy'] }}"
        icon: mdi:leaf
      - name: "Airco Bedroom Fan Control"
        value_template: "{{ value_json['value']['iu_fan_ctrl'] }}"
        icon: mdi:fan
      - name: "Airco Bedroom Powerfull"
        value_template: "{{ value_json['value']['iu_powerful'] }}"
        icon: mdi:fan-plus
      - name: "Airco Bedroom Low Noise"
        value_template: "{{ value_json['value']['ou_low_noise'] }}"
        icon: mdi:sleep
    sensor:
      - name: "Temp Outside Airco Bedroom"
        value_template: "{{ (((value_json['value']['iu_outdoor_tmp'] | float  / 100 ) - 32 ) * 5/9) | round(2) }}"
        unit_of_measurement: "°C"
      - name: "Temp Inside Airco Bedroom"
        value_template: "{{ (((value_json['value']['iu_indoor_tmp'] | float  / 100 ) - 32 ) * 5/9) | round(2) }}"
        unit_of_measurement: "°C"
      - name: "Requested Temp Airco Bedroom"
        value_template: "{{ (value_json['value']['iu_set_tmp'] | float / 10 )| round(2) }}"
        unit_of_measurement: "°C"

Scripts ( Settings > Automations & Scenes > Scripts) Add 2 scripts and paste the 2 scripts yaml

alias: Turn On Airco Bedroom
sequence:
  - service: rest_command.airco_bedroom_on
    data: {}
  - service: homeassistant.update_entity
    data: {}
    target:
      entity_id: binary_sensor.airco_bedroom_on
mode: single
icon: mdi:air-conditioner

alias: Turn Off Airco Bedroom
sequence:
  - service: rest_command.airco_bedroom_off
    data: {}
  - service: homeassistant.update_entity
    data: {}
    target:
      entity_id: binary_sensor.airco_bedroom_on
mode: single
icon: mdi:air-conditioner

Dashboard on / off button
image

Paste in yaml in a new manual card replace code with below

square: true
type: grid
cards:
  - type: conditional
    conditions:
      - entity: binary_sensor.airco_bedroom_on
        state: 'off'
    card:
      show_name: true
      show_icon: true
      type: button
      tap_action:
        action: call-service
        service: script.turn_on_airco_bedroom
        target: {}
      hold_action:
        action: none
      icon: mdi:air-conditioner
      name: Airco
      show_state: false
      entity: binary_sensor.airco_bedroom_on
  - type: conditional
    conditions:
      - entity: binary_sensor.airco_bedroom_on
        state: 'on'
    card:
      show_name: true
      show_icon: true
      type: button
      tap_action:
        action: call-service
        service: script.turn_off_airco_bedroom
        target: {}
      hold_action:
        action: none
      icon: mdi:air-conditioner
      name: Airco
      show_state: false
      entity: binary_sensor.airco_bedroom_on
columns: 4

Automation to update requested Temperature based on helper:
Create Helper under Settings > Devices and Entities > Helpers > Create helper


Input Helper for the dropdown to change mode

Automation , create 2 automations in gui and paste the yaml

alias: Airco bedroom temp Update
description: ""
trigger:
  - platform: state
    entity_id:
      - input_number.setaircotempbedroom
condition: []
action:
  - service: rest_command.airco_bedroom_set_temp
    data: {}
  - service: homeassistant.update_entity
    data: {}
    target:
      entity_id: sensor.requested_temp_airco_bedroom
mode: single

alias: Airco bedroom mode change
description: ""
trigger:
  - platform: state
    entity_id:
      - input_select.setaircoopmodebedroom
condition: []
action:
  - service: rest_command.airco_bedroom_setmode
    data: {}
  - service: homeassistant.update_entity
    data: {}
    target:
      entity_id: sensor.requested_temp_airco_bedroom
mode: single


image

4 Likes

This is looking great, I am working on a NodeRed setup with taking HTTP POST and translating them to MQTT. I have had powerful and eco working fine here. What I am getting is a disparity between the temperatures reported by the app and what the HTTP POST is returning. Are you experiencing the same? It’s about 1 deg c out, but not sure that is consistent.

3 Likes

Can you share the requests for enabling disabling powerful mode and setting the temperature?
About temparature difference between app and post have not checked.
But the temparature from the http post seems quite in line with the other temp sensors I have in the same room.

1 Like

Sure.

The payload I use for setting the temp is.

{
        device_id:"DEVICEID",
        device_sub_id:0,
        req_id:"",
        modified_by:"",
        set_level:"02",
        value: {
                iu_set_tmp: "TEMPVAL"
            }
}

The payload for powerful is

{
        device_id:"DEVICEID",
        device_sub_id:0,
        req_id:"",
        modified_by:"",
        set_level:"02",
        value: {
                iu_powerful: "0 or 1"
            }
}

Hmm ok so maybe the reported temps are right and the app is wrong, I will measure with a probe and check.

Edit: Further thought, you can only set powerful when the aircon is on. A quirk of the system, but you can set eco if it is on or off. I suspect this is bug.

Massive progress been made here!

I will have some time Saturday evening to debug with a Mac if there are any other API commands that need checking.

Let me know a lisr

Guys, sorry for posting this somehow offtopic question. I do have 5 new ACs with airstage dongle “WH3E” as mentioned earlier. I tried to install 2 of the devices and I can get them connected to the wireless router, however the app is crashing during the cloud registration process every time on any of my 3 iOS devices. Did you encounter any such issues? I searched the internet, but I can not find any hints. Interestingly I can add a device in local mode to the app.
Actually I like to hook them all in my home assistant system. so I’m eagerly following this thread and I’m also willing to contribute as soon as I get the decives running.