Viime viikon jutussa teime Power Appsilla kopion Sensibon mobiilisovelluksesta. Tällä kerralla menemme askeleen pidemmälle ja viritämme Power Apps -versiomme komentamaan kotimme ilmalämpöpumppua.

Tämä on mahdollista, sillä Sensibo tarjoaa rajapinnan ilmalämpöpumpun ohjaamiseksi.

Aloitetaan!

Avaimen (API key) luominen

Ensimmäiseksi tarvitsemme avaimen, jotta Sensibon API:a voi käyttää. Se luodaan https://home.sensibo.com/ -sivustolla. Kirjaudutaan sisään Sensibo-tunnuksella ja navigoidaan avaimen luontiin (Create an API key).

Annetaan avaimelle nimi ja luodaan se.

Avain ilmestyy sivulle, josta otamme sen talteen myöhempää käyttöä varten.

API:n käyttö

Tutkitaan hetki API:n dokumentaatiota ja huomaamme pärjäävämme kahdella kutsulla.

Ensimmäinen palauttaa parametrina saadun laitteen tiedot. Tulosjoukko sisältää laitteen nykyiset asetuksen, huoneen lämpötilan ja kosteuden, sekä laitteen mahdolliset arvojoukot eri asetuksille.

GET /pods/{device_id}

Toisella taas vaihdetaan laitteen asetuksia. Puhallinnopeus, lämpötilapyynti jne.

POST /pods/{device_id}/acStates

Tarvitsemme käyttöömme olohuoneessa möllöttävän ilmalämpöpumpun tunnisteen (device_id). Tämä löytyy kutsulla

GET /users/me/pods

Kokeillaan tätä postmanilla ja poimitaan tulosjoukosta kaivattu tunniste (id).

Siirrytään Power Platformin puolelle. Aloitetaan tekemällä flow’t, joita Power Apps voi kutsua.

Flow – Laitteen tilatietojen haku

Ensimmäinen flow käynnnistyy Power Appsista ja se hakee Sensibon API:sta laitteen tilatiedot.

Käyttämämme http-kutsu on seuraava (paluusanomassa on niin paljon turhaa, että karsitaan sitä fields-parametrilla).

GET https://home.sensibo.com/api/v2/pods/{your_device_id}?fields=measurements,acState,room&apiKey={your_API_key}

Paluuarvona saamme seuraavan kokonaisuuden.

{
  "status": "success",
  "result": {
    "room": {
      "uid": "VceFfudL",
      "name": "Olohuone",
      "icon": "Den",
      "pureBoostConfig": null
    },
    "acState": {
      "timestamp": {
        "time": "2023-01-17T18:14:17.749083Z",
        "secondsAgo": 0
      },
      "on": true,
      "mode": "heat",
      "targetTemperature": 22,
      "temperatureUnit": "C",
      "fanLevel": "high",
      "swing": "fixedMiddleTop",
      "horizontalSwing": "fixedCenterRight",
      "light": "off"
    },
    "measurements": {
      "time": {
        "time": "2023-01-17T18:13:17.931747Z",
        "secondsAgo": 59
      },
      "temperature": 22.5,
      "humidity": 43.3,
      "feelsLike": 22.5,
      "rssi": -60
    }
  }
}

Palautetaan ratkaisun tarvitsemat arvot Power Appsille kukin omassa kentässään. Emme käytä Parse JSON -toimintoa, vaan viittaamme arvoihin suoraan. Tähän tapaan:

body('HTTP')['result']['measurements']['humidity']

Flow – Laitteen asetusten muuttaminen

Toisella flow’lla muutetaan laitteen asetuksia. Se saa parametrina kaksi arvoa.

  • Setting – Asetus, jota ollaan ollaan muokkaamassa (mode, fan, targetTemperature..)
  • Value – Asetuksen uusi arvo

Laitteeen asetuksia voi muuttaa seuraavalla http-kutsulla.

POST https://home.sensibo.com/api/v2/pods/{your_device_id}/acStates?apiKey={your_API_key}

Viestin body-osiossa määritellään uudet arvot. Huomaa, että sanoma voi sisältää ainoastaan muuttuneet arvot.

