Fujitsu Air Conditioning integration - Airstage dongle

nice job @gorstj why don’t we use secrets as well for the airco ip / airco mac?

Thank you! Works perfectly. The only remaining uncontrolled thing on my system is being able to choose a vertical angle for the airflow (when swing mode is not on)… I think I saw somewhere that is possible to control with the REST commands but can live without it.

I have a Unifi router and I have one or two units which keep associating but not joining IP. I will try the standalone network…

@ptruman have you looked at the following post for what someone tried who was having issues connecting with wifi?

https://community.home-assistant.io/t/fujitsu-air-conditioning-integration-airstage-dongle/589679/33?u=gorstj

1 Like

For controlling the direction when swing is off try adding this to the file in the rest_command section: (editing the relevant name, IP and MAC):

rest_command:
  airco_bedroom_direction:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_af_dir_vrt":"{{ direction }}"}}'

Then developer tools → service try the following YAML:

service: rest_command.upstairs_aircon_direction
data:
  direction: 1

(can try 1 to 4 for different directions).

The only way to integrate with the Climate IP template (GitHub - jcwillox/hass-template-climate: ❄️Templatable Climate Device for Home Assistant, Supports Running Actions On Service Calls.) would be to have it in the list of Swing modes which could either be “On” or “Position 1”…“Position 4”.

Should be quite simple to do (copy from other elements of the code) but as I can’t test it I don’t want to try!

Latest version of file which includes tweaks for swing control as as posted by @mow
Also added tip to use capitals for the MAC address

To-do: (volunteers?)

  • !secrets for IP address and MAC address (but not sure if this will make it simpler or not as additional file)
  • change swing control options from On/Off to being ‘On’ or ‘Position 1…4’ (need volunteer as I don’t have a device with swing control)
# Integration for Fujitsu wi-fi adapters that use Airstage app (n.b. will NOT work with the older/discontinued adapters that use FGLair app)
# See the HA Community thread https://community.home-assistant.io/t/fujitsu-air-conditioning-integration-airstage-dongle/589679
#
# 1) Install 'Climate Template' via the HACS integration manager https://github.com/jcwillox/hass-template-climate
# 2) Using 'Studio Code Server' from the HA add-ons store is useful
# 3) Use seach&replace funcitonality is useful!
# 4) Save this file as e.g. 'upstairs_aircon.yaml'. 
# 5) Place this file in the same folder as your configuration.yaml
# 6) Search & replace all '192.168.1.188' with the IP address of your aircon (assign a static IP to this device)
# 7) Search & replace all 'E8FB1CFF5FF5' with the MAC address of your aircon (use CAPITALS and do not put any : in the address)
# 8) Search & replace all instances of 'upstairs' with what you want to name the new aircon device (n.b. needs to be in lower case except where indicated)
# 9) Have a look through at # out sections to see if you want to enable
# 10) Add the following lines to your configuration.yaml (ensure it refers to the correct filename & you remove the #'s')
###############
#homeassistant:
#  packages:
#    pack_1: !include upstairs_aircon.yaml 
###############
#
# ***you will need to do a 'proper'' restart of HA rather than just a quick reload ***
#
# **swing mode is not tested as my device does not have that function** (please report back in the thread if it works)
# 
# Thanks to all the people in the aforemetnioned thread including @pietervanh @ravenland

rest_command:
  upstairs_aircon_setmode:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: >
      {% set aircomodes = {"auto": '"iu_op_mode":"0"',"cool": '"iu_op_mode":"1"',"dry": '"iu_op_mode":"2"',"fan_only": '"iu_op_mode":"3"',"heat": '"iu_op_mode":"4"',"off": '"iu_onoff":"0"'} %}
      {% set opmode = aircomodes.get(hvac_mode, 0) %}
      {"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{ {{opmode}} }} 
  upstairs_aircon_settemp:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: >
      {% set setroomtemp = (target_temp | float   * 10) | int %}
      {"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_set_tmp":"{{ setroomtemp }}"}}
  upstairs_aircon_set_fan_speed:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: >
      {% set fanspds = {"auto": 0, "Quiet": 2,"low": 5,"medium": 8,"high": 11} %}
      {% set spd = fanspds.get(fan_mode, 0) %}
      {"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_fan_spd":"{{ spd }}"}}

