Hisense airconditioning in Home Assistant - De k8s manier
Gepubliceerd op 18 mei 2026 • 5 min leestijd • 975 woorden
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: longhornC 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-optionsService
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: TCPCronjob
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.ioDe 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 defaultZo wordt ook dit stukje van onze home automation een beetje stabieler.