{
  "acState": {
    "on": false,
    "mode": "string",
    "fanLevel": "string",
    "targetTemperature": 0,
    "temperatureUnit": "string",
    "swing": "string"
  }
}

Arvojen tietotyypit vaihtelevat:

  • lämpötila (targetTemperature) on kokonaisluku
  • virta (on) on boolean (virta päällä tai pois)
  • kaikki loput ovat merkkijonoja

Tänään laiskottaa, joten tehdään tämä helpolla tavalla. Flow saa parametrina yhden muutettavan asetuksen. Tehdään kullekin tietotyypille oma haaransa, niin saamme helposti muotoiltua http-kutsun bodyn oikein.

Flow’t ovat valmiit. Siirrytään viimeistelemään itse sovellus.

Power Apps

Sovelluksemme näyttää tältä. Laitetaan siihen hieman eloa.

Ensimmäisenä lisäämme tekemämme flow’t sovellukseen. Tämän jälkeen lisätään painike, jonka OnSelect -tapahtumassa

  • Käynnistetään laitteen tilatiedot hakeva flow (PA-GetACstatus)
  • Tallennetaan flow’n paluuarvo muuttujaan (gblACStatus)
  • Tallennetaan nykyinen pyyntilämpötila (targetTemperature) paikalliseen muuttujaan (locCurrentTemperatureSetting).

Eli näin:

Set(gblACStatus, 'PA-GetACstatus'.Run());
UpdateContext({locCurrentTemperatureSetting: Value(gblACStatus.targettemperature)});

Ylläpidämme kokoelmassa (colDeviceSettings) laitteen asetuksien vaihtoehtoja, sekä tietoa mikä kustakin vaihtoehdoista on parhaillaan voimassa (lue viime viikon juttu). Päivitetään nykyiset asetukset yksi kerrallaan kokoelmaan seuraavilla komennoilla.

UpdateIf(colDeviceSettings,Area = "Mode" And Lower(Setting) = Lower(gblACStatus.mode), {isCurrentValue:true});
UpdateIf(colDeviceSettings,Area = "Fan" And Lower(Setting) = Lower(gblACStatus.fanlevel), {isCurrentValue:true});
UpdateIf(colDeviceSettings,Area = "Light" And Lower(Setting) = Lower(gblACStatus.light), {isCurrentValue:true});
UpdateIf(colDeviceSettings,Area = "Swing" And Lower(Setting) = Lower(gblACStatus.swing), {isCurrentValue:true});
UpdateIf(colDeviceSettings,Area = "Horizontal swing" And Lower(Setting) = Lower(gblACStatus.horizontalswing), {isCurrentValue:true});

Lopuksi piilotetaan painike, ja painetaan sitä päänäyttöä avattaessa (OnVisible).

Select(btnSetCurrentSettings)

Näin haemme laitteen nykyarvot aina sovelluksen käynnistyessä.

Arvojen esittäminen

Nyt tiedämme laitteen asetukset, huoneen lämpötilan sekä ilmankosteuden. Vaihdetaan sovelluksen näytöllä olevat elementit käyttämään näitä todellisia arvoja.

Laitteen nimi

Huoneen lämpötila

Jne.

Mutta miten saamme sovelluksen keskellä olevan vihreän säätimen (SVG-kuva) näyttämään oikeaa lämpötilaa? Viivan täyttöaste (stroke-dasharray) ilmaistaan numerona nollan ja sadan väliltä. Lämpötilavalinnan voi tehdä välillä 16-30, joten laskemme montako prosenttia pyydetty lämpötila on tästä asteikosta.

(locCurrentTemperatureSetting-14)/14*100

Tehdään sama viivan päässä olevan pienen ympyrän sijainnille (keypoints).

Muut asetukset näkyvät samantien oikein, koska kokoelma (colDeviceSettings) päivitettiin heti alussa laitteen nykyisillä asetuksilla.

Lämpötilan säätäminen

Lämpötilan nostaminen ja laskeminen on suoraviivaista. Muutetaan pyyntilämpötila-muuttujan arvoa ja lähetetään muutos flow’lla API:n kautta ilmalämpöpumpulle.