# enable if your device has a swing mode
#  upstairs_aircon_set_swing_mode:
#    url: http://192.168.1.188/SetParam
#    method: POST
#    payload: >
#      {% set mode = {"off": 0, "on": 1} %}
#      {% set swing = mode.get(swing_mode, 0) %}
#      {"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_af_swg_vrt":"{{ swing }}"}}
    
# not all units especially ducted have powerful mode. Powerful runs for a short period then stops
  upstairs_aircon_pwrfull_on:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_powerfull":"1"}}'
  upstairs_aircon_pwrfull_off:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_powerfull":"0"}}'

# these aren't used by the template but included for completion
  upstairs_aircon_on:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"1"}}'
  upstairs_aircon_off:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_onoff":"0"}}'
  upstairs_aircon_eco_on:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_economy":"1"}}'
  upstairs_aircon_eco_off:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_economy":"0"}}'
  upstairs_aircon_fanctrl_on:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_fan_ctrl":"1"}}'
  upstairs_aircon_fanctrl_off:
    url: http://192.168.1.188/SetParam
    method: POST
    payload: '{"device_id":"E8FB1CFF5FF5","device_sub_id":0,"req_id":"","modified_by":"","set_level":"02","value":{"iu_fan_ctrl":"0"}}'

rest:
  - resource: http://192.168.1.188/GetParam
    scan_interval: 60
    payload: '{"device_id":"E8FB1CFF5FF5","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","iu_op_mode","iu_fan_spd","iu_af_swg_vrt"]}'
    sensor:
      - name: "Temp Outside upstairs Aircon"
        value_template: "{{ (((value_json['value']['iu_outdoor_tmp'] | float  / 100 ) - 32 ) * 5/9) | round(2) }}"
        unit_of_measurement: "°C"
      - name: "Temp Inside upstairs Aircon"
        value_template: "{{ (((value_json['value']['iu_indoor_tmp'] | float  / 100 ) - 32 ) * 5/9) | round(2) }}"
        unit_of_measurement: "°C"
      - name: "Requested Temp upstairs Aircon"
        value_template: "{{ (value_json['value']['iu_set_tmp'] | float / 10 )| round(2) }}"
        unit_of_measurement: "°C"
      - name: "Mode upstairs Aircon"
        value_template: >
          {% set mapper ={'0': 'auto','1': 'cool','2': 'dry','3': 'fan_only','4': 'heat'} %}
          {% set state =  value_json['value']['iu_op_mode'] %}
          {{ mapper[state] if state in mapper else 'Unknown' }}
      - name: "Fan Speed Upstairs Aircon"
        value_template: >
          {% set mapper ={'0': 'auto','2': 'Quiet','5': 'low','8': 'medium','11': 'high'} %}
          {% set state =  value_json['value']['iu_fan_spd'] %}
          {{ mapper[state] if state in mapper else 'Unknown' }}
    binary_sensor:
      - name: "Power Status upstairs Aircon"
        value_template: "{{ (value_json['value']['iu_onoff']) }}"

# enable if your device has a swing mode
#      - name: "Swing Mode Upstairs Aircon"
#        value_template: >
#          {% set mapper ={'0': 'off','1': 'on'} %}
#          {% set state =  value_json['value']['iu_af_swg_vrt'] %}
#          {{ mapper[state] if state in mapper else 'Unknown' }}



climate:
  - platform: climate_template
# the name: can have capital letters if desired
    name: Upstairs Aircon
    modes: 
      - "auto"
      - "dry"
      - "off"
      - "cool"
      - "fan_only"
      - "heat"
    fan_modes:
      - "auto"
      - "Quiet"
      - "low"
      - "medium"
      - "high"

