Liitännäiset

Mukautetut liitännäiset mahdollistavat Athenan laajentamisen omalla koodillasi. "Kortti"-liitännäinen tuo mukautetun ohjauspaneelikortin; "integraatio"-liitännäinen ajaa palvelinpuolista JavaScriptiä ja raportoi omat entiteettinsä; "aliprosessi"-liitännäinen tekee saman, mutta ajaa sen sijaan oman ohjelmatiedostosi. Kaikki kolme ajavat mielivaltaista koodia, joten lisää vain sellaisia, joihin luotat - Asetukset > Liitännäiset on vain ylläpitäjille, kuten kaikki muutkin asetussivut.

Liitännäiset-lista

Jokaisella tyypillä on oma välilehtensä, ja sama kortti-/luettelovalitsin ja hakukenttä kuin muillakin listanäkymäsivuilla (katso esim. Automaatiot) - korttinäkymä on oletuksena. Integraatio- ja aliprosessiliitännäisillä on lisäksi Käytössä/Pois käytöstä -suodatin sekä Ota käyttöön/Poista käytöstä -toiminto Muokkaa/Poista-toimintojen vieressä (korttinäkymän kolmen pisteen valikossa, tai omana painikkeenaan luettelonäkymässä) liitännäisen tauottamiseksi poistamatta sitä - korttiliitännäisillä ei ole vastaavaa käsitettä, koska ne joko ovat olemassa tai eivät. Otsikon oma "+ Lisää liitännäinen" -valikkokohta avaa yhden lomakkeen Kortti/Integraatio/Aliprosessi-valitsimella, joka on oletuksena parhaillaan avoinna olevan välilehden mukainen.

Korttiliitännäiset

Korttiliitännäinen on pieni ES-moduuli, joka tarjoillaan selaimelle ja liitetään customElements.define(...)-web-komponenttina - sama mekanismi kuin Home Assistantin omissa "custom cards" -liitännäisissä. Kun se on lisätty tänne, se näkyy tavallisena korttityyppinä Ohjauspaneelia muokattaessa.

// Minimaalinen korttiliitännäinen - näyttää staattisen tervehdyksen
class HelloCard extends HTMLElement {
  connectedCallback() {
    this.innerHTML = '<div style="padding:1rem">Hello from a card plugin!</div>';
  }
}
customElements.define('hello-card', HelloCard);

Integraatioliitännäiset

Integraatioliitännäinen on JavaScript-ohjelma, joka ajetaan jatkuvasti palvelimella (sulautettuna Athenaan itseensä, ei erillisenä prosessina) ja raportoi omat entiteettinsä samaan entiteettirekisteriin kuin jokainen sisäänrakennettu integraatio - se näkyy Laitteet ja palvelut -sivun omilla Devices/Entities- välilehdillä, Historiassa, Ohjauspaneelissa ja lähteenä Automaatioissa, aivan kuten natiivi integraatio.

Skripti näkee yhden globaalin muuttujan, athena:

  • athena.config - tämän liitännäisen oma konfiguraatio, syötettynä JSON-muodossa liitännäistä lisättäessä ja valmiiksi jäsennettynä skriptille.
  • athena.reportEntity({ key, name, domain, state, unit, deviceClass, stateClass }) - päivittää yhden entiteetin nykyisen arvon; kaikki paitsi key ja state ovat valinnaisia.
  • athena.log(message) - kirjoittaa Athenan omaan lokiin, merkittynä liitännäisen nimellä.
  • athena.fetch(url, options) - oikea HTTP-asiakas, palauttaa Promise<{ status, body }>-arvon; options on { method, headers, body }, kaikki valinnaisia (oletuksena tavallinen GET).
  • athena.mqtt.subscribe(aihe, callback) - tilaa minkä tahansa MQTT-aiheen Athenan oman jo määritetyn välittäjäyhteyden kautta (saman, jota jokainen löydetty MQTT-entiteetti jo käyttää - ei erillisiä yhteystietoja syötettäväksi tässä); callback(payload) kutsutaan jokaisen viestin raakadatalla merkkijonona, joten JSONia odottava skripti kutsuu JSON.parse(payload)-funktiota itse. Tämä on luonnollinen tapa yhdistää esimerkiksi Home Assistantin mqtt.publish-automaatio Athenan omaan entiteettirekisteriin.

Täysi setTimeout/setInterval/async/await-tuki tulee ilmaiseksi, oikean JavaScript-tapahtumasilmukan tukemana - tyypillinen skripti asettaa yhden setInterval-ajastimen, joka hakee jotain ja kutsuu athena.reportEntity- funktiota, tai athena.mqtt.subscribe-takaisinkutsun, joka tekee saman aina viestin saapuessa.

