Airtouch 4 integration (AUS)

I played around a bit more today, and got to this point. Iā€™m pretty happy with it right now, it can be improvedā€¦ But I have all the functionally (except fan speed which I think isnā€™t implemented in the integration yet) in a much smaller footprint.

Because its so much smaller nowā€¦ i think instead of a slider, Iā€™d prefer just a box with up and down arrows to change the temperatureā€¦ i canā€™t seem to find the name of that though, so I canā€™t find the custom card!

Main Controls

type: 'custom:button-card'
custom_fields:
  titlelabel: 'Airtouch 4:'
  titlemode: '[[[ return `${states["climate.ac0"].state}` ]]] '
  ac0auto:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].state != "auto") return 'grey';
          else return 'darkgreen';
        ]]]      
      icon: 'mdi:brightness-auto'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: climate.ac0
          hvac_mode: auto
  ac0heat:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].state != "heat") return 'grey';
          else return 'darkgreen';
        ]]]          
      icon: 'mdi:white-balance-sunny'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: climate.ac0
          hvac_mode: heat
  ac0cool:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].state != "cool") return 'grey';
          else return 'darkgreen';
        ]]]         
      icon: 'mdi:air-conditioner'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: climate.ac0
          hvac_mode: cool
  ac0dry:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].state != "dry") return 'grey';
          else return 'darkgreen';
        ]]]              
      icon: 'mdi:hair-dryer'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: climate.ac0
          hvac_mode: dry
  ac0fan:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].state != "fan_only") return 'grey';
          else return 'darkgreen';
        ]]]       
      icon: 'mdi:fan'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_hvac_mode
        service_data:
          entity_id: climate.ac0
          hvac_mode: fan_only
  ac0power:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: darkgreen
      icon: 'mdi:power'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: red
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.ac0"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.ac0
  ac0fanauto:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].attributes.fan_mode != "auto") return 'grey';
          else return 'darkgreen';
        ]]]       
      icon: 'mdi:fan'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_fan_mode
        service_data:
          entity_id: climate.ac0
          fan_mode: auto
  ac0fanlow:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].attributes.fan_mode != "low") return 'grey';
          else return 'darkgreen';
        ]]]       
      icon: 'mdi:fan-speed-1'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_fan_mode
        service_data:
          entity_id: climate.ac0
          fan_mode: low
  ac0fanmedium:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].attributes.fan_mode != "medium") return 'grey';
          else return 'darkgreen';
        ]]]       
      icon: 'mdi:fan-speed-2'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_fan_mode
        service_data:
          entity_id: climate.ac0
          fan_mode: medium
  ac0fanhigh:
    card:
      entity: climate.ac0
      show_state: false
      show_name: false
      show_icon: true
      color: |
        [[[
          if (states["climate.ac0"].attributes.fan_mode != "high") return 'grey';
          else return 'darkgreen';
        ]]]       
      icon: 'mdi:fan-speed-3'
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: climate.set_fan_mode
        service_data:
          entity_id: climate.ac0
          fan_mode: high
styles:
  card:
    - padding: 2%
    - font-size: 15px
  custom_fields:
    titlelabel:
      - align-self: middle
      - justify-self: start
    titlemode:
      - align-self: middle
      - justify-self: start
    ac0auto: null
    ac0heat: null
    ac0cool: null
    ac0dry: null
    ac0fan: null
    ac0power: null
    ac0fanauto: null
    ac0fanlow: null
    ac0fanmedium: null
    ac0fanhigh: null
  grid:
    - grid-template-areas: >-
        "titlelabel titlelabel titlelabel titlemode titlemode titlemode" "l l l
        l l l" "ac0auto ac0heat ac0cool ac0dry ac0fan ac0power" "ac0fanauto
        ac0fanlow ac0fanmedium ac0fanhigh i i"
    - grid-template-rows: 1fr 1fr 1fr 1fr
    - grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr
  img_cell:
    - justify-content: start
    - align-items: start
    - margin: none
  name:
    - font-weight: bold
    - font-size: 20px
    - align-self: middle
    - justify-self: start
    - padding-bottom: 5px
show_icon: false

Zones

