Token über http.request beziehen

Hallo zusammen,

Ich stehe vor einem Problem, bei dem ich hoffe hier Hilfe zu bekommen.

Derzeit habe ich eine Wallbox von Easee installiert, die beim Laden den Strom komplett aus dem Netz bezieht. Da ich aber in Kürze eine PV-Anlage installieren will (liegt schon in der Garage), soll die Wallbox zukünftig nur PV-Überschuss laden.

Jetzt scheitere ich bereits am ersten Schritt. Wenn ich mich in der Easse-Cloud anmelden will, um einen Authentifizierungstoken zu bekommen, erhalte ich immer eine Fehlermeldung 415.

Was mache ich falsch? Irgendwie verstehe ich das mit dem http.request noch nicht so wirklich.
Folgendes habe ich mir aus verschiedensten Foren zusammengebastelt:

local user = "+49123456789" --Username mit Länderkennziffer
local pwd = "GEHEIM"

function getToken()
local url = "https://api.easee.cloud/api/accounts/token"
local headers = {
        ['Accept'] = 'application/json',
        ['Content-Type'] = 'application/*+json',
        ["Authorization"] = ""
		}

local selfhttp = net.HTTPClient({timeout=2000})

selfhttp:request(url, {
  options=  {
            method = 'POST',
            header = headers,
            data = {
	                ['userName'] = user,
	                ['password'] = pwd
	                }
            },
 success = function(response) 
            data = json.encode(response),
            print('Rückgabe erste Abfrage: '..response.status)
            print('Rückgabe erste Abfrage komplett: '..data)
    end,
    error = function(message)
            print("error:", message)
    end
})
end --function

getToken()

Gruß
KaWi

Hi KaWi,

mein Enkel hat sich die letzten 2 Stunden damit um die Ohren geschlagen:
Hiermit gibt’s einen Status 200 und entsprechend das Bearer-Token zurück:

function getToken()
local url = "https://api.easee.cloud/api/accounts/token"

local user = "USERNAME" --Username mit Länderkennziffer
local pwd = "PASSWORD"

local requestBody = {
        ["username"] = user, 
        ["password"] = pwd
}

local extraheaders = {
    ['Accept'] = 'application/json',
    ['Content-Type'] = 'application/*+json'
}        

local selfhttp = net.HTTPClient({timeout=2000})

selfhttp:request(url, {
  options=  {
            headers = extraheaders,
            data = json.encode(requestBody),
            method = "POST"
            },
 success = function(response) 
            data = json.encode(response),
            print('Rückgabe erste Abfrage: '..response.status)
            print('Rückgabe erste Abfrage komplett: '..data)
    end,
    error = function(message)
            print("error:", message)
    end
})
end --function

getToken()

EDIT: Habe die gleiche Wallbox aber noch kein E-Auto. Wird noch lange dauern. Werde dann auch versuchen mit Überschussladen.

Gruß
jeep

Hi jeep
Erstmal vielen Dank an Dich und an den Enkel. Läuft super.
Jetzt versuche ich das mal Zeile für Zeile zu verstehen was da passiert und wage mich an den nächsten Schritt zu Testzwecken die LED-Helligkeit zu ändern. Dafür muss ich dann ja den generierten Token entsprechend weitergeben.

Ein E-Auto haben wir auch noch nicht. Aber immerhin schon einmal eine PV-Anlage (zumindest in der Garage :wink:). Es gibt ja den SolarManager, der bei der Easee dann Überschussladen ermöglichen soll. Aber die knapp 1000€ dachte ich mir kann ich ja mal versuchen zu sparen.

Hallo KaWi,