Automaatioiden Tilan laukaisin, jonka lähteenä on integraatioliitännäisen oma entiteetti, laukeaa heti kun athena.reportEntity kutsutaan sille - ei vasta silloin kun jokin muu sattuu lukemaan entiteettilistan uudelleen.

// Minimaalinen integraatioliitännäinen - raportoi satunnaisen lämpötilan 30 sekunnin välein
setInterval(() => {
  const value = 18 + Math.random() * 4;
  athena.reportEntity({
    key: 'demo_temperature',
    name: 'Demo Temperature',
    domain: 'sensor',
    state: value.toFixed(1),
    unit: '°C',
    deviceClass: 'temperature',
    stateClass: 'measurement'
  });
}, 30000);

Integraatioliitännäiset ovat tässä ensimmäisessä versiossa vain luku -tyyppisiä - raportoitua entiteettiä ei vielä voi ohjata Ohjauspaneelista tai Automaatiosta. Se on luonnollinen seuraava askel tämän osoittauduttua toimivaksi, ei osa ensimmäistä julkaisua.

Aliprosessiliitännäiset

Aliprosessiliitännäinen ajaa oman ohjelmatiedostosi oikeana käyttöjärjestelmäprosessina JavaScript-moduulin sijaan - integraatioille, joihin sulautettu JS-moottori ei aidosti yllä: raaka sarjaporttien käyttö, natiivi salaus, jonkin toisen kielen oman SDK:n kutsuminen ja vastaavat. Se raportoi entiteettejä täsmälleen samaan rekisteriin kuin integraatioliitännäinen, joten se näkyy kaikkialla, missä integraatioliitännäisen entiteetitkin näkyvät.

Uusi aliprosessiliitännäinen täytyy tallentaa kerran (nimi + JSON-asetukset), ennen kuin sillä on mihin liittää ohjelmatiedosto - Muokkaa-lomake saa sen jälkeen Ohjelmatiedosto-osion tiedostonvalitsimella ja Lataa-painikkeella. Uudelleenlataus korvaa edellisen ohjelmatiedoston kokonaan; kutakin liitännäistä kohti on tarkalleen yksi "nykyinen" ohjelmatiedosto.

Siirtoprotokolla on tarkoituksella yksinkertainen - mikä tahansa kieli, joka osaa tulostaa rivin stdout-virtaan, voi toteuttaa sen, eikä mitään SDK:ta tai koodin generointia tarvita:

  • Käynnistyessään Athena kirjoittaa yhden rivin prosessin omaan stdin-virtaan: {"config": {...}}, joka sisältää liitännäisen omat jäsennetyt asetukset.
  • Siitä eteenpäin Athena lukee prosessin omaa stdout-virtaa rivi kerrallaan. Jokainen rivi on JSON-objekti, jolla on "type"-kenttä:
    • "entity" - päivittää yhden entiteetin nykyisen arvon; kaikki paitsi key ja state ovat valinnaisia:
      {"type":"entity","key":"...","name":"...","domain":"...","state":"...","unit":"...","deviceClass":"...","stateClass":"..."}
    • {"type":"log","message":"..."} - kirjoitetaan Athenan omaan lokiin.
  • Prosessin oma stderr-virta kaapataan ja kirjataan sellaisenaan lokiin - paikka liitännäisen omille paniikeille/pinojäljille/debug-tulosteille.
#!/usr/bin/env python3
# Minimaalinen aliprosessiliitännäinen - raportoi käyntiajan 30 sekunnin välein
import json, sys, time

config = json.loads(sys.stdin.readline())  # {"config": {...}}
while True:
    print(json.dumps({
        "type": "entity",
        "key": "demo_uptime",
        "name": "Demo Uptime",
        "domain": "sensor",
        "state": int(time.time()),
        "unit": "s"
    }), flush=True)
    time.sleep(30)

Aliprosessiliitännäiset ovat tässä ensimmäisessä versiossa vain luku -tyyppisiä, kuten integraatioliitännäiset jo ovat - raportoitua entiteettiä ei vielä voi ohjata Ohjauspaneelista tai Automaatiosta, eikä kaatunutta prosessia käynnistetä automaattisesti uudelleen (liitännäisen poistaminen ja palauttaminen käytöstä, tai Athenan uudelleenkäynnistys, käynnistää sen uudelleen). Tilan laukaisin, jonka lähteenä on aliprosessiliitännäisen oma entiteetti, laukeaa samalla tavalla kuin integraatioliitännäisen - heti kun sitä koskeva "entity"-tyyppinen stdout-rivi saapuu.

Ladatut ohjelmatiedostot tallennetaan PLUGIN_BIN_DIR-hakemistoon (./plugin-bins oletuksena), bind-mountattuna samalla tavalla kuin lokihakemisto - katso Asennus ja käyttöönotto.