type: 'custom:button-card'
custom_fields:
  column1: Zone
  column2: Current
  column3: Set
  column4: On/Off
  masterlabel: Master
  bed2label: Bed 2
  bed3label: Bed 3
  bed4label: Bed 4
  familylabel: Family
  garagelabel: Garage
  medialabel: Media
  mastertemp: >-
    [[[ return `${states["climate.master"].attributes.current_temperature} Ā°C`
    ]]]
  bed2temp: >-
    [[[ return `${states["climate.bed_2"].attributes.current_temperature} Ā°C`
    ]]]
  bed3temp: >-
    [[[ return `${states["climate.bed_3"].attributes.current_temperature} Ā°C`
    ]]]
  bed4temp: >-
    [[[ return `${states["climate.bed_4"].attributes.current_temperature} Ā°C`
    ]]]
  familytemp: >-
    [[[ return `${states["climate.family"].attributes.current_temperature} Ā°C`
    ]]]
  garagetemp: >-
    [[[ return `${states["climate.garage"].attributes.current_temperature} Ā°C`
    ]]]
  mediatemp: >-
    [[[ return `${states["climate.media"].attributes.current_temperature} Ā°C`
    ]]]
  masterslider:
    card:
      entity: climate.master
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  bed2slider:
    card:
      entity: climate.bed_2
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  bed3slider:
    card:
      entity: climate.bed_3
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  bed4slider:
    card:
      entity: climate.bed_4
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  familyslider:
    card:
      entity: climate.family
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  garageslider:
    card:
      entity: climate.garage
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  mediaslider:
    card:
      entity: climate.media
      full_row: true
      hide_state: false
      min: 16
      max: 30
      show_icon: false
      type: 'custom:slider-entity-row'
  masterbutton:
    card:
      entity: climate.master
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      right: 10px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.master"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.master
  bed2button:
    card:
      entity: climate.bed_2
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.bed_2"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.bed_2
  bed3button:
    card:
      entity: climate.bed_3
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.bed_3"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.bed_3
  bed4button:
    card:
      entity: climate.bed_4
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.bed_4"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.bed_4
  familybutton:
    card:
      entity: climate.family
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.family"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.family
  garagebutton:
    card:
      entity: climate.garage
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.garage"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.garage
  mediabutton:
    card:
      entity: climate.media
      show_state: false
      show_name: false
      show_icon: true
      icon: 'mdi:power'
      color: darkgreen
      size: 25px
      type: 'custom:button-card'
      state:
        - value: 'off'
          color: grey
      tap_action:
        action: call-service
        service: >-
          [[[ if (states["climate.media"].state != "off") return
          "climate.turn_off"; else return "climate.turn_on" ]]]
        service_data:
          entity_id: climate.media
styles:
  card:
    - padding: 2%
    - font-size: 15px
  custom_fields:
    column1:
      - justify-self: start
      - padding-left: 30%
    column2:
      - justify-self: start
      - padding-left: 30%
    column3: null
    column4: null
    masterlabel:
      - justify-self: start
      - padding-left: 30%
    bed2label:
      - justify-self: start
      - padding-left: 30%
    bed3label:
      - justify-self: left
      - padding-left: 30%
    bed4label:
      - justify-self: left
      - padding-left: 30%
    familylabel:
      - justify-self: left
      - padding-left: 30%
    garagelabel:
      - justify-self: left
      - padding-left: 30%
    medialabel:
      - justify-self: left
      - padding-left: 30%
    mastertemp:
      - justify-self: left
      - padding-left: 30%
    bed2temp:
      - justify-self: start
      - padding-left: 30%
    bed3temp:
      - justify-self: start
      - padding-left: 30%
    bed4temp:
      - justify-self: start
      - padding-left: 30%
    familytemp:
      - justify-self: start
      - padding-left: 30%
    garagetemp:
      - justify-self: start
      - padding-left: 30%
    mediatemp:
      - justify-self: start
      - padding-left: 30%
    masterslider: null
    bed2slider: null
    bed3slider: null
    bed4slider: null
    familyslider: null
    garageslider: null
    mediaslider: null
    masterbutton: 
      - padding-left: 25%
      - padding-right: 25%    
    bed2button: 
      - padding-left: 25%
      - padding-right: 25%    
    bed3button: 
      - padding-left: 25%
      - padding-right: 25%    
    bed4button: 
      - padding-left: 25%
      - padding-right: 25%    
    familybutton: 
      - padding-left: 25%
      - padding-right: 25% 
    garagebutton:
      - padding-left: 25%
      - padding-right: 25%
    mediabutton:
      - padding-left: 25%
      - padding-right: 25%
  grid:
    - grid-template-areas: >-
        "column1 column2 column3 column4" "masterlabel mastertemp masterslider
        masterbutton" "bed2label bed2temp bed2slider bed2button" "bed3label
        bed3temp bed3slider bed3button" "bed4label bed4temp bed4slider
        bed4button" "familylabel familytemp familyslider familybutton"
        "garagelabel garagetemp garageslider garagebutton" "medialabel mediatemp
        mediaslider mediabutton" 
    - grid-template-rows: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr
    - grid-template-columns: 1fr 1fr 1fr 1fr
  img_cell:
    - justify-content: start
    - align-items: start
    - margin: none
show_icon: false

edit: Worked out how to write labelsā€¦ Iā€™m an idiot! Cleaned it up a little
edit2: added fan modes + change some formatting

1 Like

looks great! Fan speed is definitely implemented in the integration! (just no zone percentages)fanspeed

