Hisense airconditioning in Home Assistant - De k8s manier

Gepubliceerd op 18 mei 2026 • 5 min leestijd • 975 woorden
Hoe bedien je je Hisense airco’s in Home Assistant, terwijl je de software van deiger op Kubernetes draait
Hisense airconditioning in Home Assistant - De k8s manier

Ik gebruik Home Assistant als home automation systeem. Ik kijk bij iedere nieuwe aanschaf of er een mogelijkheid is om dat apparaat of die dienst aan te sturen via Home Assistant. Zo ook bij onze Fujitsu airconditioning.

Ik vind het belangrijk dat ik apparaten kan aansturen zonder internet. Dat lukt niet altijd. Bij de Fujitsu airco’s heb je een clouddienst die normaliter zorgt dat je via een app je airconditioning kunt aansturen. Dat betekent ook dat, wanneer de clouddienst eruit ligt of we geen internet hebben, ik op zoek moet naar de afstandbediening. Dat wil ik dus niet.

Daar komt de container van deiger, aircon ter tonele. Hiermee kun je de airconditioners lokaal bedienen, terwijl er wel een of ander key exchange is met de clouddienst. Ik ben nog niet heel erg in deze voodoo gedoken, maar het werkt wel in ieder geval.

Aircon is een interface tussen mqtt en de airconditioners. Home Assistant krijgt de informatie van de airconditioners via mqtt en kan op die manier ook de airconditioners aansturen.

Kubernetes  

Ik had in het verleden een aantal docker hosts. Het gebeurde wel eens dat één van de hosts uit moest voor onderhoud, of crashte, bijvoorbeeld door geheugengebrek op mijn virtualisatiehost. De diensten die bovenop die docker host draaiden waren dan tijdelijk niet beschikbaar. Op zich niet erg zou je zeggen, maar dat betekende vaak wel dat ik aan de slag moest. Host weer aanzetten, troubleshooten wat er nu weer mis gegaan was, etc. En dat voor dingen die automatisch zouden moeten gaan in een smart home, daar irriteerde ik me steeds meer aan.

Dus de aircon container van deiger moest verplaatsen naar een Kubernetes omgeving. Laten we het erop houden dat de situatie nu iets stabieler is, tupiditeiten van de lokale beheerder (ik dus) voorbehouden. Later zal ik wel een betere beschrijving geven van mijn Kubernetes setup.

Persistent storage  

Containers zijn, als het goed is, stateless. Als je data wilt bewaren, moet je zelf regelen hoe je dat wilt doen. Voor de airco oplossing heb ik gebruik gemaakt van een persistent volume van 1Gi. Of het echt nodig is om storage te hebben, in plaats van een tijdelijke locatie voor data, ben ik nog niet helemaal uit.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: hisense-ac-config-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: longhorn

C onfiguratie/Secrets  

Het grootste deel van de configuratie bevindt zich in een JSON file, options.json. Aangezien hier wat ‘geheime’ dingen in staan, heb ik de hele config in een Secret gezet. Je kunt je afvragen hoe zinvol dat is in een omgeving die beheerd wordt door één persoon, maar goed. Ik wil een beetje de ilusie van veiligheid.

apiVersion: v1
kind: Secret
metadata:
  name: hisense-ac-options
type: Opaque
stringData:
  options.json: |
    {
      "app": [
        {
          "username": "<username van de FGLAir app>",
          "password": "<password van de FGLAir app>",
          "code": "fglair-eu"
        }
      ],
      "log_level": "INFO",
      "mqtt_host": "<ipadres mqtt host>",
      "mqtt_port": 1883,
      "mqtt_user": "<mqtt username>",
      "mqtt_pass": "<mqtt password>",
      "port": 8888,
      "local_ip": "<ip van de Kubernetes loadbalancer>"
    }

Deployment  

Voor de deployment van de container gebruik ik onderstaande. Daarin zie je ook dat ik de options.json die in een secret sta, mount op de locatie waar de container het zoekt. Dit is vergelijkbaar met het volumes statetement in Docker.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hisense-ac
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hisense-ac
  template:
    metadata:
      labels:
        app: hisense-ac
    spec:
      hostNetwork: true
      containers:
        - name: hisense-ac
          image: deiger/aircon:0.3.17
          env:
            - name: CONFIG_DIR
              value: /config
            - name: OPTIONS_FILE
              value: /config/options.json
          volumeMounts:
            - name: hisense-config-pvc
              mountPath: /config
            - name: hisense-options
              mountPath: /config/options.json
              subPath: options.json
              readOnly: true
      volumes:
        - name: hisense-config-pvc
          persistentVolumeClaim:
            claimName: hisense-ac-config-pvc
        - name: hisense-options
          secret:
            secretName: hisense-ac-options

Service  

Omdat de airconditioners met een IP-adres moeten praten, heb ik de service een IP-adres gegeven via MetalLB. Ik gebruik MetalLB als loadbalancer in mijn Kubernetes omgeving. Dit is hetzelfde IP-adres dat ik heb aangegeven in options.json. Je zou MetalLB het IP-adres kunnen laten uitgeven en vervolgens dit adres over kunnen nemen in options.json, maar ik hou er zelf van om dit zelf in de hand te hebben. Belangrijke opmerking hierbij is dat ik externalTrafficPolicy: local gebruik, omdat de container in hetzelfde subnet moet draaien waar ook de airconditioners in zitten. Wanneer geen local traffic policy wordt gebruikt, krijgt de pod een IP-adres in de Kubernetes reeks, in mijn geval een 10.42.x.x. Dat zorgt ervoor dat de airco’s niet kunnen praten met de container.

apiVersion: v1
kind: Service
metadata:
  name: hisense-ac
spec:
  type: LoadBalancer
  loadBalancerIP: <ip van de Kubernetes loadbalancer>
  externalTrafficPolicy: Local
  selector:
    app: hisense-ac
  ports:
    - name: http
      port: 8888       # Externe poort op dit Service / MetalLB IP
      targetPort: 8888 # Containerpoort, moet overeenkomen met de app
      protocol: TCP

Cronjob  

Omdat ik af en toe heb dat de airconditioners niet meer goed kunnen communiceren met de container, of omdat de container het spoor bijster raakt, heb ik een cronjob gemaakt die de pod automatisch herstart. Ik heb nog niet kunnen ontdekken waarom ze het spoor bijster raken, maar dit is een ’easy fix’.

RBAC

# hisense-ac-rescaler-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: <service account>
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: <service account-role>
rules:
  - apiGroups: ["apps"]
    resources: ["deployments", "deployments/scale"]
    verbs: ["get", "list", "watch", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: <service account-role binding>
subjects:
  - kind: ServiceAccount
    name: <service account>
roleRef:
  kind: Role
  name: <service account-role>
  apiGroup: rbac.authorization.k8s.io

De job zelf

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hisense-ac-rescaler
spec:
  schedule: "0 3 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: <service account>
          restartPolicy: Never
          containers:
            - name: rescale
              image: bitnami/kubectl:latest
              command:
                - /bin/sh
                - -c
                - |
                  echo "Scaling hisense-ac to 0..."
                  kubectl scale deployment hisense-ac --replicas=0 -n default
                  echo "Sleeping 60 seconds..."
                  sleep 60
                  echo "Scaling hisense-ac to 1..."
                  kubectl scale deployment hisense-ac --replicas=1 -n default

Zo wordt ook dit stukje van onze home automation een beetje stabieler.

Zie ook

    Follow me