das Thema PV-Laden ist in der Theorie ja relativ einfach. Wenn man dann aber zu dem Punkt kommt wo es dann um die Umsetzung der eigenen Wünsche geht, merkt man häufig doch, dass die Umsetzung nicht ganz so trivial ist. Da will man erst einmal einen mindest Ladestand vom Haus erreichen, immer eine gewisse Ladung des Fahrzeugs sicherstellen, kurze Ladeunterbrechungen bei Wolken verhindern, manches Fahrzeug zickt rum wenn die Ladung seitens Wallbox mal unterbrochen wurde, beim Umschalten zwischen 1-phasigem und 3-phasigem Laden gibt es bei manchen Fahrzeugen auch ein paar Dinge zu beachten,… .
Ich bin da kürzlich auf ein Projekt gestoßen, das bezüglich Funktionsumfang wirklich interessant ist und schone eine ganze Menge Wallboxen und Fahrzeuge direkt unterstützt (auch die Easee). Ich denke gerade das Einbinden des Fahrzeugs ist in Fibaro extrem aufwendig. Kannst es Dir ja mal anschauen:
https://evcc.io/

Das ganze kann man auf einem Raspberry PI oder einem ohnehin laufenden Server betreiben.
Ich selbst bin leider noch nicht dazu gekommen das Ganze mal zu testen. Ich habe bis dato eine Lösung über ioBroker. Und in der aktuellen Jahreszeit ist PV Laden ja auch nicht so wirklich ein Thema :wink:. Wenn das Thema wieder aktueller wird, werde ich das Projekt auch mal testen.

Viele Grüße,
MasterG

Moin MasterG,
Das Projekt von evcc.io hatte ich schon gesehen. Liest sich im ersten Moment spannend. Allerdings bedarf gerade meine WallBox ein Sponsoring. Und da man dieses (wie ich zumindest gesehen habe) nur mit einer monatlichen Zahlung freischalten kann, habe ich zunächst davon Abstand genommen.

Dennoch danke für den Tip.
Gruß
KaWi

Hallo jeep,
bevor ich mich jetzt dumm und dusselig suche, dachte ich frage ich Dich mal direkt. :grin:

Ich habe jetzt dank Dir einen vernünftigen response erhalten und kann den auch auswerten. Aber wie schaffe ich es, das ich den response (in diesem Fall den Token) „aus der Funktion herausbekomme“??

Irgendwie muss es ja gehen, das ich das Token für eine weitere Funktion nutzen kann. Hast Du da einen Tipp für mich??

Gruß
KaWi

Hi,
ja da muss man die Antwort wieder decoden. Unser Augenmerk lag nur auf dem POST (Unser Fehler)
Versuch mal die Function success mit dieser zu ersetzen , sollte klappen

 success = function(response) 
            data = response.data
            easee = json.decode(data)
            print(easee.accessToken)
            

Wenn Du was brauchbares hast kannst Du mich gerne auf dem Laufenden halten.

Viel Erfolg

Hi,
ich habe den Code mal in einer QA gepackt falls man damit was anfangen will. Funktioniert auch ganz gut. Ich stelle mal den LUA-code der QA hier rein. Man muss dann noch die 3 Variablen mit usr, pwd und url einrichten.

local version = 1
local INTERVAL = 60000 * 60 --1 std
local QA = nil

local function getToken()
   local requestBody = {
        ["username"] = user, 
        ["password"] = pwd
         }
   local extraheaders = {
        ['Accept'] = 'application/json',
        ['Content-Type'] = 'application/*+json'
         }       
  local selfhttp = net.HTTPClient({timeout=2000})
  selfhttp:request(url, {
  options=  {
            headers = extraheaders,
            data = json.encode(requestBody),
            method = "POST"
            },
 success = function(response) 
             data = response.data
             easee = json.decode(data)
             QA:trace("AccesToken:",easee.accessToken )
             QA:trace("RefreshToken:",easee.refreshToken)
             --print(easee.accessToken)
                        
           end,
    error = function(message)
            print("error:", message)
    end
})
end --function

function QuickApp:onInit()
  self:debug(self.name,", version:",version,", deviceId:",self.id)
  QA = self
  url  = self:getVariable("url")
  pwd  = self:getVariable("pwd")
  user = self:getVariable("user") 

  --setInterval(getToken,INTERVAL)
  getToken()
end

