Gå til innhold
  • Bli medlem
Støtt hjemmeautomasjon.no!

Hjelp med API-kall med JSON i script


JxxxIxxx

Anbefalte innlegg

Jeg vet at det jeg nå skal spørre om ikke er spesifikt for Homeseer-script, men jeg prøver likevel å legge det her, siden det er i et slikt script jeg prøver å få til en spesifikk funksjonalitet.
I forbindelse med at jeg prøver å lage noen enkle små script for å kommunisere med en Mill panelovn vha lokalt API (i mangel av en plugin) trenger jeg hjelp med å forstå hvordan jeg skal sende JSON til ovn-APIet vha visual basic.

Se ellers tråd:

og https://github.com/millheat/Generation_3_REST_API

 

Mine veldig banale programmeringskunnskaper strekker ikke helt til i dette tilfellet. Jeg er generelt i stand til å lage enklere HS script, men dette ser ut til å være et stykke forbi min simple kompetanse.

Jeg har sett på et par andre script, bl.a. twinkly.vb som @Moskus har skrevet,

og prøvd å bruke dette som utgangspunkt, men det blir ganske raskt åpenbart at jeg ikke skjønner heeelt hva jeg driver med, så jeg må krype til korset og be pent om noen har anledning til å hjelpe meg.


Jeg har forstått at jeg kan bruke System.Net.WebClient.

 

Og jeg klarer å få til de enkleste API-kallene, slik som f.eks.det som i curl-versjon er slik:

curl -X GET -H "Content-Type: application/json" http://192.168.xx.xxx/status


I vb blir dette noe sånt (ikke hele scriptet):

    Dim source As String = ""
    Dim urlFunction As String = "status"
    Dim url As String = "http://" & IP & "/" & urlFunction
    Using client As New System.Net.WebClient
        client.Headers.Add("Content-Type", "application/json")
        source = client.DownloadString(url)
    End Using

Dette fungerer, og API-kallet returnerer en string som forventet.

 

Videre har jeg også klart å få til API-kall som invovlerer POST, slik som f.eks. dette for sette innstil temperatur (i curl-versjon):

curl -X POST -H "Content-Type: application/json" -d "{\"type\":\"Normal\", \"value\": 15}" http://192.168.xx.xxx/set-temperature


I vb blir dette noe sånt (ikke hele scriptet):

        Dim urlFunction As String = "set-temperature"
        Dim query As String = ""
        Dim url As String = "http://" & IP & "/" & urlFunction

        Dim data As New System.Collections.Generic.Dictionary(Of String, Object)
        data.Add("type", "Normal")
        data.Add("value", 16)
        query = Newtonsoft.Json.JsonConvert.SerializeObject(data)
                
        Using client As New System.Net.WebClient
            client.Headers.Add("Content-Type", "application/json")
            source = client.UploadString(url,"POST",query)
        End using

Dette fungerer også, og jeg er i stand til å sette innstilt temperatur på ovnen vha dette scriptet.

 

 

Men, det jeg ikke får til er de kallene som involverer GET med data-input, slik som f.eks å hente innstilt temperatur.
I curl-versjon er det slik:

curl -X GET -H "Content-Type: application/json" -d "{\"type\" : \"Normal\"}" http://192.168.xx.xxx/set-temperature


Her stopper det for meg, jeg skjønner ikke hva slags metode jeg skal bruke i vb-versjonen av dette.

Har prøvd ulike ting med UploadString og DownloadString og annet, men får bare feilmedlinger eller krasj, så nå er jeg helt "lost".

 

 

Lenke til kommentar
Del på andre sider

On 27/02/2022 at 12:01, JxxxIxxx said:

Men, det jeg ikke får til er de kallene som involverer GET med data-input, slik som f.eks å hente innstilt temperatur.

I curl-versjon er det slik:

curl -X GET -H "Content-Type: application/json" -d "{\"type\" : \"Normal\"}" http://192.168.xx.xxx/set-temperature

 

 

 

Jeg tillater meg å bumpe denne.

Jeg har prøvd mer og mener jeg har forstått litt, men er ikke i mål.

Det jeg tror jeg har funnet ut er at jeg må bruke DownloadString, og at inputparametrene ( {"type":"Normal"} ) må ligge i Webclient property Querystring.

Da blir koden i scriptet noe sånt (ikke komplett):
 

       Dim source As String = ""
       Dim urlFunction As String = "set-temperature"
       Dim url As String = "http://" & IP & "/" & urlFunction

        Using client As New System.Net.WebClient
            client.Headers.Add("Content-Type", "application/json")
            client.QueryString.Add("type", "Normal")
            source = client.DownloadString(url)
            ...........
            ......


Dette gir imidlertid fortsatt "(404) Bad Request" som svar.

 

Er det noen som kan si om jeg er på rett spor eller ikke?

 

 

Lenke til kommentar
Del på andre sider

Du kan ikke bruke QueryString til å sende inn parameter. API'et forventer en JSON, akkurat som du gjør i Curl-kommandoen ovenfor. Denne må du sende inn med:

source = client.DownloadString(Url, "{\"type\" : \"Normal\"}"

 

Lenke til kommentar
Del på andre sider

18 minutes ago, Siggi said:

Du kan ikke bruke QueryString til å sende inn parameter. API'et forventer en JSON, akkurat som du gjør i Curl-kommandoen ovenfor. Denne må du sende inn med:

source = client.DownloadString(Url, "{\"type\" : \"Normal\"}"

 

Jeg mener at dette var noe av det første jeg prøvde tidligere, men det fungerte ikke. Så vidt jeg husker fordi DownloadString bare tar en input-parameter, ikke to.

 

Lenke til kommentar
Del på andre sider

20 hours ago, JxxxIxxx said:

Jeg mener at dette var noe av det første jeg prøvde tidligere, men det fungerte ikke. Så vidt jeg husker fordi DownloadString bare tar en input-parameter, ikke to.

 

Etter mange søk rundt omkring har jeg kommet til den foreløpige (usikre) konklusjon at det ser ut som .net frameworks standard metoder ikke støtter en GET request med "request body".
Hvis det stemmer så er jeg usikker på hvordan jeg kan løse dette. Famler havveis i blinde her.

 

Lenke til kommentar
Del på andre sider

JxxxIxxx skrev (19 minutter siden):

Har prøvd det også, men det blir POST så vidt jeg har forstått, og interfacet godtar ikke det ser det ut til.

Det stemmer, og jeg hadde ikke satt meg inn i API'et og hvordan det fungerer.

DownloadString(GET) skal være riktig ja, og parameter skal inn med query string.

Men client.QueryString.Add krever en spesiell input av typen System.Collections.Specialized.NameValueCollection og ikke to strenger som du bruker.

Men når du legger til et nytt element i NameValueCollection, så kan den kan ta i mot to strenger:
 

Dim queryString = new NameValueCollection()
queryString.Add("type", "normal");
client.QueryString.Add(queryString);

 

Lenke til kommentar
Del på andre sider

1 hour ago, Siggi said:

Det stemmer, og jeg hadde ikke satt meg inn i API'et og hvordan det fungerer.

DownloadString(GET) skal være riktig ja, og parameter skal inn med query string.

Men client.QueryString.Add krever en spesiell input av typen System.Collections.Specialized.NameValueCollection og ikke to strenger som du bruker.

Men når du legger til et nytt element i NameValueCollection, så kan den kan ta i mot to strenger:
 

Dim queryString = new NameValueCollection()
queryString.Add("type", "normal");
client.QueryString.Add(queryString);

 

 

Den koden jeg viste over var bare en av mange varianter jeg har prøvd.
Jeg prøvde flere varianter med NameValueCollection slik du skisserer, uten at det så ut til å ha noen effekt på resultatet.
Jeg har ikke tilgang til å teste mer før senere i dag, men kan jo prøve dette igjen, det kan jo være at jeg har gjort andre feil i min kode, tror ikke jeg gjorde det nøyaktig slik du har gjort det her. Mener jeg gjorde det omtrent slik:

Dim queryString = new NameValueCollection()
queryString.Add("type", "normal")
client.QueryString = queryString

altså at jeg ikke brukte Add på den siste, og det blir vel ikke helt det samme. Jeg tror jeg fant noen eksempler der det var gjort slik.

 


 

Lenke til kommentar
Del på andre sider

6 hours ago, JxxxIxxx said:

Etter mange søk rundt omkring har jeg kommet til den foreløpige (usikre) konklusjon at det ser ut som .net frameworks standard metoder ikke støtter en GET request med "request body".
Hvis det stemmer så er jeg usikker på hvordan jeg kan løse dette. Famler havveis i blinde her.

 

Etter hva jeg leser så har du helt rett. Get med request body er ikke støttet. Egentlig skjønner jeg ikke hvorfor man gjør det slik og ikke benytter POST som er mer korrekt. Jeg ser at endel "tryller" det til ved bruk av noe som heter Reflection når man koder, men aner desverre ikke hvordan du ka klare dette med script.

 

var methodType = currentMethod.GetType();
methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);

I nederste kodelinje går man inn og setter ContentBodyNotAllowed til false. Dette gjør at request blir sendt med body.

 

https://stackoverflow.com/a/70831175/7111839

 

 

Lenke til kommentar
Del på andre sider

7 minutes ago, Guahtdim said:

Etter hva jeg leser så har du helt rett. Get med request body er ikke støttet. Egentlig skjønner jeg ikke hvorfor man gjør det slik og ikke benytter POST som er mer korrekt. Jeg ser at endel "tryller" det til ved bruk av noe som heter Reflection når man koder, men aner desverre ikke hvordan du ka klare dette med script.

 

Takk for at du bekrefter det jeg mistenkte. Jeg har også fått tilbakemelding av kompetente folk på Homeseer forumet som i allefall delvis bekrefter det samme.

 

En måte å komme rundt dette på er å la scriptet starte en curl-prosess for å utføre spørringen, men det er jo en ganske klomsete måte å gjøre det på.

 

Det jeg også ser er diskutert flere steder er at GET med request body ikke er helt "stuerent" i et REST API, men at det er mange som benytter det.
POST er vel ikke helt "stuerent" det heller i akkurat dette tilfellet, ettersom jeg oppfatter det slik at POST er beregnet på å endre noe på serversiden, ikke å bare hente en parameter. Men det ville jo løst problemet i dette tilfellet hvis de støttet POST i stedet for GET.

 

 


 

Lenke til kommentar
Del på andre sider

Moskus skrev (1 time siden):

 POST er vel først og fremst lagt for å "poste" noe til en server...? Noe som ofte er større eller mer strukturert enn hva man får til med en URI...?

Er vel ingen tvil om det nei, men jeg trodde først man måtte poste json-data for å få tilbake temperaturen.

 

Moskus skrev (1 time siden):

De burde ha støttet POST istedenfor GET

De gjør for så vidt det. Kaller du endepunktet med GET, får du set_temperature, altså temperaturen som faktisk er satt. Kaller du det med POST, så setter du set_temperature

Lenke til kommentar
Del på andre sider

2 hours ago, Siggi said:

Er vel ingen tvil om det nei, men jeg trodde først man måtte poste json-data for å få tilbake temperaturen.

Den query-stringen APIet krever at man sender over i "request body" for å spesifisere hvilken "type" temperatur man ønsker returnert er jo forsåvidt formatert som JSON.

(f.eks.  {"type":"Normal"}  )

 

Ellers så forstår jeg jo hvorfor man har valgt å spesifisere type av temperatur vha en parameter i en request body i dette tilfellet. Hvis man skulle brukt GET uten request body måtte man lage 6 forskjellige varianter av "set-temperature" (det er 6 uilke verdier av "type" definert). Så da måtte det blir GET/set-temperature-normal, GET/set-temperature-comfort, GET/set-temperature-sleep,  osv.

Men det ville jo løse problemet for Homeseer sin del slik det framstår nå.

Kanskje man kan kan høre med Mill om de kan tenke seg å legge til disse 6 variantene uten request body i APIet. Hvis de gjør det så vil de ikke lenger "ekskludere" Homeseer (og andre klilenter som benytter .net framework) fra å bruke APIet.

Det er bare denne (GET/set-temperature) pluss en til (GET/config-parameter) som bruker kombinasjonen av GET og request body så det er ikke så mye å endre.

Lenke til kommentar
Del på andre sider

Du kan kanskje klare det med VBScript, men du må jobbe litt for det. Jeg kan ikke garantere at dette virker, men teoriene bak ser ut til å holde vann.

Benytt RestSharp

https://restsharp.dev/v107/#restsharp-v107

 

og så kaller du på dll-en fra VBScript (eksempel her

https://stackoverflow.com/a/9846377/7111839

eventuelt du må registrere den

https://stackoverflow.com/a/769346/7111839

 

og kanskje du får til å sende en Get med body

 

Men dette medfører mye graving. Mulig det å bruke Curl er like "enkelt"

Endret av Guahtdim
Lenke til kommentar
Del på andre sider

37 minutes ago, Guahtdim said:

Du kan kanskje klare det med VBScript, men du må jobbe litt for det. Jeg kan ikke garantere at dette virker, men teoriene bak ser ut til å holde vann.

Benytt RestSharp

https://restsharp.dev/v107/#restsharp-v107

 

og så kaller du på dll-en fra VBScript (eksempel her

https://stackoverflow.com/a/9846377/7111839

eventuelt du må registrere den

https://stackoverflow.com/a/769346/7111839

 

og kanskje du får til å sende en Get med body

 

Men dette medfører mye graving. Mulig det å bruke Curl er like "enkelt"

 

Takk for det, det så litt komplisert ut 😃

 

Jeg har allerede fått til en kode som virker med å sparke i gang en curl-prosess.

Og akkurat når jeg hadde fått til det oppdaget jeg at APIet har en annen mulighet til å hente setpoint-temperaturen som jeg ikke hadde sett før nå.
GET/control-status returnerer en samling med ulike parametre fra ovnen, deriblant også setpoint, og denne har ikke noen request body.

Så det løser det umiddelbare problemet uten noen kompliserte programmerings-triks.

 

  • Like 1
Lenke til kommentar
Del på andre sider

Bli med i samtalen

Du kan publisere innhold nå og registrere deg senere. Hvis du har en konto, logg inn nå for å poste med kontoen din.

Gjest
Skriv svar til emnet...

×   Du har limt inn tekst med formatering.   Lim inn uten formatering i stedet

  Du kan kun bruke opp til 75 smilefjes.

×   Lenken din har blitt bygget inn på siden automatisk.   Vis som en ordinær lenke i stedet

×   Tidligere tekst har blitt gjenopprettet.   Tøm tekstverktøy

×   Du kan ikke lime inn bilder direkte. Last opp eller legg inn bilder fra URL.

×
×
  • Opprett ny...

Viktig informasjon

Vi har plassert informasjonskapsler/cookies på din enhet for å gjøre denne siden bedre. Du kan justere dine innstillinger for informasjonskapsler, ellers vil vi anta at dette er ok for deg.