1. Einführung

Das folgende Bild zeigt ein breadboard mit den relevanten Komponenten, die für die Integration mit Home Assistant verwendet werden.

ESP32-Komponentenübersicht
  1. ESP32-CAM | mit externer Antenne

  2. ESP32-dev

  3. dht11 | Temperatur und Luftfeuchtigkeit

  4. Photosensor | Helligkeit

  5. RGB Licht

  6. PIR Motion Sensor | Infrarot-Sensor

2. Implementierung mit Quarkus

2.1. Projektabhängigkeiten (pom.xml)

<dependencies>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-rest-jackson</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-rest-client</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-rest-client-jackson</artifactId>
    </dependency>
</dependencies>

2.2. Token-Konfiguration (dev.json)

Mithilfe eines Json-Webtokens (JWT) wird eine Verbindung zu HAOS (Homeassistant OS) hergestellt. Dieses erstellt man, indem man auf das Profil, dann auf Security und dann hier klickt:

HAOS Token
{
  "dev": {
    "token": "ey..."
  }
}
env

2.3. REST-Client Interface für Home Assistant

@RegisterRestClient(baseUri = "http://homeassistant.local:8123/api")
@ApplicationScoped
public interface HA_RestClient {
    ...
}

Wichtig:

Für eine reibungslose Benützung der API wird im lokalen Netzwerk mittels mDNS http://homeassistant.local:8123 vergeben, um auf HAOS zugreifen zu können.

2.4. Anwendungsbereiche von API-Aufrufen

Um zu überprüfen, ob die API überhaupt funktioniert wird "/" aufgerufen.

// Methode:
@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
String getApiResponse(@HeaderParam("Authorization") String authorization);

// Beispiel:
Log.info(ha_restClient.getApiResponse(getBearerToken()));

Eine Art "getAll" der Entities ist hier verfügbar:

// Methode:
@GET
@Path("/states")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
String getAllEntities(@HeaderParam("Authorization") String authorization);

// Beispiel:
Log.info(ha_restClient.getAllEntities(getBearerToken()));

Will man jedoch einen bestimmten Sensor ansprechen, ist das so möglich:

// Methode:
@GET
@Path("/states/{entity_id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
String getEntityState(@PathParam("entity_id") String entityId, @HeaderParam("Authorization") String authorization);
// Beispiel mit Sensor:
Log.info(ha_restClient.getEntityState("sensor.nik_station_nik_station_temperature", getBearerToken()));

Es ist außerdem möglich, informationen über sogenannte Scripts zu erhalten.

// Beispiel mit Script:
Log.info(ha_restClient.getEntityState("script.find_nik_iphone", getBearerToken()));

Bei benützung einer Kamera ist die Bildverarbeitung und Sicherung essenziell. So verarbeitet man Bilder einer ESP32-Cam:

// Methode:
@GET
@Path("/camera_proxy/{entity_id}")
@Produces(MediaType.WILDCARD)
@Consumes(MediaType.WILDCARD)
@Transactional
byte[] getCameraImage(@PathParam("entity_id") String entityId, @HeaderParam("Authorization") String authorization);

Leider ist die Kamera-Station nur ein Prototyp und noch nicht im fertigen Gehäuse. Daher leidet die Bildqualität.

nik station
// Beispiel:
Files.write(Paths.get("überwachungskamera-aufnahme.jpg"), ha_restClient.getCameraImage("camera.nik_cam_camera", getBearerToken()));
überwachungskamera aufnahme

3. Find my Phone - eine HomeAssistant User-Story

Als User will ich Home-assistant dazu nutzen, den Standort meines Mobilgeräts ausfindig zu machen. Das erfolgt über eine Audioausgabe, die auch ausgelöst wird, wenn das Gerät im Nicht-Stören- oder Leise- Modus ist.

Solch ein Script legt man in den Einstellungen unter Automationen an:

find phone script
find phone script edit

durch die Einstellung

    critical: 1
    volume: 1

wird jede Blockierung des Mobilgeräts umgangen.

In Quarkus verwendet man dann eine eigene Klasse anstatt eines Json-Objekts zur Aktivierung.

public class ScriptTriggerRequest {
    public String entity_id;

    public ScriptTriggerRequest(String entity_id) {
        this.entity_id = entity_id;
    }
}
// Methode:
@POST
@Path("/services/script/turn_on")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
String triggerScript(@HeaderParam("Authorization") String authorization, ScriptTriggerRequest request);
// Beispiel:
Log.info(ha_restClient.triggerScript(getBearerToken(), new ScriptTriggerRequest("script.find_nik_iphone")));
HAOS alert