# enable if your device has a swing mode
#    swing_modes:
#      - "on"
#      - "off"

    min_temp: 15
    max_temp: 30

    current_temperature_template: "{{ states('sensor.temp_inside_upstairs_aircon') }}"

    hvac_mode_template: >
      {% if is_state('binary_sensor.power_status_upstairs_aircon', 'off') %}
        off
      {% else %}
        {{ states('sensor.mode_upstairs_aircon') }}
      {% endif %}
    
    target_temperature_template: "{{ states('sensor.requested_temp_upstairs_aircon') }}"
    
    fan_mode_template: "{{ states('sensor.fan_speed_upstairs_aircon') }}"

# enable if your device has a swing mode
#    swing_mode_template: "{{ states('binary_sensor.swing_mode_upstairs_aircon') }}"

    set_hvac_mode:
      - service: rest_command.upstairs_aircon_on
      - delay: 1
      - service: rest_command.upstairs_aircon_setmode
        data:
          hvac_mode: "{{ hvac_mode }}"
      - delay: 2
      - service: homeassistant.update_entity
        entity_id: sensor.mode_upstairs_aircon

    set_temperature:
      - service: rest_command.upstairs_aircon_settemp
        data:
          target_temp: "{{ temperature }}"
      - delay: 2
      - service: homeassistant.update_entity
        entity_id: sensor.requested_temp_upstairs_aircon

    set_fan_mode:
      - service: rest_command.upstairs_aircon_set_fan_speed
        data:
          fan_mode: "{{ fan_mode }}"
      - delay: 2
      - service: homeassistant.update_entity
        entity_id: sensor.fan_speed_upstairs_aircon

# enable if your device has a swing mode
#    set_swing_mode:
#      - service: rest_command.upstairs_aircon_set_swing_mode
#        data:
#          swing_mode: "{{ swing_mode }}"
#      - delay: 2
#      - service: homeassistant.update_entity
#        entity_id: binary_sensor.swing_mode_upstairs_aircon

I’ll give the swing position tweak a go later on.

PS I’m not a YAML expert but is there a way to define variables at the top that work throughout, could clean up the IP and MAC stuff?

The only way I could Google to do variables was to use a !secret file
However that requires the complexity of another file and making sure the variables format correctly.

Edit: does seem there are variables for YAML but not sure they are usable within the middle of a sequence e.g. ipaddress of URL or Mac address within JSON

Define and reuse YAML Variables — GeoServer 2.24.x User Manual.

‘’'After a week week of struggling (I am pretty new to HA) I managed to make some nice cards for my 5 Fujitu’s. And got it all working (inlcuding set fan speed / operation mode)

I used two HACS integrations:
Button-card and Multiple Entity Row card.