UpdateContext({locCurrentTemperatureSetting:locCurrentTemperatureSetting+1});
'PA-SetACStatus'.Run("targetTemperature", locCurrentTemperatureSetting);

Asetusten vaihtaminen

Laitteen asetusten vaihtaminen on askeleen työläämpää. Lähetetään uusi asetus laitteelle, jonka jälkeen poistetaan kokoelmasta nykyinen asetus (UpdateIf) ja korvataan se uudella (Patch).

'PA-SetACStatus'.Run(ThisItem.Area, ThisItem.Setting);

UpdateIf(colDeviceSettings,Area = ThisItem.Area, {isCurrentValue:false});
Patch(colDeviceSettings,ThisItem, {isCurrentValue:true});

Kokoelman päivittäminen on oleellista, muutoin sovellus näyttää muutoksen jälkeen väärää asetusta.

Tilatietojen jatkuva päivittäminen

Sovelluksen ollessa aktiivinen, haemme laitteen tilatiedot 15 sekunnin välein. Näin huoneen lämpötila ja ilmankosteus -tiedot ovat aina ajan tasalla.

Lisätään näytölle ajastin (timer) jonka oletusasetuksista vaihdamme sueraavat

  • Repeat = true
  • Auto start = true
  • Duration = 15000
  • OnTimerEnd = Select(btnSetCurrentSettings)
  • Visible = false

Käytännössä ajastin klikkaa laitteen nykytilan hakevaa painiketta 15 sekunnin välein. Painike on tietenkin piilossa.

Bonus – Lämpötilan muutoksen visualisointi

Haluaisimme tämän pienen pallon (ja sen vihreän hännän) siirtyvän animoidusti aina kun käyttäjä kasvattaa tai vähentää lämpötilapyyntiä.

Miten sen teemme?

Tietenkin ajastimella!

Lisätään näytölle ajastin (tmrAnimateTemperatureChanges) ja muutetaan siitä seuraavat arvot

  • Duration = 1000
  • Start = locAnimateTemperature
  • OnTimerEnd = UpdateContext({locAnimateTemperature:false})

Käytännössä animaatio alkaa kun muuttujan locAnimateTemperature arvo muuttuu trueksi. Animaatio kestää sekunnin ja sen lopuksi muuttujan locAnimateTemperature arvoksi palautetaan false.

Muutetaan plus ja miinus -painikkeiden toimintaa hieman. Asetetaan niissä animaatioon liittyvät muuttujat kohdilleen.

UpdateContext({locAnimateTemperature:true, locAnimateIncrease: true});

Muuttuja locAnimateIncrease kertoo vähennetäänkö vai lisätäänkö lämpötilaa.

Lopuksi muutetaan SVG-kuvan stroke-dasharray ja keyPoints -ominaisuudet näyttämään joko voimassaolevaa arvoa tai ajastimen avulla muutoksen animointia. Jompaan kumpaan suuntaan.

If(locAnimateTemperature,
  If(locAnimateIncrease = true,
     (locCurrentTemperatureSetting-14-1+
        (tmrAnimateTemperatureChange.Value/1000))/14*100,
     (locCurrentTemperatureSetting-14 +1-
        (tmrAnimateTemperatureChange.Value/1000))/14*100),
  (locCurrentTemperatureSetting-14)/14*100)

Yhteenveto

Onko sovellus nyt valmis ja se toimii 1:1 kuten esikuvansa?

Ei.

Asetuksia muutettaessa käyttäjälle pitäisi antaa palautetta että jotain tehdään. Näin käyttäjä tietäisi komentojen menneen perille.

Lisäksi nopeasti tekemämme SVG-animaatio ei ole käytännössä kovin siisti. Kuva välkkyy välillä. Sen voisi yrittää toteuttaa toisin.

Ja kaikkea muuta pientä.

Mutta sovellus toimii, eli sillä voi komentaa kodin ilmalämpöpumppua. Ja se näyttää hyvin pitkälle esikuvaltaan, mikä oli alunperin koko harjoituksen tarkoitus.