Noch `ne Frage, welchen Wechselrichter/Speicher bekommst Du? Ich habe einen Senec.Home V3 hybrid mit 5kwh Speicher. Überlege gerade auf 7,5 kWh aufzurüsten. Die Solaranlage hat auch 7,5 kWp.

Hi jeep,
Ich habe mir einen SMA Sunny Tripower 8.0 - STP8.0-3AV-40 gegönnt. Den werde ich mit insgesamt 24 Modulen Bauer BS-400-M10HBB betreiben. Insgesamt komme ich dann auf ca. 9,6 kWp.
Einen Speicher will ich (vorerst) nicht verbauen, da ich den nicht wirtschaftlich rechnen konnte. Bei den angenommenen Kosten im Verhältnis zur Lebensdauer (Ladezyklen) habe ich kein für mich vernünftiges Ergebnis bekommen. Wir hatten zwar im letzten Jahr hier in Niedersachsen eine Förderung von 40% auf den Speicher; die habe ich aber leider verpasst. Also, wohin mit dem ganzen Strom? :thinking:
Nun, zuerst werde ich mir noch eine E-Patrone für den Pufferspeicher im Keller gönnen. Da habe ich dann schon einmal eine Möglichkeit bis zu 9.000 Watt „zu parken“. Das werde ich wohl über den MyPV Thor 9s steuern. Soll mit Fibaro funktionieren.
Und wenn ich dann wider erwarten immer noch Strom über habe, weil z.B. der Puffer bereits kocht, dann werde ich mir in naher Zukunft mal ein E-Auto gönnen :smiley:

Ich hatte auch schon mal überlegt, die Abfrage des Token für die Easee mit einer QA zu lösen. Aber mit QA kenn ich mich null aus und kann mir das irgendwie auch nicht herleiten, wie ich das bei den Scenen bisher gemacht habe.
Da ist es für mich dann eben ein Nachteil, das ich nie richtig programmieren gelernt habe und mir alles über „learning by doing“ aneigne. :sweat:

Hallo zusammen,
nachdem ich in der Zwischenzeit meine PV-Anlage installiert habe, will ich mich mal wieder ein wenig dem Thema PV-Überschuss widmen.
Aber leider komme ich immer noch nicht dahinter, wie ich einen response weiter „verarbeiten“ kann.

Ich habe mir die von @jeep erstellte QA genommen und einige Funktion dazugeschrieben. Hier mal mein kompletter Entwurf (ich weiß dass das bestimmt von der Programmierung her besser geht; aber das ist erstmal mein Weg das überhaupt zu verstehen :upside_down_face:)

local version = 1.5
--local INTERVAL = 60000 * 60 --1 std.
local INTERVAL = 1000 * 20 --alle 20 Sek. Status aktualisieren
local QA = nil

local function getToken()
   local url = "https://api.easee.cloud/api/accounts/token"
   local requestBody = {
        ["username"] = user, 
        ["password"] = pwd
         }
   local extraheaders = {
        ['Accept'] = 'application/json',
        ['Content-Type'] = 'application/*+json'
         }       
  local selfhttp = net.HTTPClient({timeout=2000})
  selfhttp:request(url, {
  options=  {
            headers = extraheaders,
            data = json.encode(requestBody),
            method = "POST"
            },
 success = function(response) 
             data = response.data
             easee = json.decode(data)
             QA:trace("AccesToken:",easee.accessToken )
             QA:trace("RefreshToken:",easee.refreshToken)
             --QA:trace("Ablauf des Token in ",(easee.expiresIn/3600), " Stunden"))
             QA:updateView("label_1", "text", "Token läuft ab in : "..(easee.expiresIn/3600).. " Stunden")
             QA:setVariable("Token", easee.accessToken)
             QA:setVariable("refreshToken", easee.refreshToken)
                        
           end,
    error = function(message)
            print("error:", message)
    end
    
})
end --function


local function getState()
	local chargerOpMode = {
        [0] = "Offline",
        [1] = "Disconnected",
        [2] = "AwaitingStart",
        [3] = "Charging",
        [4] = "Completed",
        [5] = "Error",
        [6] = "ReadyToCharge",
    }

   local url = "https://api.easee.cloud/api/chargers/" .. ChargerID .. "/state"
   local extraheaders = {
        ['Authorization'] = "Bearer " .. Token,
        ['Content-Type'] = 'application/*+json'
         }  
   
   local selfhttp = net.HTTPClient({timeout=2000})
        selfhttp:request(url, {
        options=  {
            headers = extraheaders,
            method = "GET"
            },
        success = function(response) 
			 QA:debug("******* response status of Get State Data :", response.status .. " ********") 
             data = json.decode(response.data)
             --easee = json.decode(data)
			 
			 QA:debug("Response ChargerOpMode: ",data.chargerOpMode )
             if data.chargerOpMode == 0 then 
                 QA:updateView("label_status", "text", json.encode(chargerOpMode[0]))
             elseif data.chargerOpMode == 1 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[1]))
             elseif data.chargerOpMode == 2 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[2]))
             elseif data.chargerOpMode == 3 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[3]))
             elseif data.chargerOpMode == 4 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[4]))
             elseif data.chargerOpMode == 5 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[5]))
             elseif data.chargerOpMode == 6 then 
                 QA:updateView("label_status", "text",  json.encode(chargerOpMode[6]))
             end
			 --QA:debug("Response Energiekosten: ",data.energyPerHour )
			 QA:debug("Response dynamicChargerCurrent: ",data.dynamicChargerCurrent )
                        
           end,
    error = function(message)
            print("error:", message)
    end
   
})
end --function

function QuickApp:uibuttongetState() 
getState()
end

function QuickApp:uibuttongetToken() 
getToken()
end

function QuickApp:onInit()
  self:debug(self.name,", version:",version,", deviceId:",self.id, ", gestartet am: ", os.date("🕑 %a, %d.%m.%Y, %H:%M"))
  QA = self
  pwd  = QA:getVariable("pwd")
  user = QA:getVariable("user") 
  Token = tostring(QA:getVariable("Token"))
  refreshToken = tostring(QA:getVariable("refreshToken"))
  ChargerID = QA:getVariable("ChargerID")

  --setInterval(getToken,INTERVAL)
  setInterval(getState,INTERVAL)
  setInterval(getConfiguration,INTERVAL)
  --setInterval(getToken,60000 * 60 * 24) --alle 24 Stunden den Token erneuern
end

Mein Problem ist, das ich mir bei der Funktion getState mit einer Krücke behelfe, indem ich den Response der Funktion getToken in eine Variable schreibe. Diese wiederum rufe ich dann in der Funktion getState ab (Bereich extraheader/username).

Geht das auch anders?? Wenn ja, was muss ich wo einbauen??
Bin über jede Hilfe dankbar

Gruß
KaWi

Hi @KaWi ,

versuch mal stat:

 QA:setVariable("Token", easee.accessToken)
 QA:setVariable("refreshToken", easee.refreshToken)

[/quote]

einfach:

Token = easee.accessToken
usw.

Eventuell noch ein local Token ganz oben.

Mit der API habe ich mich noch nicht auseinander gesetzt. Wenn Du weiter kommst gib mir Bescheid.

Gruß, Jeep

Moin @jeep
genau das was Du vorgeschlagen hast habe ich gemacht und Tadaaa; es funktioniert :smiley:

Ich habe ganz oben im Code „Token = nil“ eingefügt und dann in der Funktion getState „Token = easee.accessToken“.
Danach kann ich dann den Response (also in diesem Fall den Token) in meiner weiteren Funktion getState nutzen. Hammer :grinning:

Genau was ich gesucht habe.

Vielen vielen Dank.
Wenn ich mein E-Auto habe werde ich versuchen über die API die jeweiligen Schaltzustände der WallBox auszulesen. Das ganze dann mit dem Überschuss der PV-Anlage kombiniert.
Leider dauert es aber wohl noch etwas bis ich das Auto habe. Aber mal gucken. Evtl. leihe ich mir eins aus der Nachbarschaft zum testen :thinking:

Ich halte Dich auf dem laufenden

Gruß
KaWi