You were correct, it was workingā€¦ I just made some mistakes the first time and thought it wasnā€™tā€¦ I have updated my post to add in the fan modes.

Hi all, newby here.

I have read through this a couple time and attempted it over a couple days but keep coming up with different issues. When looking through the components folder of the repo, there seems to be tons of other addons I would not require?

To confirm:
Am I supposed to copy every file from https://github.com/LonePurpleWolf/core/tree/airtouch4-integration-2 and put it into config folder within my HASS setup? Or just certain sections?

Thank you in advance for any assistance :slight_smile:

Hi Tom,

The way that I got it to work on my actual installation (I think, its been a while now), after you check out the airtouch4-integration branch from my repository, is just taking all the files I changed in my PR, listed here https://github.com/home-assistant/core/pull/43513/files (looks like theres about 14), and splatting them over the top of the ones in my actual home assistant installation - once youā€™ve done that you should be able to add it through the Integrations pageā€¦ but if youā€™ve got a running home assistant installation and arenā€™t too sure about fixing it if it explodes, it might be best to steer clear for now! hopefully, eventually, one day they will finally accept the PR and you will just be able to add it via the Integrations screen.

Hi Sam,

After some messing around, and a few snapshot restores, I ended up getting it working.
Funnily enough, all I needed to do was copy the airtouch4 folder into the custom_components folder and it showed up as an integration. All functional now and thank you for the help :slight_smile:

(files from here: https://github.com/LonePurpleWolf/core/tree/airtouch4-integration-2/homeassistant/components/airtouch4)

Thanks @tpez for the above instructions! seems to be working!

Hi @tpez im looking into this and have tried it in my dev HA copy.

I have created a custom_componants folder and copied the airtouch4 folder in.
after a reboot i go into the home assistant integrations page and i can see the integration.
i then click to install and it just spins on installing integration.

Did you do anything differently?

Cheers

Hi @4Sakyen,
From what you have said, we have done the same things. Unfortunately, I am not too sure what would cause it to freeze on the install either. I suppose it is possible that some of my other settings or config files in my instance could be affecting the results but that is just a stab in the dark.
Sorry I canā€™t offer anymore.

Bummer! Oh well thanks for your reply, letā€™s hope the pr gets approved soon. Iā€™m really keen to get this working.

My installation seems to have stalled - it is showing temp readings from 2 weeks ago - not current.

I was going to install the latest files you refer to above. I notice your files are now under ā€œPullā€, not ā€œComponentsā€ in GitHub. Do we read anything into that? (I guess I was looking at different branches - still learning to speak GitHub)

Hey Steve,

Not sure what the ā€˜componentsā€™ vs ā€˜pullā€™ situation is - the files havenā€™t moved anywhere! If you just check out the same branch (airtouch4-integration) making sure that youā€™ve pulled the latest files, all the files should be in the same places as there were. As far as I have heard, the newest version has been good (hasnā€™t broken for me yet)

I wasnā€™t looking at your fork - clearly Iā€™m running a bit slow here.

Sam.

I am getting this in the logs:
2021-03-30 19:24:31 WARNING (MainThread) [homeassistant.loader] No ā€˜versionā€™ key in the manifest file for custom integration ā€˜airtouch4ā€™. This will not be allowed in a future version of Home Assistant. Please report this to the maintainer of ā€˜airtouch4ā€™

Apologies if it has come up elsewhere.

@LonePurpleWolf Iā€™m wondering if youā€™ll have more luck submitting your integration for use via HACS (Home Assistant Community Store) instead of official HA Integration.

Yeah possibly - I donā€™t use HACS so not sure whatā€™s involved - as far as I know most people (at least on this thread) have it working as it is - and it certainly seems like the intended way to distribute integrations like this is through the home assistant core integrations (core is full to the brim of a bunch of other climate control integrations). I am hoping that in the scenario that they ever approve the pull request, subsequent PRs will be much faster (as my understanding is stuff can be approved by the people involved in making that integration, not whoever it is currently waiting for)

Hi Sam

The latest update for HomeAssistant now excludes this because of the lack of version number I mentioned above.

2021-06-03 11:45:18 ERROR (SyncWorker_1) [homeassistant.loader] The custom integration ā€˜airtouch4ā€™ does not have a valid version key (None) in the manifest file and was blocked from loading. See Custom integration changes | Home Assistant Developer Docs for more details

Any suggestions for a fix???

Update

I just added a line:

ā€œversionā€: ā€œ1.0.0ā€,

to the manifest.json and it is now happy.

Not sure what your real version is.

Hey Steve, glad you solved your issue. As the goal is not to ship it as a custom component, my understanding is it doesnā€™t need a version in the manifest file, itā€™s only required because some people are using the custom_components folder to allow it to run

I have put it in the custom_components folder. Should it just be in the configuration.yaml

  • or does it go somewhere else?