Since I rent out this house I have put some extra’s in it like When the requested temp (from the remote controller get’s lower than the change temp slider it turn bold and red.

I made some automations as well: If my shelly door/window sensor stay open for >120 secs. the Livingroom airco turns off. The same counts for all the bedroom aircons.

Personally I really like the tap buttons for the OP Mode, however I can’t get the icons lit up in yellow as soon as one is tapped (and active). It should adjust to yellow regarding the value of iu_op_mode eventually. Maybe someone know how to do tis?

Here’s my yaml for one of them (Sorry I don’t know how to insert it as a copy field):

type: entities
title: Airco Bedroom 2
state_color: true
entities:

  • type: custom:button-card
    entity: script.airco_bedroom2_toggle
    tap_action:
    action: call-service
    service: script.turn_on
    service_data:
    entity_id: script.airco_bedroom2_toggle
    show_icon: false
    show_name: true
    name: |
    [[[
    if (states[‘binary_sensor.airco_bedroom2_powered’].state === ‘on’) return ‘Powered on - Turn Off’;
    else return ‘Powered off - Turn On’;
    ]]]
    styles:
    card:
    - background-color: |
    [[[
    if (states[‘binary_sensor.airco_bedroom2_powered’].state === ‘on’) return ‘#90EE90’;
    else return ‘#FF7F7F’;
    ]]]
    name:
    - font-weight: bold
  • entity: sensor.requested_temp_airco_bedroom2
    name: Requested Temperature
    icon: mdi:remote
    state_color: true
    style: |
    :host {
    font-weight: {% if states(‘sensor.requested_temp_airco_bedroom2’) | float < states(‘input_number.setaircotempbedroom2’) | float %} bold {% else %} normal {% endif %};
    color: {% if states(‘sensor.requested_temp_airco_bedroom2’) | float < states(‘input_number.setaircotempbedroom2’) | float %} red {% else %} inherit {% endif %};
    }
  • entity: input_number.setaircotempbedroom2
    name: Change temperature
  • type: custom:multiple-entity-row
    entity: sensor.operational_mode_airco_bedroom1_friendlyname
    name: ’ ’
    icon: mdi:cog-outline
    state_icon:
    ‘0’: mdi:auto-mode
    ‘1’: mdi:snowflake
    ‘2’: mdi:water-off-outline
    ‘3’: mdi:fan
    ‘4’: mdi:radiator
    entities:
    • icon: mdi:auto-mode
      tap_action:
      action: call-service
      service: input_number.set_value
      service_data:
      entity_id: input_number.setaircooperationalmodebedroom2
      value: 0
    • icon: mdi:snowflake
      tap_action:
      action: call-service
      service: input_number.set_value
      service_data:
      entity_id: input_number.setaircooperationalmodebedroom2
      value: 1
    • icon: mdi:water-off-outline
      tap_action:
      action: call-service
      service: input_number.set_value
      service_data:
      entity_id: input_number.setaircooperationalmodebedroom2
      value: 2
    • icon: mdi:fan
      tap_action:
      action: call-service
      service: input_number.set_value
      service_data:
      entity_id: input_number.setaircooperationalmodebedroom2
      value: 3
    • icon: mdi:radiator
      tap_action:
      action: call-service
      service: input_number.set_value
      service_data:
      entity_id: input_number.setaircooperationalmodebedroom2
      value: 4

I hope you guy;s like it and can do somthing with it :slight_smile:

Regards, Mark’’’

This is what the built-in (I think) Lovelace thermostat card looks like with the climate code that has been put up in recent posts.

If you click the three dots in top right you get the ‘full’ HVAC options including fan control etc.

One more feature idea.

The climate integration in home assistant supports preset_mode like for example eco.

Unfortunately the HACS integration Climate Template does not support it. There is an one year old open feature request. Maybe someone here is able to add this feature to the HACS integration.

1 Like

Looking at the code of the HACS Climate Template…

  1. It should be relatively easy to replicate the preset_mode functionality from existing similar code

  2. I wonder if a dedicated Fujitsu HACS integration plugin can be made by altering the original HACS Climate Template integration - configuration.yaml would just need to have the IP/MAC/NAME +/- optional features to enable/disable settings… I may look at the practicalities of doing this…

3 Likes

I’ve had a nose around the AirStage API today and it’s using Google Firebase for it’s comms, and Android Keystore (presumably for user creds).

I can see the api keys/ids that it uses, but the APK is heavily obfuscated for “sub-URLs” to (for example) iterate devices etc, so I can’t see those or where it’s hiding tokens. Dumping the app log shows function names which are not visible in the code browser due to the obfuscation :\

Looks like Firebase is ultimately MQTT-esque on that side, as I can see references to “TopicBindingName” etc.

Hi,

I have made a home assistant integration for Fujitsu Airstage Airconditioners, if any one want to try it out.

Please let me know if any issues here:

8 Likes

Daniel! You’re the hero we’ve been waiting for! :smiling_face_with_three_hearts:

2 Likes

Appears to work flawlessly on my system. Case closed everyone, shut down the thread, send Daniel some beers.

That’s awesome! Good to hear!

@edmooredop Did you go for local connection or via cloud?

Local. That approach with the various REST calls we got working over the rest of this thread was working fine for me so saw no reason to involve the cloud now.

Allright :+1:
Let me know if you stumble upon any issues!

1 Like